Card
A surface with optional header, title, description, action, body and footer parts. The inverse tone flips every token inside it; brand and accent are the tinted surfaces of the dashboard widgets (KpiTile's tone), with no stroke.
Import
import { Card } from '@nizivo/react/card';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/card.css';Static or interactive
Server. It ships no client JavaScript when a Server Component renders it, in every Next.js build
mode; its code is bundled only when a client component (a 'use client' file) imports it. Every
part is server-safe; a child you put in Card.Action ships whatever its own component ships. 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.
Tones
tone="brand" and tone="accent" are new in 0.2.0; 0.1.0 has surface, subtle and inverse
only. In dark mode bg/brand-subtle and bg/accent-subtle
are both green-950, so the two tints look the same there. That is Figma's design, and the code
follows it for now (Figma 04 issue 5; the maintainer's decision M42).
On brand and accent, a Delta inside the Card is drawn as a
bg/surface pill, so it shows on the tint: Figma's bg/success-subtle pill is the same colour as
bg/brand-subtle (green-50 in light, and all three are green-950 in dark), so it would show no fill.
This is a deviation from Figma 04 (gap 4) that the maintainer chose (M42). The pill's text keeps its
colour, at least 5.68:1 on bg/surface in light and 5.96:1 in dark (text/critical; CONTRAST.md).
The nearest Card decides: a Delta inside an untinted Card nested in a tinted one keeps its own
pill. A --nz-delta-bg you set still wins.
The surface variable
Card declares --nz-surface, the colour it paints, in every tone (and so do KpiTile and TrendCard,
which are Cards). Any child can read it to match the surface it sits on, for example a ring or a gap
that should look cut out of the card:
.my-marker {
box-shadow: 0 0 0 2px var(--nz-surface, var(--nz-bg-surface));
}- It is read-only: Card sets it; set
--nz-card-bgto change the surface, and--nz-surfacefollows. - It is not a token. Outside a Card it is undefined, so always read it with a fallback.
- Inside
tone="inverse"it resolves in the inverse colour scheme, as every token there does. @nizivo/chartsreads it with a fallback: a Sparkline's end-dot halo, for example, takes the tinted tile's colour instead of a white ring, and still works on a page without@nizivo/react.
Examples
Basic
Top products
Last 30 days
Plan
import type { JSX } from 'react';
import { Badge } from '@nizivo/react/badge';
import { Button } from '@nizivo/react/button';
import { Card } from '@nizivo/react/card';
export function CardExample(): JSX.Element {
return (
<div>
<Card.Root>
<Card.Header>
<Card.Title>Top products</Card.Title>
<Card.Description>Last 30 days</Card.Description>
<Card.Action>
<Button variant="tertiary" size="sm">
View all
</Button>
</Card.Action>
</Card.Header>
<Card.Body>
Stoneware mug <Badge tone="success">In stock</Badge>
</Card.Body>
<Card.Footer>
<Button size="sm">Export</Button>
</Card.Footer>
</Card.Root>
<Card.Root tone="subtle">
<Card.Title level={2}>Plan</Card.Title>
<Card.Body>Grow, billed monthly</Card.Body>
</Card.Root>
<Card.Root tone="inverse" render={<section aria-label="Tip" />}>
<Card.Body>Share your store to get your first order.</Card.Body>
</Card.Root>
</div>
);
}
Tones
The tinted surfaces (M41): a row of related widgets shares one tint; it never encodes data.
Holiday drop is ready
Restock soon
import type { JSX } from 'react';
import { Card } from '@nizivo/react/card';
export function CardTonesExample(): JSX.Element {
return (
<div>
<Card.Root tone="brand">
<Card.Title>Holiday drop is ready</Card.Title>
<Card.Body>Brand: bg/brand-subtle, no stroke.</Card.Body>
</Card.Root>
<Card.Root tone="accent">
<Card.Title>Restock soon</Card.Title>
<Card.Body>Accent: bg/accent-subtle, no stroke.</Card.Body>
</Card.Root>
</div>
);
}
Parts
Use the parts through the namespace (Card.Root) or by their flat names (CardRoot); both work from Server Components.
Card.Root
Server component Renders data-slot="card" with the class nz-card. Props: CardRootProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
elevation | CardElevation01 | 0 | No shadow at rest until design says otherwise (decision 8j). |
padding | CardPadding"sm""md" | 'md' | |
render | RenderProp<CardRootState> | – | |
tone | CardTone"surface""subtle""inverse""brand""accent" | 'surface' |
|
- Also takes every attribute of
<div>. (ComponentPropsWithRef<"div">)
render takes an element, or, in client code, a function of the props and this state (CardRootState):
| Name | Type | Default | Description |
|---|---|---|---|
elevationrequired | CardElevation01 | – | |
paddingrequired | CardPadding"sm""md" | – | |
tonerequired | CardTone"surface""subtle""inverse""brand""accent" | – |
Card.Header
Server component Renders data-slot="card-header" with the class nz-card-header. Props: CardHeaderProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<div>. (ComponentPropsWithRef<"div">)
render takes an element, or, in client code, a function of the props and no state.
Card.Title
Server component Renders data-slot="card-title" with the class nz-card-title. Props: CardTitleProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
level | CardTitleLevel23456 | 3 | The heading level; its look is Heading/H4 at every level. |
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<h3>. (ComponentPropsWithRef<"h3">)
render takes an element, or, in client code, a function of the props and no state.
Card.Description
Server component Renders data-slot="card-description" with the class nz-card-description. Props: CardDescriptionProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<p>. (ComponentPropsWithRef<"p">)
render takes an element, or, in client code, a function of the props and no state.
Card.Action
Server component Renders data-slot="card-action" with the class nz-card-action. Props: CardActionProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<div>. (ComponentPropsWithRef<"div">)
render takes an element, or, in client code, a function of the props and no state.
Card.Body
Server component Renders data-slot="card-body" with the class nz-card-body. Props: CardBodyProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<div>. (ComponentPropsWithRef<"div">)
render takes an element, or, in client code, a function of the props and no state.
Card.Footer
Server component Renders data-slot="card-footer" with the class nz-card-footer. Props: CardFooterProps. Source: src/card/card.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
render | RenderProp<Record<string, never>> | – |
- Also takes every attribute of
<div>. (ComponentPropsWithRef<"div">)
render takes an element, or, in client code, a function of the props and no state.
Other exports
CardActionPropstypeimport type { CardActionProps } from '@nizivo/react/card'Figma "Show action": the control at the end of the header, for example an IconButton.
The props of
Card.Action, listed above.CardBodyPropstypeimport type { CardBodyProps } from '@nizivo/react/card'Figma's "Slot" frame.
The props of
Card.Body, listed above.CardDescriptionPropstypeimport type { CardDescriptionProps } from '@nizivo/react/card'The props of
Card.Description, listed above.CardElevationtypeimport type { CardElevation } from '@nizivo/react/card'0 draws no shadow (the rest elevation); 1 draws
--nz-elevation-1.type CardElevation = 0 | 1CardFooterPropstypeimport type { CardFooterProps } from '@nizivo/react/card'The props of
Card.Footer, listed above.CardHeaderPropstypeimport type { CardHeaderProps } from '@nizivo/react/card'The props of
Card.Header, listed above.CardPaddingtypeimport type { CardPadding } from '@nizivo/react/card'24 px (
md, Figma) or 20 px (sm).type CardPadding = "sm" | "md"CardRootPropstypeimport type { CardRootProps } from '@nizivo/react/card'The props of
Card.Root, listed above.CardRootStatetypeimport type { CardRootState } from '@nizivo/react/card'The render state of
Card.Root, listed above.CardTitleLeveltypeimport type { CardTitleLevel } from '@nizivo/react/card'type CardTitleLevel = 2 | 3 | 4 | 5 | 6CardTitlePropstypeimport type { CardTitleProps } from '@nizivo/react/card'The props of
Card.Title, listed above.CardTonetypeimport type { CardTone } from '@nizivo/react/card'Figma "Style": Surface | Subtle | Inverse, plus the tinted surfaces of the dashboard widgets (KPI Tile "Tinted", Insight Card Brand and Accent; figma/04 §2/§3, M41):
brand(bg/brand-subtle) andaccent(bg/accent-subtle).type CardTone = "surface" | "subtle" | "inverse" | "brand" | "accent"
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 |
|---|---|---|
card.nz-card | Card.Rootroot (takes render) |
|
card-action.nz-card-action | Card.Actionroot (takes render) | none |
card-body.nz-card-body | Card.Bodyroot (takes render) | none |
card-description.nz-card-description | Card.Descriptionroot (takes render) | none |
card-footer.nz-card-footer | Card.Footerroot (takes render) | none |
card-header.nz-card-header | Card.Headerroot (takes render) | none |
card-title.nz-card-title | Card.Titleroot (takes render) | 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-card-bg |
|
|
--nz-card-border |
|
|
--nz-card-gap | --nz-space-5 |
|
--nz-card-padding |
|
|
--nz-card-radius | --nz-radius-xl |
|
--nz-card-shadow |
|
|
--nz-card-title-font | --nz-font-heading-h4 |
|
Layers: nz.components. Classes: .nz-card, .nz-card-action, .nz-card-body, .nz-card-description, .nz-card-footer, .nz-card-header, .nz-card-title, .nz-delta.
Tokens this stylesheet reads (19)
--nz-bg-accent-subtle, --nz-bg-brand-subtle, --nz-bg-subtle, --nz-bg-surface, --nz-border-subtle, --nz-border-width-default, --nz-elevation-1, --nz-font-body-m, --nz-font-heading-h4, --nz-icon-secondary, --nz-radius-xl, --nz-space-1, --nz-space-2, --nz-space-3, --nz-space-5, --nz-space-6, --nz-text-primary, --nz-text-secondary, --nz-tracking-heading-h4
Accessibility
Nothing in this component takes focus or keyboard input.
Keyboard
None.
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.
- Canonical: Figma node
7275:13757 - Ghost masters: none
Button
A native button in five variants and three sizes, with a pending state that keeps focus. Compose it into triggers and links through render.
Checkbox
A native checkbox with its label, including the indeterminate (mixed) state. It submits with the form before hydration; inside a Field it is labelled, described and validated by the Field.