# Contact With Office Locations

> Contact section with a message form beside a static map placeholder and address cards for the San Francisco, Berlin, and Singapore offices.

A shadcn/ui block from the [@7ovr](https://7ovr.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/7ovr/contact-3).

- Page, with a live preview: https://shadcn.exchange/r/7ovr/contact-3
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/7ovr/contact-3-light-bf6e05e043e2f0ff.png
- Registry item: https://7ovr.com/r/contact-3.json
- Categories: contact
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://7ovr.com/r/contact-3.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@base-ui/react`
- Registry items: `badge`, `button`, `card`, `checkbox`, `field`, `input`, `select`, `separator`, `sonner`, `textarea`

## Files

### `registry/blocks/contact/3/contact-block.tsx`

```tsx
"use client"
import { toast } from "sonner"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import { Checkbox } from "@/components/ui/checkbox"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import { Separator } from "@/components/ui/separator"
import { Toaster } from "@/components/ui/sonner"
import { Textarea } from "@/components/ui/textarea"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const TOPICS = ["General inquiry", "Sales", "Support", "Partnership", "Other"]

const OFFICES = [
  {
    city: "San Francisco",
    address: "548 Market St, Suite 200, CA 94104",
    phone: "+1 (415) 555-0188",
  },
  {
    city: "Berlin",
    address: "Torstraße 35, 10119 Berlin, Germany",
    phone: "+49 30 555 0142",
  },
  {
    city: "Singapore",
    address: "12 Marina Blvd, #18-01, 018982",
    phone: "+65 6555 0117",
  },
]

export default function ContactBlock() {
  return (
    <section className="flex w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground">
      <Toaster />
      <div className="mx-auto w-full max-w-5xl">
        <div className="mb-10 max-w-2xl">
          <Badge variant="secondary">
            <IconPlaceholder
              lucide="Send"
              tabler="IconSend"
              hugeicons="MailSendIcon"
              phosphor="PaperPlane"
              remixicon="RiMailSendLine"
              data-icon="inline-start"
            />
            Contact
          </Badge>
          <h2 className="mt-4 font-heading text-2xl font-semibold tracking-tight sm:text-3xl">
            Let&apos;s talk about your project
          </h2>
          <p className="mt-2 text-sm text-muted-foreground">
            Send the Acme team a message or drop by one of our offices. We reply
            within one business day.
          </p>
        </div>

        <div className="grid gap-6 md:grid-cols-2">
          <Card className="w-full">
            <form
              className="flex flex-col gap-(--card-spacing)"
              onSubmit={(event) => {
                event.preventDefault()
                toast.success(
                  "Message sent. We'll reply within one business day."
                )
              }}
            >
              <CardHeader>
                <CardTitle className="text-sm font-semibold">
                  Send a message
                </CardTitle>
                <CardDescription>
                  Tell us a bit about what you need.
                </CardDescription>
              </CardHeader>

              <Separator />

              <CardContent>
                <FieldGroup>
                  <Field>
                    <FieldLabel htmlFor="name">Full name</FieldLabel>
                    <Input id="name" type="text" placeholder="Jane Doe" />
                  </Field>

                  <Field>
                    <FieldLabel htmlFor="email">Work email</FieldLabel>
                    <Input
                      id="email"
                      type="email"
                      placeholder="jane@company.com"
                    />
                  </Field>

                  <Field>
                    <FieldLabel htmlFor="topic">Topic</FieldLabel>
                    <Select name="topic">
                      <SelectTrigger id="topic" className="w-full">
                        <SelectValue placeholder="Select a topic…" />
                      </SelectTrigger>
                      <SelectContent alignItemWithTrigger={false}>
                        {TOPICS.map((topic) => (
                          <SelectItem key={topic} value={topic}>
                            {topic}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </Field>

                  <Field>
                    <FieldLabel htmlFor="message">Message</FieldLabel>
                    <Textarea
                      id="message"
                      rows={6}
                      className="min-h-32 resize-none"
                      placeholder="How can we help?"
                    />
                  </Field>
                </FieldGroup>
              </CardContent>

              <CardFooter className="flex flex-col items-stretch gap-4">
                <div className="flex items-center gap-2.5">
                  <Checkbox id="consent" name="consent" required />
                  <label
                    htmlFor="consent"
                    className="text-xs leading-snug font-normal text-muted-foreground"
                  >
                    I agree to the{" "}
                    <a
                      href="#"
                      className="underline underline-offset-4 hover:text-foreground"
                    >
                      Privacy Policy
                    </a>
                    .
                  </label>
                </div>
                <Button type="submit" className="w-full">
                  <IconPlaceholder
                    lucide="Send"
                    tabler="IconSend"
                    hugeicons="MailSendIcon"
                    phosphor="PaperPlane"
                    remixicon="RiMailSendLine"
                    data-icon="inline-start"
                  />
                  Send Message
                </Button>
              </CardFooter>
            </form>
          </Card>

          <div className="flex flex-col gap-6">
            <div
              className="relative h-52 w-full overflow-hidden rounded-lg border border-border bg-muted/40"
              aria-hidden="true"
            >
              <div className="absolute inset-0 grid grid-cols-6">
                {Array.from({ length: 6 }).map((_, i) => (
                  <div
                    key={i}
                    className="border-r border-border/40 last:border-r-0"
                  />
                ))}
              </div>
              <div className="absolute inset-0 grid grid-rows-3">
                {Array.from({ length: 3 }).map((_, i) => (
                  <div
                    key={i}
                    className="border-b border-border/40 last:border-b-0"
                  />
                ))}
              </div>

              <div className="absolute top-1/2 left-1/2 size-44 -translate-x-1/2 -translate-y-1/2 rounded-full border border-primary/15 bg-primary/[0.03]" />
              <div className="absolute top-1/2 left-1/2 size-24 -translate-x-1/2 -translate-y-1/2 rounded-full border border-primary/20 bg-primary/[0.04]" />

              <span className="absolute top-1/2 left-1/2 flex size-9 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-md ring-4 ring-background/70">
                <IconPlaceholder
                  lucide="MapPin"
                  tabler="IconMapPin2"
                  hugeicons="MapPinIcon"
                  phosphor="MapPin"
                  remixicon="RiMapPin2Line"
                  className="size-5"
                />
              </span>
            </div>

            <div className="grid gap-4 sm:grid-cols-2 md:grid-cols-1">
              {OFFICES.map((office) => (
                <Card key={office.city}>
                  <CardContent className="flex items-start gap-3">
                    <span className="flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-muted">
                      <IconPlaceholder
                        lucide="MapPin"
                        tabler="IconMapPin2"
                        hugeicons="MapPinIcon"
                        phosphor="MapPin"
                        remixicon="RiMapPin2Line"
                        className="size-4 text-muted-foreground"
                        aria-hidden="true"
                      />
                    </span>
                    <div className="min-w-0">
                      <p className="text-sm font-medium">{office.city}</p>
                      <p className="mt-0.5 text-xs text-muted-foreground">
                        {office.address}
                      </p>
                      <p className="mt-1.5 flex items-center gap-1.5 text-xs text-muted-foreground">
                        <IconPlaceholder
                          lucide="Phone"
                          tabler="IconPhone"
                          hugeicons="TelephoneIcon"
                          phosphor="Phone"
                          remixicon="RiPhoneLine"
                          className="size-3.5"
                          aria-hidden="true"
                        />
                        {office.phone}
                      </p>
                    </div>
                  </CardContent>
                </Card>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  )
}
```
