# Contact List Card

> A single card listing four on-call contacts as rows with a greyscale Cloud shape avatar, name, title and an outline Email button. Rows are divided by hairlines under a header and description.

A shadcn/ui block from the [@01orbital](https://01orbital.dev/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/01orbital/contact-list-card).

- Page, with a live preview: https://shadcn.exchange/r/01orbital/contact-list-card
- Screenshot: https://shadcn.exchange/shot/01orbital/contact-list-card/light.png
- Registry item: https://01orbital.dev/r/contact-list-card.json
- Categories: app
- Listed: 2026-11-01, source last changed 2026-11-01

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/01orbital/contact-list-card.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: `@phosphor-icons/react`, `cn`
- Registry items: `@01orbital/button`, `card`, `@01orbital/cloud-shapes`, `@01orbital/item`

## Files

### `blocks/app/contact-list-card/index.tsx`

```tsx
import { EnvelopeSimpleIcon } from "@phosphor-icons/react/dist/ssr"
import { cn } from "cn"

import {
  CloudShape,
  type CloudPalette,
} from "@/components/graphics/cloud-shapes"
import { buttonVariants } from "@/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

// The copy: change text here, not in the markup.
const COPY = {
  title: "Who to call",
  body: "The four people on console this week, in the order the checklist names them.",
  action: "Email",
} as const

const PEOPLE = [
  {
    name: "JoAnn Morgan",
    title: "Instrumentation Controller",
    email: "joann@orbcore.co",
  },
  { name: "Gene Kranz", title: "Flight Director", email: "gene@orbcore.co" },
  {
    name: "Katherine Johnson",
    title: "Trajectory Analyst",
    email: "katherine@orbcore.co",
  },
  {
    name: "Margaret Hamilton",
    title: "Flight Software Lead",
    email: "margaret@orbcore.co",
  },
] as const

// Knob: the orb's shading; zero chroma keeps it greyscale.
const ORB: CloudPalette = {
  main: "oklch(0.55 0 0)",
  accent: "oklch(0.7 0 0)",
}

export default function ContactListCard() {
  return (
    <Card className="mx-auto w-full max-w-md">
      <CardHeader>
        <CardTitle>{COPY.title}</CardTitle>
        <CardDescription>{COPY.body}</CardDescription>
      </CardHeader>
      <CardContent>
        <ul role="list" className="divide-y divide-border">
          {PEOPLE.map((person) => (
            <li key={person.email}>
              <Item size="sm" className="rounded-none px-0 py-3">
                <ItemMedia>
                  <CloudShape palette={ORB} width={40} height={40} />
                </ItemMedia>
                <ItemContent className="gap-0.5">
                  <ItemTitle>{person.name}</ItemTitle>
                  <ItemDescription className="text-xs">
                    {person.title}
                  </ItemDescription>
                </ItemContent>
                <ItemActions>
                  <a
                    href={`mailto:${person.email}`}
                    className={cn(
                      buttonVariants({ variant: "outline", size: "sm" })
                    )}
                  >
                    <EnvelopeSimpleIcon
                      aria-hidden="true"
                      data-icon="inline-start"
                    />
                    {COPY.action}
                  </a>
                </ItemActions>
              </Item>
            </li>
          ))}
        </ul>
      </CardContent>
    </Card>
  )
}
```
