Skip to content
BrandCloud

Components

Astro components render to HTML with no client JavaScript. React components are accessible primitives for interactive screens. Both read only the tokens, so everything below follows this site's brand.

On this page

Props tables are generated from the packages at build time. Hover and focus are also shown with the pointer away, labelled, so you can see every state at once.

Astro components

Import

import Button from "@brandcloud/astro/components/Button.astro";

Button

Same props as the React Button. A link when it has href, otherwise a button. No arrows inside; a channel glyph is the only icon allowed.

tone="brand"

tone="ink"

tone="neutral"

tone="danger"

tone="whatsapp"

tone="level"

size

States

defaulthoverfocus-visiblepressed (held)loadingdisabled
Button props
Props of Button
PropTypeDefaultWhat it does
toneButtonTonenone
appearanceButtonAppearancenone
levelOfferLevelnone
sizeButtonSizenone
variantButtonVariantAliasnone
loadingbooleanfalse
disabledbooleanfalse
blockbooleanfalseFull width.
channel"whatsapp" | "phone" | "email"noneChannel glyph before the label.
externalbooleanfalseOpens in a new tab (links only).
classstringnone

Also accepts: Any <a> attribute when href is set, otherwise <button> attributes

Container

A centred column with the brand's gutters.

width="narrow"
width="default"
width="wide"
Container props
Props of Container
PropTypeDefaultWhat it does
width"narrow" | "default" | "wide" | "full""default"
as"div" | "section" | "header" | "footer" | "nav" | "main""div"
classstringnone

Section

A page section. tone re-points the tokens for everything inside, so components on an ink or brand section take its colours. Use the brand tone once per page at most.

tone="default"

tone="muted"

tone="raised"

tone="ink"

tone="brand"

Section props
Props of Section
PropTypeDefaultWhat it does
toneSectionTonenone
appearance"neutral" | "brand" | "inverse"none
space"none" | "tight" | "default" | "loose""default"
width"narrow" | "default" | "wide" | "full""default"
as"section" | "div" | "aside" | "header" | "footer""section"
containedbooleantrueSet false to render children without the inner Container (full-bleed layouts).
idstringnone
classstringnone
aria-labelledbystringnone
aria-labelstringnone

Heading

Rank (as) and look (size) are set separately. These examples use as="p" so they do not add to this page's outline.

size="display"

size="h1"

size="h2"

size="h3"

size="h4"

Heading props
Props of Heading
PropTypeDefaultWhat it does
as"h1" | "h2" | "h3" | "h4" | "p""h2"
size"display" | "h1" | "h2" | "h3" | "h4"none
idstringnone
classstringnone
balancebooleantrue

Hero

Three layouts so two sites never share one look: split beside a real photo, field on a solid surface with key facts, and editorial.

variant="split" with media

Bikes serviced while you work

Drop it off before nine, collect it by five.

The campaign recipe page for a made-up physio clinic.

variant="field"

Winter service week

Every bike checked for dark mornings.

Dates
1 to 7 December
Price
£45

variant="editorial"

A bike shop that explains the fix

We show you what was worn and why it mattered.

Fictional example.

Hero props
Props of Hero
PropTypeDefaultWhat it does
copy requiredHeroCopynone
variant"split" | "field" | "editorial""split"
tone"default" | "muted" | "raised" | "ink" | "brand"noneSurface. Defaults: split/editorial = default, field = ink.
mediaImageRefnone
mediaCaptionstringnone
portraitbooleannonePortrait photos get a narrower column. Detected from width/height when given.
factsHeroFact[][]
headingLevel"h1" | "h2""h1"
idstringnone
classstringnone

Steps

A real ordered list, numbered in text. Three layouts.

variant="rail"

How a service works

  1. Book online

    Pick a slot that suits you.

    Two minutes

  2. Drop it off

    Leave the bike with us before 9am.

    Same day

  3. Collect it

    We text you when it is ready.

    By 5pm

variant="list"

How a service works

  1. Book online

    Pick a slot that suits you.

    Two minutes

  2. Drop it off

    Leave the bike with us before 9am.

    Same day

  3. Collect it

    We text you when it is ready.

    By 5pm

variant="split"

How a service works

  1. Book online

    Pick a slot that suits you.

    Two minutes

  2. Drop it off

    Leave the bike with us before 9am.

    Same day

  3. Collect it

    We text you when it is ready.

    By 5pm

Steps props
Props of Steps
PropTypeDefaultWhat it does
steps requiredStepItem[]none
variant"rail" | "list" | "split""rail"
headingstringnone
introstringnone
headingLevel"h2" | "h3""h2"
stepLabelstring""Text before the number for screen readers and sighted users, e.g. "Step". Empty for numerals only.
idstringnone
classstringnone

TrustStrip

Real credentials only. The logos layout keeps each name visible next to its logo; it needs real logos, so it is not drawn here.

  • Fixed prices before work starts
  • Twelve-month warranty on labour
  • Open six days a week
  • Card and cash
  • Step-free entrance
  • Free parking
TrustStrip props
Props of TrustStrip
PropTypeDefaultWhat it does
items requiredTrustItem[]none
variant"rule" | "inline" | "logos""rule"
label requiredstringnoneAccessible name of the list, e.g. "Qualifications and memberships".
classstringnone

Faq

Native details and summary: works with no JavaScript and from the keyboard.

Questions

Do you need the bike all day?

Most services are done by 5pm on the day.

Can I wait while you work?

Yes, for safety checks. They take about twenty minutes.

Still not sure?

Ask us anything.

Send a question

Questions

Do you need the bike all day?

Most services are done by 5pm on the day.

Can I wait while you work?

Yes, for safety checks. They take about twenty minutes.

Faq props
Props of Faq
PropTypeDefaultWhat it does
items requiredFaqItem[]none
headingstringnone
introstringnone
variant"split" | "stacked""split"
headingLevel"h2" | "h3""h2"
openFirstbooleanfalseOpen the first question.
ask{ heading: string; text?: string; action: CtaLink }none"Still have questions?" block: heading, text and one action.
idstringnone
classstringnone

CtaBand

One clear next step. Urgency shows only with a real reason and an end date or policy.

variant="band"

Book before the winter rush

variant="card"

Questions about your bike?

We reply the same day.

variant="split" with an aside

Visit the workshop

Open Monday to Saturday.

Merewick Cycles

8am to 6pm, fictional address.

CtaBand props
Props of CtaBand
PropTypeDefaultWhat it does
copy requiredCtaCopynone
variant"band" | "card" | "split""band"
tone"default" | "muted" | "raised" | "ink" | "brand"none
urgencyUrgencyCopynone
headingLevel"h2" | "h3""h2"
hidesStickyBarbooleantrue
idstringnone
classstringnone

Navbar

The mobile menu is a native disclosure; a small script adds Escape, outside click and link-click close.

Navbar props
Props of Navbar
PropTypeDefaultWhat it does
brandName requiredstringnone
brandHrefstring"/"
brandNameHiddenbooleanfalseHide the text name visually (keep it for screen readers) when the logo spells it.
links requiredNavLink[]none
ctaCtaLinknone
secondaryCtaLinknoneA quiet channel link, e.g. WhatsApp or phone.
layout"split" | "left""split"
tone"default" | "raised" | "ink""default"
stickybooleantrue
navLabelstring"Main"Accessible names. Generic defaults; pass your own words if you prefer.
menuLabelstring"Menu"
classstringnone

EnquiryFormShell

No backend: it posts natively to your action. The script adds inline errors and moves focus to the first problem. In preview mode it never sends. Consent is unticked and separate.

Ask a mechanic

submits the empty form, so the component's own validation shows its errors.

EnquiryFormShell props
Props of EnquiryFormShell
PropTypeDefaultWhat it does
actionstringnone
method"post" | "get""post"
mode"live" | "preview""live"
previewMessagestringnone
headingstringnone
introstringnone
labelsPartial<Labels>{}
fieldsField[]["name", "email", "phone", "message"]
requiredField[]["name", "email"]
interest{ label: string; options: string[]; placeholder?: string; name?: string }none
consent{ label: string; required?: boolean; name?: string }none
hiddenRecord<string, string>{}
honeypotbooleantrue
layout"stacked" | "grid" | "panel""stacked"
headingLevel"h2" | "h3""h3"
idstring"enquiry"
classstringnone

Icon

Stroke icons in currentColor, decorative unless given a label. Arrows are for text links only.

  • check
  • plus
  • menu
  • close
  • whatsapp
  • phone
  • email
  • shield
  • map-pin
  • clock
  • calendar
  • arrow-right
  • external
Icon props
Props of Icon
PropTypeDefaultWhat it does
name requiredIconNamenone
sizenumber18
labelstringnone
classstringnone

React: Button

Tone is the colour role, appearance the treatment. Without an appearance the brand decides.

tone="brand"

tone="ink"

tone="neutral"

tone="danger"

tone="whatsapp"

tone="level"

size

States

defaulthoverfocus-visiblepressed (held)loadingdisabled

Toggle (pressed prop)

As a link (render)

Button

A real <button>, or any element through render or asChild. Loading sets aria-busy and keeps the width.

Button props
Props of Button
PropTypeDefaultWhat it does
toneButtonTonenone
appearanceButtonAppearancenone
levelButtonLevelnone
sizeButtonSize"md"
loadingbooleanfalse
pressedbooleannoneToggle state. Sets `aria-pressed`; leave undefined for ordinary actions.
variantButtonVariantnoneshadcn-compatible alias. Explicit `tone` and `appearance` win over it.
renderButtonRendernoneRender as another element (for example a router link) while keeping Button styling and state.
asChildbooleanfalseRadix-style alternative to `render`: style the single child element as the button.

Also accepts: ButtonHTMLAttributes<HTMLButtonElement>

React: Form fields

FormField wires the label, description and error to its control, so inputs inside it need no ids.

As it appears on invoices.

Enter a full email address, with an @ and a domain.

Disabled until the account is verified.

Choose a service to continue.

Anything the mechanic should know.

Keep it under 500 characters.

Built from parts

For the collection address.

That postcode looks incomplete.

FormField

Label, description and error around one control. Setting error marks the control invalid.

FormField props
Props of FormField
PropTypeDefaultWhat it does
label requiredstringnone
idstringnone
requiredbooleanfalse
descriptionReactNodenone
errorReactNodenone
disabledbooleanfalse

Also accepts: HTMLAttributes<HTMLDivElement>

FormLabel

A label on its own, with an optional required marker.

FormLabel props
Props of FormLabel
PropTypeDefaultWhat it does
requiredbooleannone

Also accepts: LabelHTMLAttributes<HTMLLabelElement>

FormDescription

Help text under a control.

FormDescription props

Also accepts: HTMLAttributes<HTMLParagraphElement>

FormError

The error message under a control.

FormError props

Also accepts: HTMLAttributes<HTMLParagraphElement>

Input

A text input. invalid shows the error state without a FormField.

Input props
Props of Input
PropTypeDefaultWhat it does
invalidbooleannone

Also accepts: InputHTMLAttributes<HTMLInputElement>

Select

A native select with options as data and a placeholder.

Select props
Props of Select
PropTypeDefaultWhat it does
labelReactNodenone
optionsArray<SelectOption | string>none
placeholderstringnone
invalidbooleannone
valuestring | numbernone
onValueChange(value: string) => voidnone

Also accepts: Omit<SelectHTMLAttributes<HTMLSelectElement>, "onChange" | "value">

Textarea

Multi-line text, with the same states as Input.

Textarea props
Props of Textarea
PropTypeDefaultWhat it does
invalidbooleannone

Also accepts: TextareaHTMLAttributes<HTMLTextAreaElement>

React: Choices

Native inputs underneath, so forms submit and validate without extra code.

Extras
Collection

Single radios

Checkbox

One checkbox with its label. Supports indeterminate.

Checkbox props
Props of Checkbox
PropTypeDefaultWhat it does
valuestring | undefinednone
checkedboolean | undefinednone
defaultCheckedboolean | undefinedfalse
onChangeInputHTMLAttributes<HTMLInputElement>["onChange"]none
onCheckedChange((checked: boolean) => void) | undefinednone
labelReactNodenone
indeterminateboolean | undefinedfalse

Also accepts: Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "onChange" | "checked" | "defaultChecked" | "value">

CheckboxGroup

A fieldset of checkboxes with a legend, from data.

CheckboxGroup props
Props of CheckboxGroup
PropTypeDefaultWhat it does
legendReactNodenone
namestring | undefinednone
valueReadonlyArray<string> | undefinednone
defaultValueReadonlyArray<string> | undefinednone
onValueChange((value: string[]) => void) | undefinednone
optionsReadonlyArray<CheckboxOption> | undefinednone
disabledValuesIterable<string> | undefinednone
disabledboolean | undefinednone
readOnlyboolean | undefinednone
requiredboolean | undefinednone

Also accepts: Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "onChange" | "value" | "defaultValue">

Radio

One radio with its label.

Radio props
Props of Radio
PropTypeDefaultWhat it does
value requiredstringnone
checkedboolean | undefinednone
defaultCheckedboolean | undefinedfalse
onChangeInputHTMLAttributes<HTMLInputElement>["onChange"]none
labelReactNodenone

Also accepts: Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "onChange" | "checked" | "defaultChecked" | "value">

RadioGroup

A fieldset of radios with a legend, from data.

RadioGroup props
Props of RadioGroup
PropTypeDefaultWhat it does
legendReactNodenone
namestring | undefinednone
valuestring | undefinednone
defaultValuestring | undefinednone
onValueChange((value: string) => void) | undefinednone
optionsReadonlyArray<RadioOption> | undefinednone
disabledboolean | undefinednone
readOnlyboolean | undefinednone
requiredboolean | undefinednone

Also accepts: Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "onChange" | "value" | "defaultValue">

Switch

An on and off switch, a checkbox underneath.

Switch props
Props of Switch
PropTypeDefaultWhat it does
checkedboolean | undefinednone
defaultCheckedboolean | undefinedfalse
onChangeInputHTMLAttributes<HTMLInputElement>["onChange"]none
onCheckedChange((checked: boolean) => void) | undefinednone
labelReactNodenone

Also accepts: Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "onChange" | "checked" | "defaultChecked">

React: Overlays

Focus is trapped where it should be, Escape closes, and focus returns to the trigger.

Dialog

Drawer

Menu

Popover

Tooltip

Toast

Dialog

A modal with a title, description, content and actions. The trigger must be one real button.

Dialog props
Props of Dialog
PropTypeDefaultWhat it does
trigger requiredTriggerElementnoneExactly one interactive button element. BrandCloud intentionally does not accept arbitrary ReactNode here because Base UI trigger behaviour must be composed onto the actual interactive element.
descriptionStableReactNodenone
children requiredStableReactNodenone
actionsStableReactNodenone
closeLabelstring"Close"Text for the built-in close button.
openbooleannoneControlled state.
defaultOpenbooleannoneInitial state for uncontrolled usage.
onOpenChange(open: boolean) => voidnone
portalDirectionDirectionnoneOptional portal presentation overrides. When omitted, values are captured from document.documentElement when the dialog opens.
portalThemestringnone
portalDataAttributesPortalDataAttributesnoneData attributes copied to the portaled root for scoped presentation adapters.
classNamestringnoneOptional class applied to the trigger element.
title requiredstring | number | bigint | Exclude<AccessibleTitleNode, string | number | bigint>noneA primitive visible title that supplies its own programmatic name.
titleAccessibleLabelstring | stringnone

Drawer

A modal panel from the left or right edge.

Drawer props
Props of Drawer
PropTypeDefaultWhat it does
trigger requiredDrawerTriggerElementnoneExactly one real button onto which Base UI composes trigger behaviour.
descriptionStableReactNodenone
children requiredStableReactNodenone
actionsStableReactNodenone
closeLabelstring"Close"
sideDrawerSide"right"
openbooleannone
defaultOpenbooleannone
onOpenChange(open: boolean) => voidnone
portalDirectionDrawerDirectionnone
portalThemestringnone
portalDataAttributesPortalDataAttributesnoneData attributes copied to the portaled root for scoped presentation adapters.
classNamestringnone
title requiredstring | number | bigint | Exclude<AccessibleTitleNode, string | number | bigint>noneA primitive visible title that supplies its own programmatic name.
titleAccessibleLabelstring | stringnone

Menu

The root of an actions menu.

Menu props
Props of Menu
PropTypeDefaultWhat it does
children requiredReactNodenone
openboolean | undefinednoneControlled open state.
defaultOpenboolean | undefinedfalseInitial state for uncontrolled usage.
onOpenChange((open: boolean) => void) | undefinednoneEvent handler called when the menu opens or closes.
sideMenuSide | undefined"bottom"Default side of the trigger the popover is placed on.
alignMenuAlign | undefined"center"Default alignment of the popover relative to the trigger.

MenuTrigger

The button that opens the menu.

MenuTrigger props
Props of MenuTrigger
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BaseMenuTriggerProps, "children">

MenuPopover

The menu panel.

MenuPopover props
Props of MenuPopover
PropTypeDefaultWhat it does
childrenReactNodenone
sideMenuSide | undefinednone
alignMenuAlign | undefinednone

Also accepts: Omit<BaseMenuPopupProps, "children">

MenuItem

One action. onSelect runs on click or Enter.

MenuItem props
Props of MenuItem
PropTypeDefaultWhat it does
onSelect(() => void) | undefinednoneCalled when the item is activated by pointer or keyboard.
closeOnSelectboolean | undefinedtrueWhether the menu closes after the item is selected.

Also accepts: Omit<BaseMenuItemProps, "onClick" | "closeOnClick">

MenuCheckboxItem

An item that toggles.

MenuCheckboxItem props
Props of MenuCheckboxItem
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BaseMenuCheckboxItemProps, "children">

MenuGroup

Groups items under a label.

MenuGroup props
Props of MenuGroup
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BaseMenuGroupProps, "children">

MenuLabel

The label of a group.

MenuLabel props
Props of MenuLabel
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BaseMenuGroupLabelProps, "children">

MenuSeparator

A rule between groups.

MenuSeparator props

Also accepts: HTMLAttributes<HTMLDivElement>

Popover

Non-modal content anchored to a trigger.

Popover props
Props of Popover
PropTypeDefaultWhat it does
children requiredReactNodenone
openboolean | undefinednoneControlled open state.
defaultOpenboolean | undefinedfalseInitial state for uncontrolled usage.
onOpenChange((open: boolean) => void) | undefinednoneEvent handler called when the popover opens or closes.
sidePopoverSide | undefined"bottom"Default side of the trigger the content is placed on.
alignPopoverAlign | undefined"center"Default alignment of the content relative to the trigger.

PopoverTrigger

The button that opens it.

PopoverTrigger props
Props of PopoverTrigger
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BasePopoverTriggerProps, "children">

PopoverContent

The panel.

PopoverContent props
Props of PopoverContent
PropTypeDefaultWhat it does
childrenReactNodenone
sidePopoverSide | undefinednone
alignPopoverAlign | undefinednone

Also accepts: Omit<BasePopoverPopupProps, "children">

Tooltip

A short label on hover and keyboard focus. Never the only place for important text.

Tooltip props
Props of Tooltip
PropTypeDefaultWhat it does
children requiredReactNodenone
delaynumber | undefined300
closeDelaynumber | undefined0
openboolean | undefinednone
defaultOpenboolean | undefinedfalse
onOpenChange((open: boolean) => void) | undefinednone
disabledboolean | undefinedfalse

TooltipTrigger

The element the tooltip describes.

TooltipTrigger props
Props of TooltipTrigger
PropTypeDefaultWhat it does
childrenReactNodenone

Also accepts: Omit<BaseTooltipTriggerProps, "delay" | "closeDelay" | "children">

TooltipContent

The tooltip text.

TooltipContent props
Props of TooltipContent
PropTypeDefaultWhat it does
sideTooltipSide"top"
alignTooltipAlign"center"
childrenReactNodenone

Also accepts: Omit<BaseTooltipPopupProps, "children">

Toast

A short status message that closes itself after duration.

Toast props
Props of Toast
PropTypeDefaultWhat it does
open requiredbooleannone
onOpenChange required(open: boolean) => voidnone
durationnumber6000
toneNoticeTone"info"
titleReactNodenone
dismissLabelstring"Dismiss"

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "title" | "role">

React: Structure and identity

Disclosure, tabs and layout pieces with the keyboard behaviour people expect.

Accordion

Most are ready the same day.

Tabs

Three bookings today.

Separator

Above the rule

Below the rule

LeftRight

Card and Badge

Full service

Ready the same day.

Most booked

Safety check

Twenty minutes, while you wait.

Container, Stack, Heading

A stack with a small gap

Stacks space their children evenly.

VisuallyHidden

Avatar and AvatarGroup

Accordion

A set of disclosure sections, one or many open.

Accordion props
Props of Accordion
PropTypeDefaultWhat it does
valueAccordionValue[]noneOpen item values (controlled).
defaultValueAccordionValue[]noneInitially open item values (uncontrolled).
onValueChange(value: AccordionValue[]) => voidnone
multiplebooleanfalseAllow more than one item open at once. Defaults to false (one at a time).
disabledbooleanfalse

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "defaultValue" | "onChange" | "dir">

AccordionItem

One section.

AccordionItem props
Props of AccordionItem
PropTypeDefaultWhat it does
value requiredAccordionValuenone
disabledbooleannone

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "dir">

AccordionTrigger

Its heading button. headingLevel keeps the outline right.

AccordionTrigger props
Props of AccordionTrigger
PropTypeDefaultWhat it does
headingLevelAccordionHeadingLevel3Heading level wrapping the trigger, so the outline stays correct. Defaults to 3.
children requiredReactNodenone

Also accepts: Omit<HTMLAttributes<HTMLButtonElement>, "dir">

AccordionPanel

Its content.

AccordionPanel props

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "dir">

Tabs

Tabs with automatic or manual activation.

Tabs props
Props of Tabs
PropTypeDefaultWhat it does
valueTabsValuenone
defaultValueTabsValuenone
onValueChange(value: TabsValue) => voidnone
activationTabsActivation"automatic"
orientationTabsOrientation"horizontal"

Also accepts: HTMLAttributes<HTMLDivElement>

TabsList

The row of tabs. Give it an aria-label.

TabsList props

Also accepts: HTMLAttributes<HTMLDivElement>

TabsTab

One tab.

TabsTab props
Props of TabsTab
PropTypeDefaultWhat it does
value requiredTabsValuenone

Also accepts: ButtonHTMLAttributes<HTMLButtonElement>

TabsPanel

The panel for a tab value.

TabsPanel props
Props of TabsPanel
PropTypeDefaultWhat it does
value requiredTabsValuenone
keepMountedbooleannone

Also accepts: HTMLAttributes<HTMLDivElement>

Separator

A rule, horizontal or vertical, real or decorative.

Separator props
Props of Separator
PropTypeDefaultWhat it does
orientationSeparatorOrientation"horizontal"
decorativebooleanfalsePurely visual rule: hidden from assistive technology. Defaults to false (a real separator).

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "dir">

Card

A surface for grouped content. elevated adds a shadow.

Card props
Props of Card
PropTypeDefaultWhat it does
elevatedbooleanfalse

Also accepts: HTMLAttributes<HTMLDivElement>

Badge

A small label. Accepts span attributes.

Container

A centred column. Accepts div attributes.

Stack

Vertical spacing between children.

Stack props
Props of Stack
PropTypeDefaultWhat it does
gap"sm" | "md" | "lg" | "xl""md"
align"start" | "center" | "end" | "stretch""stretch"

Also accepts: HTMLAttributes<HTMLDivElement>

Heading

A heading with rank (as) and size set separately.

Heading props
Props of Heading
PropTypeDefaultWhat it does
as"h1" | "h2" | "h3" | "h4""h2"
size"sm" | "md" | "lg" | "xl""md"

Also accepts: HTMLAttributes<HTMLHeadingElement>

VisuallyHidden

Text for screen readers only. Accepts span attributes.

Avatar

A photo or initials, with the name as its label.

Avatar props
Props of Avatar
PropTypeDefaultWhat it does
name requiredstringnonePerson or organisation name. Used for the accessible label and the initials fallback.
srcstringnone
sizeAvatarSize"md"
decorativebooleanfalseSet when the avatar sits next to the visible name, so it is not announced twice.

Also accepts: Omit<HTMLAttributes<HTMLSpanElement>, "children" | "dir">

AvatarGroup

Overlapping avatars with one label for the group.

AvatarGroup props
Props of AvatarGroup
PropTypeDefaultWhat it does
label requiredstringnoneAccessible label for the group, for example "Workspace members".

Also accepts: HTMLAttributes<HTMLDivElement>

React: Feedback

Status, progress and asking for feedback. Spinners stop spinning under reduced motion.

Notice

Information

Opening hours change on Monday

We open at 9am from next week.
Success

Booking confirmed

Warning

Parts on order

Your wheel arrives Friday.

Meter

Slots booked today
6 of 8
Storage used
92%

Loading

FeedbackPrompt

Was this page useful?

How was your service?

PoorGreat

Notice

An inline message in four tones, optionally dismissible.

Notice props
Props of Notice
PropTypeDefaultWhat it does
toneNoticeTonenone
title requiredReactNodenone
childrenReactNodenone
actionsReactNodenone
dismissLabelstringnone
headingLevel1 | 2 | 3 | 4 | 5 | 6none
dismissible requiredtrue | falsenone
onDismiss required() => void | undefinednone

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "title" | "role">

Meter

A measured value in a range, with its accessible value text.

Meter props
Props of Meter
PropTypeDefaultWhat it does
label requiredReactNodenone
ariaLabelstringnoneRequired when the visible label is rich content rather than a string or number.
value requirednumbernone
minnumber0
maxnumber100
ariaValueText requiredstringnoneHuman-readable accessible value, such as “3 of 5 seats used”.
formattedValueReactNodenoneVisible value. Defaults to a deterministic percentage.
toneMeterTone"neutral"

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "aria-label" | "aria-labelledby" | "children" | "role">

Spinner

Indeterminate loading with a label.

Spinner props
Props of Spinner
PropTypeDefaultWhat it does
label requiredstringnone
sizeSpinnerSize"md"

Also accepts: HTMLAttributes<HTMLDivElement>

Skeleton

A placeholder shape while content loads.

Skeleton props
Props of Skeleton
PropTypeDefaultWhat it does
widthstring | numbernone
heightstring | numbernone
borderRadiusstring | numbernone
shimmerbooleanfalse

Also accepts: HTMLAttributes<HTMLDivElement>

Progress

Determinate progress.

Progress props
Props of Progress
PropTypeDefaultWhat it does
valuenumbernone
minnumber0
maxnumber100
ariaValueTextstringnone

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "role" | "aria-valuenow" | "aria-valuetext">

FeedbackPrompt

Yes or no, a 1 to 5 rating, or a 0 to 10 score, with an optional comment.

FeedbackPrompt props
Props of FeedbackPrompt
PropTypeDefaultWhat it does
question requiredReactNodenone
headingLevelFeedbackPromptHeadingLevelnone
positiveLabelstringnone
negativeLabelstringnone
submitLabelstringnone
commentbooleannone
commentLabelstringnone
submittedbooleannone
submittedLabelReactNodenone
scaleLabelsFeedbackPromptScaleLabelsnone
announcementTemplatestringnone
outOfLabelstringnone
mode required"binary" | "csat" | "nps"none
valueboolean | null | number | null | number | nullnone
onValueChange(value: boolean) => void | (value: number) => void | (value: number) => voidnone
onSubmit(submission: FeedbackPromptSubmission<boolean>) => void | (submission: FeedbackPromptSubmission<number>) => void | (submission: FeedbackPromptSubmission<number>) => voidnone

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "onSubmit">

React: Screen parts

Pieces for product screens.

PageHeader

Bookings

11 this week

Every booking, newest first.

EmptyState

No bookings yet

New bookings show up here.

No matches

Try a different name or date.

CodeBlock

Embed codeHTML
<script src="/booking.js" defer></script>

PageHeader

A screen title with meta, description, actions and tabs in a fixed order.

PageHeader props
Props of PageHeader
PropTypeDefaultWhat it does
title requiredReactNodenoneVisible page title. Rendered as the page heading.
descriptionReactNode | undefinednoneOptional one-line description under the title.
contextReactNode | undefinednoneBreadcrumb, back link or switcher rendered above the title.
metaReactNode | undefinednoneShort meta beside the title, for example a record count.
primaryActionReactNode | undefinednoneThe single primary action, placed last on the right.
secondaryActionsReactNode | undefinednoneGrouped secondary actions, placed before the primary action.
overflowReactNode | undefinednoneOverflow menu for everything else, placed between secondary and primary.
tabsReactNode | undefinednoneTabs or a sub-navigation row rendered as the last row of the header.
headingLevel1 | 2 | undefined1Heading level. Pages use 1; nested surfaces such as panels use 2.
actionsLabelstring | undefined"Page actions"Accessible name for the action group.

Also accepts: Omit<HTMLAttributes<HTMLElement>, "title">

EmptyState

What to show when there is nothing yet, no results, an error or no access.

EmptyState props
Props of EmptyState
PropTypeDefaultWhat it does
title requiredReactNodenoneWhat the user is looking at, in plain words.
descriptionReactNode | undefinednoneWhat happened and what to do next.
actionReactNode | undefinednoneThe one next action, usually a Button or link.
secondaryActionReactNode | undefinednoneA quieter alternative, for example "Learn more".
iconReactNode | null | undefinednoneReplaces the default tone icon. Pass null to hide the icon.
toneEmptyStateTone | undefined"empty"Chooses the default icon and how the state is announced.
sizeEmptyStateSize | undefined"page""page" centres the state in a large area; "inline" fits inside cards and tables.
headingLevel2 | 3 | 4 | undefined2

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "title">

CodeBlock

Code with a copy button that reports success or failure.

CodeBlock props
Props of CodeBlock
PropTypeDefaultWhat it does
code requiredstringnoneThe exact text that is shown and copied.
titlestring | undefinednoneVisible heading for the block, for example "Embed code".
languagestring | undefinednoneShort language label, for example "HTML".
wrapboolean | undefinedfalseWrap long lines instead of scrolling sideways.
copyLabelstring | undefined"Copy"
copiedLabelstring | undefined"Copied"
copyFailedLabelstring | undefined"Copy failed. Select the code and copy it manually."
onCopy((result: CodeBlockCopyResult) => void) | undefinednoneCalled after each copy attempt.
resetAfterMsnumber | undefined2000How long the copied confirmation stays, in milliseconds.

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "children" | "onCopy">

React: Experimental

On their own subpaths and may change before they are promoted to the stable root.

TextButton

Your booking is saved.

HandwrittenAction

Book a service

FloatingField

That postcode looks incomplete.

ActionList

Today

  • Full serviceThursday 10am
  • Wheel trueFriday 2pm

RangeSlider

Price range
Minimum
£40
Maximum
£120

MilestoneSelector

When do you need it?

FileDropzone

Photos of the bikePNG or JPG. Nothing is uploaded in this demo.

TextButton

A button presented as inline text. From /experimental/text-button.

TextButton props
Props of TextButton
PropTypeDefaultWhat it does
emphasis"accent" | "neutral""accent"Semantic emphasis for the revealed action surface.

Also accepts: ButtonHTMLAttributes<HTMLButtonElement>

StatusPillAction

A status note on a link or button you own. From /experimental/annotated-action. Not drawn here: its pill floats over the action, which the AI-look rules flag (AP-COMP-03), so use it sparingly.

StatusPillAction props
Props of StatusPillAction
PropTypeDefaultWhat it does
children requiredReactNodenone
status requiredReactNodenone
statusAriaHiddenbooleantrueDecorative by default. Put equivalent status text in the action's accessible name.
activebooleanfalseShows a restrained activity marker without changing the accessible label.
emphasis"accent" | "neutral""accent"

Also accepts: HTMLAttributes<HTMLSpanElement>

HandwrittenAction

A short note beside a link or button you own.

HandwrittenAction props
Props of HandwrittenAction
PropTypeDefaultWhat it does
children requiredReactNodenone
note requiredReactNodenone
noteAriaHiddenbooleantrueDecorative by default. Set false when the note adds information absent from the action label.
emphasis"accent" | "neutral""accent"
noteStyle"handwritten" | "plain""handwritten"
tone"light" | "dark""light"

Also accepts: HTMLAttributes<HTMLSpanElement>

FloatingField

An input whose label moves above the text. From /experimental/polish.

FloatingField props
Props of FloatingField
PropTypeDefaultWhat it does
label requiredstringnone
hintstringnone
errorstringnone

Also accepts: Omit<InputHTMLAttributes<HTMLInputElement>, "placeholder">

ActionList

A removable list of items with optional tags.

ActionList props
Props of ActionList
PropTypeDefaultWhat it does
title requiredstringnone
items requiredreadonly ActionListItem[]none
tagsreadonly ActionListTag[][]
clearLabelstring"Clear all"
emptyMessagestring"No recent items."
onClear() => voidnone
onRemoveItem(id: string) => voidnone
onRemoveTag(id: string) => voidnone

Also accepts: HTMLAttributes<HTMLElement>

RangeSlider

A two-handle range with an optional histogram.

RangeSlider props
Props of RangeSlider
PropTypeDefaultWhat it does
label requiredstringnone
min requirednumbernone
max requirednumbernone
stepnumber1
value requiredreadonly [number, number]none
histogramreadonly number[][]
formatValue(value: number) => stringString
onValueChange required(value: [number, number]) => voidnone

Also accepts: Omit<HTMLAttributes<HTMLDivElement>, "onChange">

MilestoneSelector

A single choice drawn as a row of milestones.

MilestoneSelector props
Props of MilestoneSelector
PropTypeDefaultWhat it does
legend requiredstringnone
options requiredreadonly MilestoneOption[]none
valuestringnone
onValueChange required(value: string) => voidnone

Also accepts: Omit<HTMLAttributes<HTMLFieldSetElement>, "onChange">

FileDropzone

Drop or choose files, with preview and status.

FileDropzone props
Props of FileDropzone
PropTypeDefaultWhat it does
title requiredstringnone
description requiredstringnone
acceptstringnone
multiplebooleanfalse
previewFilePreviewnone
status"idle" | "uploading" | "complete" | "error""idle"
statusMessagestringnone
onFiles required(files: FileList) => voidnone
onRemove() => voidnone

Also accepts: HTMLAttributes<HTMLDivElement>