Menu

Change language

GitHub repo

Contact Us

blockmarketing

Two-column contact section. Left: eyebrow, headline, lede, icon contact rows (email / phone / office) and a live Mapbox map pinned to your office (pass accessToken + location; falls back to a placeholder without a token). Right: a Card-wrapped form (name / email / company / subject Select / message Textarea) that swaps to a success state. Calls onsubmit with the payload.

Installation

$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/contact-us.json
Manifest:https://uipkge.dev/r/svelte/contact-us.jsonInstalls to:src/lib/components/blocks/contact-us/

Variants

Loading interactive previews…

Theming

CSS custom properties referenced in this item. Override any of them in your :root or per-element to retheme.

--background

Files installed (1)

  • src/lib/components/blocks/contact-us/ContactUs.svelte6.8 kB
    <script lang="ts">
      /**
       * Contact section — two columns. Left: eyebrow, headline, lede, icon-prefixed
       * contact rows, and a live map pinned to your office (pass `accessToken` +
       * `location`; falls back to a styled placeholder without a token). Right: a
       * Card-wrapped form (name / email / company / subject / message) that swaps to
       * a success state after submit. Calls `onsubmit` with the payload.
       */
      import { CircleCheckBig, Mail, MapPin, Phone, Send } from '@lucide/svelte'
      import { Button } from '$lib/components/ui/button'
      import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card'
      import { Input } from '$lib/components/ui/input'
      import { Label } from '$lib/components/ui/label'
      import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '$lib/components/ui/select'
      import { Textarea } from '$lib/components/ui/textarea'
      import { Map, MapMarker } from '$lib/components/ui/map'
    
      export interface ContactSubmitPayload {
        name: string
        email: string
        company: string
        subject: string
        message: string
      }
    
      interface ContactUsProps {
        /** Mapbox token. Without it the map area shows a styled placeholder. */
        accessToken?: string
        /** Office [lng, lat]. */
        location?: [number, number]
        locationLabel?: string
        onsubmit?: (payload: ContactSubmitPayload) => void
      }
    
      let {
        accessToken = '',
        location = [-122.4194, 37.7749],
        locationLabel = 'San Francisco, CA',
        onsubmit,
      }: ContactUsProps = $props()
    
      let name = $state('')
      let email = $state('')
      let company = $state('')
      let subject = $state('sales')
      let message = $state('')
      let sent = $state(false)
    
      const canSubmit = $derived(name !== '' && email !== '' && message !== '')
    
      function submit() {
        if (!canSubmit) return
        onsubmit?.({ name, email, company, subject, message })
        sent = true
      }
    </script>
    
    <section data-slot="contact-us" class="bg-background">
      <div class="mx-auto max-w-6xl px-6 py-20">
        <div class="grid gap-10 lg:grid-cols-2 lg:items-start">
          <!-- Left: copy + contact rows + map -->
          <div class="space-y-6">
            <p class="text-primary text-sm font-medium tracking-widest uppercase">Contact</p>
            <h2 class="text-3xl font-semibold tracking-tight sm:text-4xl">Talk to our team</h2>
            <p class="text-muted-foreground max-w-md">
              Questions about pricing, onboarding, or a custom plan? Send a note and we'll get back within one business
              day.
            </p>
    
            <ul class="space-y-3">
              <li class="flex items-center gap-3">
                <span class="bg-muted text-foreground flex size-9 items-center justify-center rounded-lg"
                  ><Mail class="size-4" /></span
                >
                <span class="text-sm">hello@example.com</span>
              </li>
              <li class="flex items-center gap-3">
                <span class="bg-muted text-foreground flex size-9 items-center justify-center rounded-lg"
                  ><Phone class="size-4" /></span
                >
                <span class="text-sm">+1 (555) 010-2030</span>
              </li>
              <li class="flex items-center gap-3">
                <span class="bg-muted text-foreground flex size-9 items-center justify-center rounded-lg"
                  ><MapPin class="size-4" /></span
                >
                <span class="text-sm">{locationLabel}</span>
              </li>
            </ul>
    
            <div class="h-56 overflow-hidden rounded-xl border">
              {#if accessToken}
                <Map {accessToken} center={location} zoom={11} muted class="size-full">
                  <MapMarker lngLat={location} anchor="bottom">
                    <svg viewBox="0 0 24 24" width="26" height="34" class="text-primary drop-shadow">
                      <path
                        d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"
                        fill="currentColor"
                        stroke="currentColor"
                        stroke-width="1.5"
                      />
                      <circle cx="12" cy="9" r="2.6" fill="var(--background)" />
                    </svg>
                  </MapMarker>
                </Map>
              {:else}
                <div class="bg-muted text-muted-foreground flex size-full items-center justify-center gap-2 text-sm">
                  <MapPin class="size-4" /> {locationLabel}
                </div>
              {/if}
            </div>
          </div>
    
          <!-- Right: form -->
          <Card>
            {#if !sent}
              <CardHeader>
                <CardTitle>Send a message</CardTitle>
                <CardDescription>We'll route it to the right person.</CardDescription>
              </CardHeader>
              <CardContent class="space-y-4">
                <div class="grid gap-4 sm:grid-cols-2">
                  <div class="space-y-1.5">
                    <Label for="cu-name">Name</Label>
                    <Input id="cu-name" bind:value={name} placeholder="Jane Cooper" />
                  </div>
                  <div class="space-y-1.5">
                    <Label for="cu-email">Email</Label>
                    <Input id="cu-email" bind:value={email} type="email" placeholder="[email protected]" />
                  </div>
                </div>
                <div class="space-y-1.5">
                  <Label for="cu-company">Company</Label>
                  <Input id="cu-company" bind:value={company} placeholder="Acme Inc." />
                </div>
                <div class="space-y-1.5">
                  <Label>Subject</Label>
                  <Select bind:value={subject}>
                    <SelectTrigger><SelectValue placeholder="Choose a topic" /></SelectTrigger>
                    <SelectContent>
                      <SelectItem value="sales">Sales</SelectItem>
                      <SelectItem value="support">Support</SelectItem>
                      <SelectItem value="partnership">Partnership</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
                <div class="space-y-1.5">
                  <Label for="cu-message">Message</Label>
                  <Textarea id="cu-message" bind:value={message} rows={4} placeholder="How can we help?" />
                </div>
                <Button class="w-full" disabled={!canSubmit} onclick={submit}>
                  <Send class="size-4" /> Send message
                </Button>
              </CardContent>
            {:else}
              <CardContent class="flex flex-col items-center gap-3 py-16 text-center">
                <span class="bg-success/10 text-success flex size-12 items-center justify-center rounded-full"
                  ><CircleCheckBig class="size-6" /></span
                >
                <p class="text-lg font-semibold">Message sent</p>
                <p class="text-muted-foreground max-w-xs text-sm">
                  Thanks, {name} — we'll reply to {email} within one business day.
                </p>
                <Button variant="outline" onclick={() => (sent = false)}>Send another</Button>
              </CardContent>
            {/if}
          </Card>
        </div>
      </div>
    </section>
    

Raw manifest:https://uipkge.dev/r/svelte/contact-us.json