Skip to content
Nizivo UI

Alert

A tinted message with a title, an optional action and an optional dismiss button. Static and server-rendered unless you add the dismiss leaf.

Server component with client leaf AlertDismiss

Import

import { Alert, AlertDismiss } from '@nizivo/react/alert';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css and @nizivo/react/css/icon-button.css
import '@nizivo/react/css/alert.css';

Static or interactive

Split. An Alert ships one client module, the AlertDismiss leaf, only when you pass it in dismiss (+1,490 B gzip under Turbopack on the Next.js fixture's /alert-dismiss page). The shell does not import the leaf, so an Alert without dismiss ships nothing in every build mode. How to choose.

In a client app (a Vite or React Router single-page app, or a 'use client' file) it is an ordinary React component: event handlers, refs and state work as usual. In a client app.

The dismiss button

Pass an AlertDismiss in dismiss. With no render it is an IconButton (tertiary, sm) showing the close glyph, named "Dismiss", so it looks, sizes, focuses and responds like every other icon button. Change the name with labels, or pass aria-label; children replace the glyph.

<Alert
  tone="critical"
  role="alert"
  title="Payment failed for order #1040"
  dismiss={<AlertDismiss onDismiss={dismissPaymentAlert} labels={{ dismiss: 'Fermer' }} />}
>
  Card was declined.
</Alert>

onDismiss is called with no arguments, so a Server Component can pass a Server Action. The Alert does not hide itself: the caller stops rendering it. An Alert without a dismiss ships no client JavaScript; AlertDismiss is its only client module.

Its glyph is 16 px and sits where Figma draws the close glyph: 16 px from the inline-end edge and centred on the title's line. The 32 px button reaches into the padding around it, so the row is no taller. It has no tooltip, like Dialog.Close: its name is read by assistive technology, and a tooltip would add the Tooltip code to every page that shows a dismissible alert. Its markup is IconButton's, so a page that imports per-component stylesheets needs css/icon-button.css too (the stylesheets list above names it; styles.css already has it).

With render, it is your element. A plain element keeps its own look; an IconButton keeps its variant and size and takes the slot's placement, which is made for sm. To add a tooltip, compose one: render={<IconButton icon={<X />} label="Dismiss" variant="tertiary" size="sm" />}. --nz-alert-dismiss-fg still sets the glyph colour (default --nz-icon-secondary).

Examples

Basic

Server-rendered and static: no live role, no dismiss, no client JS.

Payouts move to daily on Nov 1
No action needed.
import type { JSX } from 'react';
import { Alert } from '@nizivo/react/alert';

/** Stand-ins for `@nizivo/icons` glyphs. */
function Mark(): JSX.Element {
  return (
    <svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor">
      <circle cx="12" cy="12" r="9" />
    </svg>
  );
}

export function AlertExample(): JSX.Element {
  return (
    <Alert icon={<Mark />} title="Payouts move to daily on Nov 1">
      No action needed.
    </Alert>
  );
}

Dismissible

Injected after a payment attempt, so it is announced. Dismissal is the caller's state: pass onDismiss from a client component, or a Server Action from a Server Component.

import type { JSX } from 'react';
import { Button } from '@nizivo/react/button';
import { Alert, AlertDismiss } from '@nizivo/react/alert';

/** Stand-ins for `@nizivo/icons` glyphs. */
function Mark(): JSX.Element {
  return (
    <svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor">
      <circle cx="12" cy="12" r="9" />
    </svg>
  );
}

function Cross(): JSX.Element {
  return (
    <svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor">
      <path d="M7 7l10 10M17 7 7 17" />
    </svg>
  );
}

export function AlertDismissibleExample({ onDismiss }: { onDismiss?: () => void }): JSX.Element {
  return (
    <Alert
      tone="critical"
      role="alert"
      icon={<Mark />}
      title="Payment failed for order #1040"
      action={<Button size="sm">Retry payment</Button>}
      dismiss={
        <AlertDismiss {...(onDismiss && { onDismiss })}>
          <Cross />
        </AlertDismiss>
      }
    >
      Card was declined.
    </Alert>
  );
}

Props

Alert

Server component Renders data-slot="alert" with the class nz-alert. Props: AlertProps. Source: src/alert/alert.tsx.

NameTypeDefaultDescription
actionReactNode–

Controls under the text, for example <Button size="sm">Retry</Button>.

dismissReactNode–

<AlertDismiss onDismiss={…}>…</AlertDismiss>; leave it out for an alert that cannot be dismissed.

iconReactNode–

Decorative tone glyph, for example <CircleX /> for critical; the text carries the meaning.

renderRenderProp<AlertState>–
roleComponentPropsWithRef<"div">["role"]–

There is no live role by default: an alert present on page load must not interrupt. Pass role="status" or role="alert" for one injected after a user action.

titleReactNode–

One line, Label/M Strong. The description is children.

toneAlertTone
"info""success""warning""critical"
'info'
  • Also takes every attribute of <div> except title; role is redeclared above. (Omit<ComponentPropsWithRef<"div">, "title">)

render takes an element, or, in client code, a function of the props and this state (AlertState):

NameTypeDefaultDescription
tonerequiredAlertTone
"info""success""warning""critical"
–

AlertDismiss

With no render, an IconButton (tertiary, sm: the 16 px glyph Figma draws, in a 32 px target) with no tooltip, as Dialog.Close does.

Client component Renders data-slot="alert-dismiss" with the class nz-alert-dismiss. Props: AlertDismissProps. Source: src/alert/alert-dismiss.client.tsx.

NameTypeDefaultDescription
childrenReactNode–

The close glyph, decorative. Defaults to the internal close glyph (Lucide's x).

labelsPartial<AlertDismissLabels>–
onDismiss() => void–

Called with no arguments, so a Server Component can pass a Server Action. The Alert does not hide itself: the caller stops rendering it.

renderRenderProp<Record<string, never>>–

Your element in place of the default IconButton; it must render a <button>. A plain element keeps its own look. An IconButton, for example render={<IconButton icon={<X />} label="Dismiss" variant="tertiary" size="sm" />} to add its tooltip, keeps its variant and size, and in an Alert takes the dismiss slot's placement (made for sm) and icon/secondary glyph colour, as a composed IconButton does in Dialog.Close.

  • Also takes every attribute of <button> except children. (Omit<ComponentPropsWithRef<"button">, "children">)

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

Other exports

AlertDismissLabels type

import type { AlertDismissLabels } from '@nizivo/react/alert'

Strings this part renders (§16.4).

NameTypeDefaultDescription
dismissrequiredstring'Dismiss'

The button's accessible name.

AlertDismissProps type

import type { AlertDismissProps } from '@nizivo/react/alert'

The props of AlertDismiss, listed above.

AlertProps type

import type { AlertProps } from '@nizivo/react/alert'

The props of Alert, listed above.

AlertState type

import type { AlertState } from '@nizivo/react/alert'

The render state of Alert, listed above.

AlertTone type

import type { AlertTone } from '@nizivo/react/alert'

Figma "Tone".

type AlertTone = "info" | "success" | "warning" | "critical"

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
alert
.nz-alert
Alert
root (takes render)
  • data-tone: "info""success""warning""critical" ← tone
    The tone prop; values in each component manifest
alert-action
.nz-alert-action
Alert
inner element (CSS only)
none
alert-content
.nz-alert-content
Alert
inner element (CSS only)
none
alert-description
.nz-alert-description
Alert
inner element (CSS only)
none
alert-dismiss
.nz-alert-dismiss
AlertDismiss
root (takes render); interactive, focus: self
none
alert-icon
.nz-alert-icon
Alert
inner element (CSS only)
none
alert-title
.nz-alert-title
Alert
inner element (CSS only)
none
icon-button-icon
.nz-icon-button-icon
AlertDismiss
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-alert-bg
  • default: var(--nz-bg-info-subtle)
  • data-tone="critical": var(--nz-bg-critical-subtle)
  • data-tone="success": var(--nz-bg-success-subtle)
  • data-tone="warning": var(--nz-bg-warning-subtle)
  • background on .nz-alert
--nz-alert-description-font--nz-font-body-m
  • font on .nz-alert-description
--nz-alert-dismiss-fg--nz-icon-secondary
  • --_nz-icon-button-fg on .nz-alert > .nz-icon-button.nz-alert-dismiss
--nz-alert-gap--nz-space-3
  • gap on .nz-alert
--nz-alert-icon-fg
  • default: var(--nz-icon-info)
  • data-tone="critical": var(--nz-icon-critical)
  • data-tone="success": var(--nz-icon-success)
  • data-tone="warning": var(--nz-icon-warning)
  • color on .nz-alert-icon
--nz-alert-padding-block--nz-space-3
  • padding-block on .nz-alert
--nz-alert-padding-inline--nz-space-4
  • padding-inline on .nz-alert
--nz-alert-radius--nz-radius-lg
  • border-radius on .nz-alert
--nz-alert-title-font--nz-font-label-m-strong
  • font on .nz-alert-title

Layers: nz.components. Classes: .nz-alert, .nz-alert-action, .nz-alert-content, .nz-alert-description, .nz-alert-dismiss, .nz-alert-icon, .nz-alert-title, .nz-icon-button.

Tokens this stylesheet reads (21)

--nz-bg-critical-subtle, --nz-bg-info-subtle, --nz-bg-success-subtle, --nz-bg-warning-subtle, --nz-font-body-m, --nz-font-label-m-strong, --nz-icon-critical, --nz-icon-info, --nz-icon-secondary, --nz-icon-success, --nz-icon-warning, --nz-radius-lg, --nz-size-control-sm, --nz-size-icon-md, --nz-size-icon-sm, --nz-space-0-5, --nz-space-2, --nz-space-3, --nz-space-4, --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:

  • alert-dismiss: draws the focus outline itself on keyboard focus.

Keyboard

KeysAction
TabMoves focus to the action, then to the dismiss button, in that order. The action is whatever you pass (the examples pass a Button); the dismiss control is a native button.
Enter, SpaceActivates the focused button. The dismiss button calls onDismiss; the caller stops rendering the alert.

Source: The Alert shell (alert.tsx) renders the action before the dismiss slot; AlertDismiss is a native <button type="button"> (alert-dismiss.client.tsx), and the Next fixture checks that it takes a click.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

On this page