Skip to content
Get started

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.

Tier: clientUnstable

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.

Needs your approval

Send 3 emails to customers?

Each gets a short apology and a 10 % code. Sent emails cannot be unsent.
To: 3 customers whose orders shipped lateSubject: Your order is on its way
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.

Source only
It passes an event handler, code that runs in a client component of your app, so it is shown as source only.
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.

NameTypeDefaultDescription
autoFocusbooleantrue

Focus Cancel when the card mounts.

confirmLabelrequiredReactNode–

The confirm button's label, naming the action: "Send emails".

headingLevel2 | 3 | 4 | 5 | 63

The title's level, so the card fits the page outline.

labelsPartial<ApprovalCardLabels>–
onCancel() => void–

Cancel and Escape call it.

onConfirm() => void–
onEdit() => void–

Without it there is no "Edit first" button.

pendingbooleanfalse

The confirm is in flight (Button pending).

renderRenderProp<Record<string, never>>–

Must render a <section>.

summaryReactNode–

What exactly will happen, set apart: the recipients, the subject, the amount.

titlerequiredReactNode–

The action, as a question or a statement: "Send 3 emails to customers?"

  • Also takes every attribute of <section> except title; autoFocus is redeclared above. (Omit<ComponentPropsWithRef<"section">, "title">)

render takes an element, or, in client code, a function of the props and no state.

Other exports

ApprovalCardLabels type

import type { ApprovalCardLabels } from '@nizivo/react/unstable/approval-card'

ApprovalCard's own strings (§16.4): serialisable, English defaults.

NameTypeDefaultDescription
badgerequiredstring'Needs your approval'

The badge over the title.

cancelrequiredstring'Cancel'
editrequiredstring'Edit first'
ApprovalCardProps type

import 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.

SlotRendered byData attributes
approval-card
.nz-approval-card
ApprovalCard
root (takes render)
none
approval-card-action
.nz-approval-card-action
ApprovalCard
inner element (CSS only); interactive, focus: self
none
approval-card-body
.nz-approval-card-body
ApprovalCard
inner element (CSS only)
none
approval-card-summary
.nz-approval-card-summary
ApprovalCard
inner element (CSS only)
none
approval-card-title
.nz-approval-card-title
ApprovalCard
inner 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.

HookDefaultRead as
--nz-approval-card-bg--nz-bg-surface
  • background on .nz-approval-card
--nz-approval-card-radius--nz-radius-xl
  • border-radius on .nz-approval-card

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.

On this page