Source: https://monarchui.dev/components/no-app-access/

Components · Identity

# NoAppAccess

The “you don’t have access to this app” screen: who can fix it, request access, contact an admin and switch workspace.

@rookcom/monarch-react/shell

Component

## Every action

## Usage examples

### Explanation and a way back

## Purpose

A person can be a member of a Rook workspace without a grant for every app. NoAppAccess is that screen, built on ErrorPage, with the actions the person can actually take.

### Use when

- In place of the app’s pages when Rook ID says this member has no grant for the app.
- Inside an embedded page (App Settings) for the same case; it still counts as an answer for the ready handshake.

### Avoid when

- A missing permission inside the app (a page or an action): show an ErrorState or disable the action with a reason.
- Not signed in, or not a member of the workspace: those are sign-in and workspace flows.

## Design principles

- Say who can fix it: the person cannot grant themselves access, so the text names the admins (and the workspace).
- Always a way forward: request access, contact an admin, back to the workspace or another workspace.
- The grant check stays in the app; the screen only shows the outcome and runs the callbacks it is given.
- Calm, not alarming: a lock and plain words, no error code.

## API reference

```tsx
import { NoAppAccess } from '@rookcom/monarch-react/shell';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `NoAppAccess` | component | client | `.mn-no-app-access` |

Forwards its ref to the root element (`section`, or `main` with `fullScreen`). Built on ErrorPage (`kind="forbidden"`) from `@rookcom/monarch-react`.

Generated from the TypeScript declarations of `packages/react/src/components/identity/no-app-access`.

## Properties

With `onRequestAccess` returning a promise, the button shows pending, then "Access requested"; a rejection shows an alert and allows another try. `requestState` controls it (e.g. `sent` when a request is already open).

Switch workspace is `onSwitchWorkspace`, `switchWorkspaceHref`, or your own control in `workspaceSwitcher` (such as WorkspaceSwitcher).

### `NoAppAccess`

The "you don't have access to this app" screen: the person is a member of the workspace but has no grant for this app. It explains who can fix it and offers request access, contact an admin, back to the workspace and switch workspace. Built on ErrorPage (`forbidden`). The grant check stays in the app.

| Prop | Type | Description |
| --- | --- | --- |
| `appName` required | `string` | The app the person can't open, e.g. "Rook Tickets". |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `contactHref` | `string` | "Contact an admin": a mailto: or a page that lists the admins. |
| `description` | `ReactNode` | Replaces the default explanation. |
| `focusOnMount` | `boolean` | Focus the heading on mount, after a client-side navigation. Default false. |
| `fullScreen` | `boolean` | Fill the viewport (no app shell). Default false: sits in the shell's content area. |
| `headingLevel` | `"h2" \| "h1"` | Heading level. Default `h1` (the screen replaces the page). |
| `homeHref` | `string` | "Back to workspace": the workspace home in Rook ID or another app. |
| `id` | `string` |  |
| `linkAs` | `ShellLinkComponent` | Router link for the internal links. Default `<a>`. |
| `messages` | `Partial<NoAppAccessMessages>` | Interface text, for translation. |
| `onRequestAccess` | `(() => unknown)` | Shows "Request access". A returned promise drives the pending, sent and failed states (unless `requestState` is controlled). |
| `onSwitchWorkspace` | `(() => void)` | "Switch workspace" as an action… |
| `requestState` | `AccessRequestState` | Request state (controlled), e.g. `sent` when a request is already open. |
| `switchWorkspaceHref` | `string` | …or a link. |
| `title` | `ReactNode` | Replaces the default heading. |
| `workspaceName` | `string` | The current workspace, named in the explanation. |
| `workspaceSwitcher` | `ReactNode` | Or your own control (e.g. a WorkspaceSwitcher) in place of the switch button. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `fullScreen` | `'false'``'true'` | Inside the app shell (default), or filling the viewport without one. |
| `headingLevel` | `'h1'``'h2'` | h1 when the screen replaces the page (default). |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Idle | `data-request="idle"` | Request access is offered. |
| Pending | `data-request="pending"` | The button is busy (`aria-busy`) and ignores further clicks. |
| Sent | `data-request="sent"` | The button reads "Access requested" and is disabled; a status says what happens next. |
| Error | `data-request="error"` | An alert says the request failed; the button works again. |

## Interaction behaviour

- Request access runs `onRequestAccess` once per attempt.
- Back to workspace and switch links render with `linkAs` (your router link) when given.
- Contact an admin is a plain link (a mailto: or a page listing the admins).

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab | Moves through the actions and the contact link. |
| Enter / Space | Activates the focused action. |

## Accessibility

Role

region (section labelled by its heading), or main with fullScreen

Accessible name

The heading, "You don’t have access to <app>".

- The lock is decorative (`aria-hidden`), fixing the products’ unhidden icon.
- The sent message is in a status region, and a failure is an alert, so both are announced.
- `focusOnMount` moves focus to the heading after a client-side navigation.
- Security: the screen shows no data from the app and does not decide access; render it only after the app’s own grant check, and enforce access on the server too.

## Responsive behaviour

- Centred column; the actions wrap onto several lines at 320px.

## Theme support

- ErrorPage tokens; the status uses the success text colour and the error the danger text colour.

## Do and don't

### Do

- Name the app the way the rail and Rook ID do.
- Offer request access only when the product can actually deliver the request to the admins.
- Keep the rail on screen so the person can switch apps.

### Don't

- Do not show the app’s data or navigation behind the screen.
- Do not use it for a missing permission inside the app.

## Related components

- [ErrorPage](https://monarchui.dev/components/error-page/): The page-level error it is built on.
- [WorkspaceSwitcher](https://monarchui.dev/components/workspace-switcher/): Can fill the switch workspace slot.
- [ErrorState](https://monarchui.dev/components/error-state/): A failed region inside a page.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `react` |
| Monarch components | [Button](https://monarchui.dev/components/button/), [ErrorPage](https://monarchui.dev/components/error-page/) |

## Testing coverage

- Heading, explanation with the workspace, forbidden ErrorPage root, decorative lock, no actions by default.
- Request access: pending, single call, then sent (status) and disabled.
- A failed request is an alert and can be retried; a synchronous request counts as sent; controlled state.
- Back to workspace, switch workspace and contact links; switch link, custom switcher slot and router link.
- Focus on mount, h2, custom text and full screen; translation.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/no-app-access; Cross-browser axe: /components/no-app-access |

Tests: `packages/react/src/components/identity/no-app-access`

## All example code

### Every action

```tsx
import { NoAppAccess } from '@rookcom/monarch-react/shell';

function Basic() {
  return (
    <NoAppAccess
      appName="Example Desk"
      workspaceName="Acme"
      headingLevel="h2"
      onRequestAccess={() => new Promise((resolve) => setTimeout(resolve, 800))}
      homeHref="#workspace-home"
      onSwitchWorkspace={() => {}}
      contactHref="mailto:admin@example.com"
    />
  );
}

<Basic />
```

### Explanation and a way back

```tsx
import { NoAppAccess } from '@rookcom/monarch-react/shell';

function Minimal() {
  return <NoAppAccess appName="Example Wiki" headingLevel="h2" homeHref="#workspace-home" />;
}

<Minimal />
```
