Contact

Contact Departments and Offices

Contact section in two intro-column rows: department cards with mailto and tel links, then office cards with street addresses. Built from Section, Card and DescriptionList with Orbcore sample details.

Free, MIT licenseOpen in Browse
import {
  DescriptionList,
  DescriptionListDetails,
  DescriptionListItem,
  DescriptionListTerm,
} from "@/components/editorial/description-list"
import {
  Feature,
  FeatureGroup,
} from "@/components/editorial/features"
import { Heading } from "@/components/editorial/heading"
import {
  Section,
  SectionColumns,
  SectionContent,
  SectionDescription,
  SectionHeader,
  SectionTitleGroup,
} from "@/components/editorial/section"
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"

// The copy: change text here, not in the markup.
const COPY = {
  title: "Get in touch",
  body: "One address per question, so the right people read it first. Replies come within one working day.",
  emailTerm: "Email",
  phoneTerm: "Phone number",
} as const

const LOCATIONS = {
  title: "Locations",
  body: "Four studios in four time zones. Visits are by appointment; write to the studio first.",
} as const

const DEPARTMENTS = [
  {
    name: "Collaborate",
    email: "collaborate@orbcore.example",
    phone: "+1 (555) 905-2345",
  },
  { name: "Press", email: "press@orbcore.example", phone: "+1 (555) 905-3456" },
  {
    name: "Join our team",
    email: "careers@orbcore.example",
    phone: "+1 (555) 905-4567",
  },
  {
    name: "Say hello",
    email: "hello@orbcore.example",
    phone: "+1 (555) 905-5678",
  },
] as const

const OFFICES = [
  { name: "Portland", address: ["301 Meridian Way", "Portland, OR 97209"] },
  { name: "Austin", address: ["1450 Halo Street", "Austin, TX 78702"] },
  { name: "Halifax", address: ["62 Eclipse Avenue", "Halifax, NS B3J 1A1"] },
  { name: "Edinburgh", address: ["9 Starling Close", "Edinburgh EH1 2AB"] },
] as const

// A tel: link carries only the digits and the leading plus.
const tel = (phone: string) => `tel:${phone.replace(/[^\d+]/g, "")}`

export default function ContactOffices01() {
  return (
    <Section>
      <SectionContent>
        <section>
          <SectionColumns variant="intro">
            <SectionHeader size="sm">
              <SectionTitleGroup>
                <Heading>{COPY.title}</Heading>
              </SectionTitleGroup>
              <SectionDescription>{COPY.body}</SectionDescription>
            </SectionHeader>
            <FeatureGroup cols={2} gap="sm" className="@sm:grid-cols-2">
              {DEPARTMENTS.map((department) => (
                <Feature key={department.name}>
                  <Card>
                    <CardHeader>
                      <CardTitle role="heading" aria-level={3}>
                        {department.name}
                      </CardTitle>
                    </CardHeader>
                    <CardContent>
                      <DescriptionList className="gap-1">
                        <DescriptionListItem className="justify-start">
                          <DescriptionListTerm className="sr-only">
                            {COPY.emailTerm}
                          </DescriptionListTerm>
                          <DescriptionListDetails>
                            <a
                              href={`mailto:${department.email}`}
                              className="font-semibold underline-offset-4 hover:underline"
                            >
                              {department.email}
                            </a>
                          </DescriptionListDetails>
                        </DescriptionListItem>
                        <DescriptionListItem className="justify-start">
                          <DescriptionListTerm className="sr-only">
                            {COPY.phoneTerm}
                          </DescriptionListTerm>
                          <DescriptionListDetails className="text-muted-foreground">
                            <a
                              href={tel(department.phone)}
                              className="underline-offset-4 hover:underline"
                            >
                              {department.phone}
                            </a>
                          </DescriptionListDetails>
                        </DescriptionListItem>
                      </DescriptionList>
                    </CardContent>
                  </Card>
                </Feature>
              ))}
            </FeatureGroup>
          </SectionColumns>
        </section>
        <section>
          <SectionColumns variant="intro">
            <SectionHeader size="sm">
              <SectionTitleGroup>
                <Heading>{LOCATIONS.title}</Heading>
              </SectionTitleGroup>
              <SectionDescription>{LOCATIONS.body}</SectionDescription>
            </SectionHeader>
            <FeatureGroup cols={2} gap="sm" className="@sm:grid-cols-2">
              {OFFICES.map((office) => (
                <Feature key={office.name}>
                  <Card>
                    <CardHeader>
                      <CardTitle role="heading" aria-level={3}>
                        {office.name}
                      </CardTitle>
                    </CardHeader>
                    <CardContent>
                      <address className="grid gap-1 text-sm/6 text-muted-foreground not-italic">
                        {office.address.map((line) => (
                          <p key={line}>{line}</p>
                        ))}
                      </address>
                    </CardContent>
                  </Card>
                </Feature>
              ))}
            </FeatureGroup>
          </SectionColumns>
        </section>
      </SectionContent>
    </Section>
  )
}

Installation

pnpm dlx shadcn add @01orbital/contact-offices-01
npx shadcn add @01orbital/contact-offices-01
yarn shadcn add @01orbital/contact-offices-01
bunx --bun shadcn add @01orbital/contact-offices-01

Free under the MIT license. Add the @01orbital registry to components.json once (install guide), then run the command.

It lands at components/blocks/contact/contact-offices-01/index.tsx, as source you own and edit.

Usage

import ContactOffices01 from "@/components/blocks/contact/contact-offices-01"

export default function Example() {
  return <ContactOffices01 />
}

Dependencies

Registry pieces it installs with it: