# Read By

> How many have read a message, out of how many it went to, with a peek that reminds the rest.

- Name: `read-by`
- Status: beta
- Categories: people, display, overlays
- File: the install writes `read-by.tsx` to your `ui` alias, `@/components/ui` by default.
- Other registry items: `@arbokui/hover-card`, `@arbokui/peek-card`, `@arbokui/person`. The install adds them.
- Gallery: https://arbokui.com/components/read-by
- Registry item: https://arbokui.com/r/read-by.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/read-by
   ```

## Use it for

- Under a message, a notice, or a form people were asked to read: "Read by 241 of 280".
- Pass everyone it went to in people. Mark read: true, or the time, like "10:12", once they have.
- Its peek lists who has not read it yet, each with Remind, and Remind all for two or more.
- Send the reminders in onRemind. It runs once the 8-second undo window ends, never on the press.
- Once everyone has read it, it says "Read by all 23" as plain text, with no peek.

## Avoid it for

- A count with no one behind it, like page views. Use plain text.
- Showing who has read it. The peek is for the ones who have not.

## Props

- `people`: `Array<{ person: string; photo?: string; meta?: string; read?: boolean | string }>`. Required. Everyone it went to. read is true, or when they read it, once they have.
- `onRemind`: `(people: { person: string; photo?: string }[]) => void`. Reminds people who have not read it, once the undo window ends. Remind all leaves out anyone already reminded.
- `open`: `boolean`. Controlled. The peek shows while true. Hover, focus, and Esc only ask, through onOpenChange.
- `defaultOpen`: `boolean`. Default `false`. Starts with the peek open, without taking focus.
- `onOpenChange`: `(open: boolean) => void`. Hears the peek open and close, or what it asks for when controlled.
- `className`: `string`. Extra classes on the text. Later classes win.

## Accessibility

- With people still to read it, the text is a focusable button that opens a dialog. Its name is the count, like "Read by 241 of 280".
- The peek is named by its title, like "39 haven't read it yet". Enter moves into it, and Esc closes it and puts focus back.
- Each Remind says what it did in the page's one polite live region. Undo arms 1.2 seconds after a key press, and ⌘Z or Ctrl+Z takes back the newest reminder.
- Once everyone has read it, the text is plain, with no button and no Tab stop.

## Examples

### Under a message

```tsx
<ReadBy
  people={[
    { person: "Kate Clarke", read: "10:12" },
    { person: "Tom Hale", read: true },
    { person: "Ava Moss", meta: "Design team" },
    { person: "Rob Kerr", meta: "Support team" },
  ]}
  onRemind={(people) => console.log("remind", people)}
/>
```
