# No Access

> What someone sees when they open something they cannot: what it is, whose it is, and Request access with an 8-second Undo.

- Name: `no-access`
- Status: beta
- Categories: feedback
- File: the install writes `no-access.tsx` to your `ui` alias, `@/components/ui` by default.
- npm packages: `lucide-react`. The install adds them.
- Other registry items: `@arbokui/button`, `@arbokui/spot-icon`. The install adds them.
- Gallery: https://arbokui.com/components/no-access
- Registry item: https://arbokui.com/r/no-access.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/no-access
   ```

## Use it for

- Put it where the content would be, when someone opens a page, file, or team they cannot see.
- Name what it is in title, so they know they reached the right thing.
- Pass owner, so they know who will get the request. Put their avatar in owner.avatar.
- Send the request in onRequest. It runs once the 8-second undo window ends, or when the part leaves the page.
- Pass asked when they asked before, so the button shows the record instead of asking twice.

## Avoid it for

- Hiding that something exists when its name is private too. Show a plain not-found page instead.
- Sending the request on press. onRequest waits for the undo window, so Undo never takes back a sent email.
- Content that is only loading or empty. Use an empty state or a skeleton.

## Props

- `title`: `string`. What it is, like "Budget review, before Saturday 3 October".
- `owner`: `{ person: string; avatar?: ReactNode }`. Whose it is. avatar is an element, like an Avatar with their photo.
- `hint`: `string`. Default `"Ask for access and they get an email. You hear back when they answer."`. What happens when they ask.
- `asked`: `{ at?: string | Date } | null`. Asked before. The button shows "Asked", with the day and time when at is given.
- `onRequest`: `() => void`. Sends the request, once the 8-second undo window ends.
- `headingLevel`: `1 | 2 | 3 | 4 | 5 | 6`. Default `2`. The title's heading level, so it fits the page's outline.
- `className`: `string`. Extra classes on the root. Later classes win.

## Accessibility

- The title is a real heading, at the level you give.
- Request access is a native button. After a press it reads "Asked. Press to undo." and focus stays on it.
- Undo arms when the pointer leaves, or after 1.2 seconds for the keys and touch, so a double press never undoes.
- A polite status line says the request was made, and says when it was undone.
- Once sent, the button is a record: it stays in the tab order with aria-disabled and full contrast.
- The lock spot is hidden from screen readers, since the title says what it is.

## Examples

### A page they cannot see

```tsx
"use client";

export function LockedPage() {
  return (
    <NoAccess
      title="Budget review, before Saturday 3 October"
      owner={{ person: "Sam Carter" }}
      onRequest={() => fetch("/api/access-requests", { method: "POST" })}
    />
  );
}
```

### Asked before

```tsx
<NoAccess
  title="Pay notes, Design team"
  owner={{ person: "Priya Shah" }}
  asked={{ at: "2026-10-02T09:20:00" }}
/>
```
