Components
ApprovalCard
Unstable: the AI asks before an action it cannot undo, saying what will happen and to whom, with Cancel, Edit first and a confirm that names the action. Import it from @nizivo/react/unstable/approval-card.
Examples
Basic
The AI asks before sending emails it cannot unsend. autoFocus={false} here, since the card is part of the page; in a conversation it appears in answer to the reader, and focus lands on Cancel.
Send 3 emails to customers?
import type { JSX } from 'react';
import { ApprovalCard } from '@nizivo/react/unstable/approval-card';
export function ApprovalCardExample(): JSX.Element {
return (
<div style={{ maxInlineSize: 480 }}>
<ApprovalCard
title="Send 3 emails to customers?"
confirmLabel="Send emails"
autoFocus={false}
summary={
<>
<span>To: 3 customers whose orders shipped late</span>
<span>Subject: Your order is on its way</span>
</>
}
>
Each gets a short apology and a 10 % code. Sent emails cannot be unsent.
</ApprovalCard>
</div>
);
}
Edit First
The card: onEdit adds "Edit first", which opens the draft before anything is sent.
import type { JSX } from 'react';
import { ApprovalCard } from '@nizivo/react/unstable/approval-card';
export function ApprovalCardEditFirstExample(): JSX.Element {
return (
<div style={{ maxInlineSize: 480 }}>
<ApprovalCard
title="Send 3 emails to customers?"
confirmLabel="Send emails"
autoFocus={false}
onEdit={() => {}}
summary={
<>
<span>To: 3 customers whose orders shipped late</span>
<span>Subject: Your order is on its way</span>
</>
}
>
Each gets a short apology and a 10 % code. Sent emails cannot be unsent.
</ApprovalCard>
</div>
);
}
Import
import { ApprovalCard } from '@nizivo/react/unstable/approval-card';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/ai-badge.css and @nizivo/react/css/base.css and @nizivo/react/css/button.css
import '@nizivo/react/css/approval-card.css';Static or interactive
Client. It moves focus to Cancel when it appears and cancels on Escape. How to choose.
Content
title is the action ("Send 3 emails to customers?"), the children say what will happen and what
cannot be taken back, and summary sets out the details (the recipients, the subject, the amount).
confirmLabel names the action ("Send emails"), never "OK". onEdit adds an "Edit first" button.
pending shows the confirm in flight.
Focus
As the design asks, focus lands on Cancel when the card mounts, without scrolling (autoFocus={false}
turns that off, for a card rendered with the page rather than in answer to the reader), and Escape
anywhere in the card calls onCancel. It is a section named by its title, not a modal: the
conversation stays readable around it. headingLevel (3 by default) fits it into the page outline.
Props
Client component Renders data-slot="approval-card" with the class nz-approval-card. Props: ApprovalCardProps. Source: src/unstable/approval-card/approval-card.client.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
autoFocus | boolean | true | Focus Cancel when the card mounts. |
confirmLabelrequired | ReactNode | – | The confirm button's label, naming the action: "Send emails". |
headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | The title's level, so the card fits the page outline. |
labels | Partial<ApprovalCardLabels> | – | |
onCancel | () => void | – | Cancel and Escape call it. |
onConfirm | () => void | – | |
onEdit | () => void | – | Without it there is no "Edit first" button. |
pending | boolean | false | The confirm is in flight (Button |
render | RenderProp<Record<string, never>> | – | Must render a |
summary | ReactNode | – | What exactly will happen, set apart: the recipients, the subject, the amount. |
titlerequired | ReactNode | – | The action, as a question or a statement: "Send 3 emails to customers?" |
- Also takes every attribute of
<section>excepttitle;autoFocusis redeclared above. (Omit<ComponentPropsWithRef<"section">, "title">)
render takes an element, or, in client code, a function of the props and no state.
Other exports
ApprovalCardLabelstypeimport type { ApprovalCardLabels } from '@nizivo/react/unstable/approval-card'ApprovalCard's own strings (§16.4): serialisable, English defaults.
Name Type Default Description badgerequiredstring'Needs your approval'The badge over the title.
cancelrequiredstring'Cancel'editrequiredstring'Edit first'ApprovalCardPropstypeimport type { ApprovalCardProps } from '@nizivo/react/unstable/approval-card'The props of
ApprovalCard, listed above.
Data attributes and slots
Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.
| Slot | Rendered by | Data attributes |
|---|---|---|
approval-card.nz-approval-card | ApprovalCardroot (takes render) | none |
approval-card-action.nz-approval-card-action | ApprovalCardinner element (CSS only); interactive, focus: self | none |
approval-card-body.nz-approval-card-body | ApprovalCardinner element (CSS only) | none |
approval-card-summary.nz-approval-card-summary | ApprovalCardinner element (CSS only) | none |
approval-card-title.nz-approval-card-title | ApprovalCardinner element (CSS only) | none |
CSS hooks
Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.
| Hook | Default | Read as |
|---|---|---|
--nz-approval-card-bg | --nz-bg-surface |
|
--nz-approval-card-radius | --nz-radius-xl |
|
Layers: nz.components. Classes: .nz-approval-card, .nz-approval-card-actions, .nz-approval-card-body, .nz-approval-card-summary, .nz-approval-card-title.
Tokens this stylesheet reads (17)
--nz-bg-subtle, --nz-bg-surface, --nz-border-brand, --nz-border-width-default, --nz-elevation-2, --nz-font-body-m, --nz-font-body-s, --nz-font-heading-h3, --nz-radius-md, --nz-radius-xl, --nz-space-0-5, --nz-space-1-5, --nz-space-2, --nz-space-3, --nz-space-5, --nz-text-primary, --nz-text-secondary
Accessibility
These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:
approval-card-action: draws the focus outline itself on keyboard focus.
Keyboard
To be written.
AppShell
The page's frame. The Sidebar and the TopBar on screens 640 px and wider, the MobileTopBar and the MobileTabBar below that, around the page's main content, switched by CSS with no script.
Avatar
A person's or store's photo with an initials fallback that needs no script, and AvatarGroup, a stack of avatars and a count announced as one item ("Maya, Jonah, Priya, and 4 more").