# Team directory

> A complete people directory for a company. Filter by office, each shown with its local time, then browse team-grouped cards or a sortable table. It also has an org chart you rearrange by dragging, time off approvals, and a profile panel showing the hours each person shares with you.

- Type: Screen (a complete app view, installed as a block)
- Page: https://uiarc.dev/components/screens/team-directory
- Markdown: https://uiarc.dev/components/screens/team-directory/markdown

- Access: Arc Pro
- Registry id: `team-directory`
- Source file: `registry/blocks/team-directory/team-directory.tsx`
- Built from: Input, Avatar, Button, Motion
- Keywords: react team directory, employee directory, people search, staff directory ui, company directory, team list with profile

Use this when people need to browse a team and find contact details. Replace the sample people and portraits with your own directory data.

## When to use

- An internal directory where people search colleagues and copy contact details.
- Team pages with department filters and a profile pane.

## When not to use

- Use team-members to manage roles and invitations.
- Use team-showcase for a public, image-led team section.
- Use customers-table for large tabular people data.

## Installation

Team directory is part of Arc Pro. The live preview is public; the source and install command need Pro.

### CLI with a Pro token

1. Create a token in your account and set it in the environment (or `.env.local`). Never commit it.

```bash
export ARC_PRO_TOKEN=arc_pro_...
```

2. Add the Pro registry to `components.json`:

```json
{
  "registries": {
    "@uiarc": "https://uiarc.dev/r/{name}.json",
    "@uiarc-pro": {
      "url": "https://uiarc.dev/r/pro/{name}.json",
      "headers": {
        "Authorization": "Bearer ${ARC_PRO_TOKEN}"
      }
    }
  }
}
```

3. Install:

```bash
npx shadcn@latest add @uiarc-pro/team-directory
```

### Manual

Signed-in Pro members can copy the source from the Manual tab on the docs page.

- Plans: https://uiarc.dev/pricing
- Create a Pro token: https://uiarc.dev/account#pro-access
- Setup guide: https://uiarc.dev/docs/ai#pro-access

## Usage

```tsx
import { TeamDirectory } from "@/components/arc/blocks/team-directory/team-directory";

export function PeoplePage({ people }: { people: DirectoryPerson[] }) {
  return (
    <div style={{ height: "100dvh" }}>
      <TeamDirectory
        people={people}
        viewerId="diane-foster"
        onManagerChange={(personId, managerId) => saveManager(personId, managerId)}
        onInvite={({ email, team }) => sendInvite(email, team)}
      />
    </div>
  );
}
```

## API reference

### TeamDirectory

A full people directory screen inside the Arc screen shell. The sidebar holds the main nav, an Offices section of live office clocks (local time, the sun or moon over the office, and how many people there are working now; a row filters the People page to that office) and starred people. The People page has Arc's search field, team and status pickers and either cards grouped by team or a sortable table, with every team and status drawn as its own icon. The Org chart page draws reporting lines and lets you drag someone onto a new manager. The Time off page lists requests to approve or decline, a four week calendar and approved leave. A resizable profile panel opens on demand (a sheet on narrow frames) with status, working hours on a 24 hour strip with the overlap with you, reporting line, contact, direct reports, skills and profiles, plus a quick message, copy email and favorite. The sample studio, Fieldnote, has 16 people in four offices on Thursday 12 November 2026.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `onPersonSelect` | `(person: { id: string; name: string; team: Team }) => void` | – | Called when a person is chosen in the grid, the table, the org chart, the sidebar favorites or a profile. |
| `people` | `DirectoryPerson[]` | `directoryPeople` | Everyone in the directory: role, team, office, UTC offset, working hours, manager, contact, start date, avatar, bio, skills, GitHub and LinkedIn handles and an optional status override (out, in a meeting, joining). |
| `timeOff` | `TimeOffRequest[]` | `directoryTimeOff` | Time off requests. Pending ones wait on the Time off page; approved ones show on the calendar and in profiles. |
| `viewerId` | `string` | `"diane-foster"` | The person viewing: working hour overlap is measured against them and they fill the account row. |
| `workspaceName` | `string` | `"Saltmarsh"` | The workspace in the switcher and the trail. |
| `defaultView` | `"grid" \| "list"` | `"grid"` | Cards grouped by team, or a sortable table. |
| `defaultPage` | `"people" \| "org" \| "timeoff"` | `"people"` | The page that opens first. |
| `defaultSelectedId` | `string` | `"marcus-johnson"` | The person the keyboard starts on, and whose profile shows when the panel opens without a pick. |
| `defaultProfileOpen` | `boolean` | `false` | Opens the profile panel on load. By default the people page has the full width and the profile opens when someone is chosen. |
| `onInvite` | `(invite: { email: string; team: Team }) => void` | – | Called when the Invite form is sent. The invite also appears under Pending invites. |
| `onManagerChange` | `(personId: string, managerId: string) => void` | – | Called when someone's manager changes, from a drag in the org chart or the Reports to field in a profile. |
| `onTimeOffDecision` | `(requestId: string, decision: "approve" \| "decline") => void` | – | Called when a request is approved or declined. |
| `className` | `string` | – | Class on the outer element. |

## Accessibility

- The cards are a listbox of options grouped by team, with one tab stop: arrow keys move by row and column, Home and End jump, Enter opens the profile. The table rows work the same way with up and down.
- Slash and the sidebar search (Cmd K) focus the people search, Escape clears it, and Down or Enter moves into the results.
- Office clocks are buttons with aria-pressed and a full label (office, local time, people working now); the layout switch is Arc's segmented control and sortable columns carry aria-sort.
- Team, status and manager pickers are listboxes in Arc's Popover: the highlight follows the arrow keys instantly, Escape closes and focus returns to the trigger.
- Every org chart change has a keyboard path: the Reports to field in the profile. Changes, approvals and invites are announced in a polite live region with an Undo button.
- Status is always a word next to its own glyph (check, calendar clock, plane, moon, hourglass), never colour alone. Copy and message results are announced through role="status".

## Motion

- The profile crossfades once when the person changes; the message composer opens with a height spring.
- Pickers and the invite form open in Arc's Popover: a short fade and settle from the trigger, leaving faster. Picker highlights move instantly.
- The Grid and List thumb is Arc's segmented control on the morph spring. Card, row and office selection is an instant calm fill in place, shown while the profile is open.
- Approved or declined requests leave and the list closes its gap on the smooth spring. Header notices fade in place.
- Arc's Buttons squeeze to 0.97 on press; picker and invite triggers answer with colour only. Hover fills are instant. Reduced motion removes every movement and keeps the final states.

## Responsive behavior

- Follows the screen shell: below 900px the sidebar (with the office clocks) is a sheet, below 1080px the profile panel is a sheet. Below 760px the org chart folds to two columns and the table drops Reports to and Started; below 600px the search takes its own row, cards stack in one column and the table keeps name and status.

## Performance

- Search and filters run in memory on every keystroke, and rows are not virtualized.
- For hundreds of people, filter on the server and paginate before passing data in.

## Notes for AI

- Use for an internal people directory, an HR or ops tool, or a company handbook where people need to find someone, see when they work and who they report to.
- The screen fills its container, so give the parent a height (the preview is 1440 by 900). Scrolling happens inside the page, the panel and the strips, never on the outer page.
- Replace the people, offices, teams and time off in team-directory-data.ts. directoryNow fixes the clock so server and client render the same local times; swap in Date.now() on a client only page.
- Messages are simulated and say so. Wire onInvite, onManagerChange and onTimeOffDecision to your backend.
- Built on Arc's screen shell (workspace mark: ScreenShellMark seed on teal) with Arc's Button, SearchField, SegmentedControl, Popover, Input, CopyButton, Badge, Avatar and Kbd. The office clocks are the shell's section content; Simple Icons marks for GitHub, LinkedIn and Slack.

## Related

- [Team members](https://uiarc.dev/components/blocks/team-members/markdown): A members list where typed emails turn into chips and fly into pending invites as seats roll.
- [Roles and permissions](https://uiarc.dev/components/blocks/roles-permissions/markdown): A permissions matrix with group toggles that ripple, role duplication and a review bar.

## Guidance for AI tools

Blocks are complete, self-contained screens with sample data. Replace the sample data and connect the callbacks described above. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://uiarc.dev/llms.txt
