@molecule/app-ui-react
v1.3.1
Published
React UI components for molecule.dev
Readme
@molecule/app-ui-react
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
React UI components for molecule.dev.
Provides React implementations of the @molecule/app-ui component
interfaces using the UIClassMap abstraction from @molecule/app-ui.
Quick Start
import { setClassMap } from '@molecule/app-ui'
import { classMap } from '@molecule/app-ui-tailwind'
import { Button, Modal, Icon, EmptyState } from '@molecule/app-ui-react'
import { useState } from 'react'
// Once at startup, before first render — components throw without it:
setClassMap(classMap)
function ConfirmDelete({ onConfirm }: { onConfirm: () => void }) {
const [open, setOpen] = useState(false)
return (
<>
<Button color="error" onClick={() => setOpen(true)}>
<Icon name="trash" size={16} /> Delete
</Button>
<Modal
open={open}
onClose={() => setOpen(false)}
title="Delete item?"
data-mol-id="confirm-delete"
>
<EmptyState title="This cannot be undone" />
<Button color="error" onClick={onConfirm}>
Confirm
</Button>
</Modal>
</>
)
}Type
framework
Installation
npm install @molecule/app-ui-react @molecule/app-i18n @molecule/app-icons @molecule/app-react @molecule/app-ui react react-dom react-router
npm install -D @types/react @types/react-domAPI
Interfaces
AccordionItem
A single item in an Accordion component.
interface AccordionItem<T = string> {
/**
* Item value/id.
*/
value: T
/**
* Item header/trigger.
*/
header: Children
/**
* Item content.
*/
content: Children
/**
* Whether the item is disabled.
*/
disabled?: boolean
}AccordionProps
Props for the Accordion component.
interface AccordionProps<T = string> extends BaseProps {
/**
* Accordion items.
*/
items: AccordionItem<T>[]
/**
* Expanded item(s).
*/
value?: T | T[]
/**
* Default expanded item(s).
*/
defaultValue?: T | T[]
/**
* Change handler.
*/
onChange?: (value: T | T[]) => void
/**
* Whether multiple items can be expanded.
*/
multiple?: boolean
/**
* Whether items can be collapsed.
*/
collapsible?: boolean
}AlertProps
Props for the Alert component.
interface AlertProps extends HTMLElementProps {
/**
* Alert content.
*/
children?: Children
/**
* Alert title.
*/
title?: string
/**
* Alert status/type.
*/
status?: ColorVariant
/**
* Alert variant.
*/
variant?: 'solid' | 'subtle' | 'outline' | 'left-accent'
/**
* Whether the alert is dismissible.
*/
dismissible?: boolean
/**
* Called when dismissed.
*/
onDismiss?: () => void
/**
* Icon to display.
*/
icon?: Children
/**
* Accessible label for the dismiss button.
* @default 'Dismiss'
*/
dismissLabel?: string
}AuthGuardProps
Props for {@link AuthGuard}.
All props are optional — the default behavior (loading tag → redirect
to /login → <Outlet />) matches the bare-bones guard apps were
shipping locally. The props let apps customize per-call without
forking the component.
interface AuthGuardProps {
/**
* Element rendered while `useAuth().state.initialized` is `false`.
* Overrides the default `<div data-mol-id="auth-guard-loading">…</div>`
* loading tag — pass a full-page spinner or any other UI you want
* during the auth bootstrap window.
*/
loadingFallback?: ReactNode
/**
* i18n key used for the default loading-tag text. Defaults to
* `'common.loading'`. Ignored when `loadingFallback` is set.
*/
loadingKey?: string
/**
* Fallback text if the i18n key is missing. Defaults to `'Loading...'`
* (the project-canonical ASCII glyph — Phase C of the locale
* canonicalization plan). Ignored when `loadingFallback` is set.
*/
loadingDefault?: string
/**
* Path to redirect to when the user is not authenticated. Defaults to
* `'/login'`. The current `useLocation()` is preserved as `state.from`
* for post-login restoration.
*/
loginPath?: string
/**
* Callback invoked when `isAuthenticated` transitions to `true` (or is
* already `true` on first render). Useful for one-shot per-app
* bootstrap effects (e.g. seeding fixture data). The caller is
* responsible for idempotency if the auth state can flip back and
* forth — this fires on every transition.
*/
onAuthenticated?: () => void
/**
* Children to render when authenticated. Defaults to `<Outlet />`,
* which is the React Router pattern this guard is designed for.
*/
children?: ReactNode
}AvatarProps
Props for the Avatar component.
interface AvatarProps extends HTMLElementProps {
/**
* Image source URL.
*/
src?: string
/**
* Alt text for the image.
*/
alt?: string
/**
* Name for fallback initials.
*/
name?: string
/**
* Avatar size.
*/
size?: Size | number
/**
* Whether the avatar is rounded.
*/
rounded?: boolean
/**
* Fallback element when no image.
*/
fallback?: Children
}BadgeProps
Props for the Badge component (status labels, counts, tags).
interface BadgeProps extends HTMLElementProps {
/**
* Badge content.
*/
children?: Children
/**
* Badge color.
*/
color?: ColorVariant
/**
* Badge variant.
*/
variant?: 'solid' | 'outline' | 'subtle'
/**
* Badge size.
*/
size?: Size
/**
* Whether the badge is rounded.
*/
rounded?: boolean
}BaseProps
Base props shared by all components.
interface BaseProps {
/**
* Additional CSS class name(s).
*/
className?: string
/**
* Inline styles.
*/
style?: CSSProperties
/**
* Test ID for automated testing.
*/
testId?: string
/**
* Automation ID for AI agents and E2E tests. Maps to the `data-mol-id`
* HTML attribute. Use `molId()` from `./automation.js` to generate
* semantic IDs. (Tooling only — screen readers do not expose `data-*`
* attributes; accessible names come from labels/`aria-*`.)
*/
automationId?: string
/**
* Whether the component is disabled.
*/
disabled?: boolean
}ButtonElementProps
Base props for button elements.
interface ButtonElementProps extends HTMLElementProps {
type?: 'button' | 'submit' | 'reset'
name?: string
value?: string
form?: string
}ButtonProps
Props for the Button component.
interface ButtonProps extends ButtonElementProps {
/**
* Button content.
*/
children?: Children
/**
* Visual variant.
*/
variant?: ButtonVariant
/**
* Color scheme.
*/
color?: ColorVariant
/**
* Button size.
*/
size?: ButtonSize
/**
* Whether the button is in a loading state.
*/
loading?: boolean
/**
* Loading text to display.
*/
loadingText?: string
/**
* Whether the button takes full width.
*/
fullWidth?: boolean
/**
* Icon to display before the label.
*/
leftIcon?: Children
/**
* Icon to display after the label.
*/
rightIcon?: Children
}CardProps
Props for the Card container component (elevated, outlined, or filled surface).
interface CardProps extends HTMLElementProps {
/**
* Card content.
*/
children?: Children
/**
* Card variant.
*/
variant?: 'elevated' | 'outlined' | 'filled'
/**
* Whether the card is interactive (clickable).
*/
interactive?: boolean
/**
* Padding size.
*/
padding?: Size | 'none'
}CheckboxProps
Props for the Checkbox component.
interface CheckboxProps extends InputElementProps {
/**
* Checkbox label.
*/
label?: Children
/**
* Whether the checkbox is checked.
*/
checked?: boolean
/**
* Whether the checkbox is in an indeterminate state.
*/
indeterminate?: boolean
/**
* Checkbox size.
*/
size?: Size
/**
* Error message.
*/
error?: string
}ConfirmButtonProps
Props for {@link ConfirmButton}.
interface ConfirmButtonProps extends Omit<
ButtonProps,
'onClick' | 'children' | 'onConfirm' | keyof React.DOMAttributes<HTMLButtonElement>
> {
/**
* Fired ONLY on the confirming (second) click — i.e. when the action
* actually commits. Errors should be handled by the caller (render an
* inline banner); while the returned promise is pending the button stays
* in its confirming state and ignores further clicks.
*/
onConfirm: () => void | Promise<void>
/**
* Visible label in the idle (armed-to-be-clicked) state.
*/
label: React.ReactNode
/**
* Visible label in the armed state — the "click again to confirm" step.
* Defaults to a localized "Confirm?" via the i18n bond.
*/
confirmLabel?: React.ReactNode
/**
* Visible label while {@link onConfirm} is pending. Defaults to a
* localized "Working…".
*/
pendingLabel?: React.ReactNode
/**
* Seconds before the armed state auto-disarms back to idle. Low-stakes
* actions tolerate a long window; destructive ones should keep it short.
* `0` disables auto-disarm (not recommended — a stray click then leaves
* the button armed forever).
*/
disarmSeconds?: number
/**
* Disable the control entirely (idle and confirming states).
*/
disabled?: boolean
/**
* data-mol-id for the button (all states share one element).
*/
testId?: string
}ConfirmDialogProps
Props for {@link ConfirmDialog}.
interface ConfirmDialogProps {
/** Whether the dialog is open. */
open: boolean
/** Called when the dialog should close (escape, backdrop, cancel). */
onClose: () => void
/** Title. */
title: ReactNode
/** Body / warning text. */
description: ReactNode
/** Confirm-button label (e.g. "Delete"). */
confirmLabel?: ReactNode
/** Cancel-button label. */
cancelLabel?: ReactNode
/** Called when the user confirms. */
onConfirm: () => void | Promise<void>
/** Is the confirm action destructive? Defaults to true. */
destructive?: boolean
/** Extra body content between description and footer. */
children?: ReactNode
/** Disables both buttons. Set it yourself while your `onConfirm` promise is pending — the dialog does not track it and does not auto-close. */
loading?: boolean
}ContainerProps
Props for the Container layout component.
interface ContainerProps extends HTMLElementProps {
/**
* Container content.
*/
children?: Children
/**
* Maximum width.
*/
maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | string
/**
* Whether to center the container.
*/
centered?: boolean
/**
* Horizontal padding.
*/
paddingX?: Size | string
}CSSProperties
Framework-agnostic CSS properties. Mirrors React.CSSProperties but without React dependency.
interface CSSProperties {
[key: string]: string | number | undefined
}FlexProps
Flex container props.
interface FlexProps extends HTMLElementProps {
/**
* Flex content.
*/
children?: Children
/**
* Flex direction.
*/
direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
/**
* Justify content.
*/
justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'
/**
* Align items.
*/
align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
/**
* Flex wrap.
*/
wrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
/**
* Gap between items.
*/
gap?: Size | string | number
}FormElementProps
Base props for form elements.
interface FormElementProps extends HTMLElementProps {
action?: string
method?: 'get' | 'post'
encType?: string
target?: string
noValidate?: boolean
autoComplete?: 'on' | 'off'
onSubmit?: FormEventHandler
onReset?: FormEventHandler
}FormFieldProps
Form field wrapper props.
interface FormFieldProps extends HTMLElementProps {
/**
* Field content.
*/
children?: Children
/**
* Field label.
*/
label?: string
/**
* Field name.
*/
name?: string
/**
* Error message.
*/
error?: string
/**
* Hint/help text.
*/
hint?: string
/**
* Whether the field is required.
*/
required?: boolean
}FormProps
Props for the Form component (wraps inputs with submission handling and validation).
interface FormProps extends FormElementProps {
/**
* Form content.
*/
children?: Children
/**
* Submit handler with form data.
*/
onFormSubmit?: (data: Record<string, unknown>) => void | Promise<void>
/**
* Whether the form is submitting.
*/
submitting?: boolean
}GridProps
Grid container props.
interface GridProps extends HTMLElementProps {
/**
* Grid content.
*/
children?: Children
/**
* Number of columns.
*/
columns?: number | string
/**
* Number of rows.
*/
rows?: number | string
/**
* Gap between items.
*/
gap?: Size | string | number
/**
* Column gap.
*/
columnGap?: Size | string | number
/**
* Row gap.
*/
rowGap?: Size | string | number
}HTMLElementProps
Base props for HTML elements. Framework bindings should extend this with framework-specific attributes.
interface HTMLElementProps extends BaseProps {
id?: string
title?: string
tabIndex?: number
role?: string
'aria-label'?: string
'aria-labelledby'?: string
'aria-describedby'?: string
'aria-hidden'?: boolean
'aria-disabled'?: boolean
'aria-expanded'?: boolean
'aria-selected'?: boolean
'aria-checked'?: boolean | 'mixed'
'aria-pressed'?: boolean | 'mixed'
'aria-invalid'?: boolean
'aria-required'?: boolean
'aria-readonly'?: boolean
'aria-busy'?: boolean
'aria-live'?: 'off' | 'polite' | 'assertive'
onClick?: MouseEventHandler
onDoubleClick?: MouseEventHandler
onMouseEnter?: MouseEventHandler
onMouseLeave?: MouseEventHandler
onFocus?: FocusEventHandler
onBlur?: FocusEventHandler
onKeyDown?: KeyboardEventHandler
onKeyUp?: KeyboardEventHandler
onKeyPress?: KeyboardEventHandler
}IconProps
Props for {@link Icon}.
Extends SVGProps<SVGSVGElement> so callers can pass any SVG / HTML
attribute the underlying <svg> accepts, including data-mol-id,
aria-*, role, event handlers, style, etc. — without the
component needing to enumerate them.
interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'width' | 'height' | 'viewBox' | 'fill'> {
/**
* Name of the glyph to look up in the bonded icon set. Typed as
* {@link IconName} so a typo fails the type-check instead of throwing at
* render time; sets with extra glyphs augment `CustomIconNames` in
* `@molecule/app-icons` to widen it.
*/
name: IconName
/** Width and height of the rendered SVG in pixels. Defaults to 20. */
size?: number
/** Class name forwarded to the root `<svg>`. */
className?: string
}InputElementProps
Base props for input elements.
interface InputElementProps extends HTMLElementProps {
name?: string
value?: string | number | readonly string[]
defaultValue?: string | number | readonly string[]
placeholder?: string
required?: boolean
readOnly?: boolean
autoFocus?: boolean
autoComplete?: string
maxLength?: number
minLength?: number
pattern?: string
onChange?: ChangeEventHandler
onInput?: FormEventHandler
}InputProps
Props for the Input component (text field, email, password, etc.).
interface InputProps extends InputElementProps {
/**
* Input type.
*/
type?: InputType
/**
* Input size.
*/
size?: Size
/**
* Horizontal text alignment inside the input (see
* {@link InputClassOptions.align}). Defaults to the bond's own style.
*/
align?: 'left' | 'center'
/**
* Label text.
*/
label?: string
/**
* Error message.
*/
error?: string
/**
* Hint/help text.
*/
hint?: string
/**
* Element to display on the left.
*/
leftElement?: Children
/**
* Element to display on the right.
*/
rightElement?: Children
/**
* Whether to show a clear button.
*/
clearable?: boolean
/**
* Called when the clear button is clicked.
*/
onClear?: () => void
/**
* Accessible label for the clear button.
* @default 'Clear'
*/
clearLabel?: string
}LanguagePickerProps
Props for {@link LanguagePicker}.
Extends standard <button> attributes so callers can pass any extra
data-*, aria-*, event handler, or style prop without forking the
component. The named props let apps customize the trigger label, icon,
size, and modal heading without spreading attribute concerns.
interface LanguagePickerProps extends Omit<
ButtonHTMLAttributes<HTMLButtonElement>,
'aria-label' | 'onClick' | 'type' | 'children'
> {
/** i18n key for the trigger button label / aria-label. Defaults to `'footer.language'`. */
labelKey?: string
/** Fallback label if the i18n key is missing. Defaults to `'Language'`. */
labelDefault?: string
/** i18n key for the modal title. Defaults to `'languagePicker.modalTitle'`. */
modalTitleKey?: string
/** Fallback modal title if the i18n key is missing. Defaults to `'Choose language'`. */
modalTitleDefault?: string
/** Icon glyph to render before the current locale name. Defaults to `'globe'`. */
icon?: IconName
/** Pixel size for the rendered icon. Defaults to `16`. */
iconSize?: number
/**
* What to render inside the trigger button.
*
* - `'name'` — globe icon + current locale's native name (e.g. `🌐 English`).
* This is the default; matches the molecule-dev footer pattern.
* - `'code'` — globe icon + lowercase locale code (e.g. `🌐 en`). Useful in
* tight chrome where the long native name (e.g. "Bahasa Indonesia") would wrap.
* - `'icon'` — globe icon only. Useful in icon-bar headers.
*/
display?: 'name' | 'code' | 'icon'
/** Optional className appended to the trigger button. */
className?: string
/** Optional render override: receives `{ open }` and replaces the default trigger. */
renderTrigger?: (open: () => void) => ReactNode
}LoadErrorBannerProps
Props for {@link LoadErrorBanner}. Rest props are forwarded to the root
<div>, so they are typed as its attributes.
interface LoadErrorBannerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
/** The primary error line (e.g. the localized "Could not load X."). */
message: React.ReactNode
/** Secondary line under the message (status code, hint). */
detail?: React.ReactNode
/**
* Called when Retry is clicked. Return the promise; while pending, the
* button is disabled and shows "Retrying…". Omit for a display-only
* banner.
*/
onRetry?: () => void | Promise<void>
/** Retry-button label. Falls back to a localized "Retry". */
retryLabel?: React.ReactNode
/** `data-mol-id` for the retry button (default `load-error-retry`). */
retryMolId?: string
/** Extra content between message and retry row (e.g. an error code). */
children?: React.ReactNode
}ModalProps
Props for the Modal/Dialog component.
interface ModalProps extends HTMLElementProps {
/**
* Whether the modal is open.
*/
open: boolean
/**
* Called when the modal should close.
*/
onClose: () => void
/**
* Modal title.
*/
title?: string
/**
* Modal content.
*/
children?: Children
/**
* Modal size.
*/
size?: ModalSize
/**
* Whether to show a close button.
*/
showCloseButton?: boolean
/**
* Whether clicking the overlay closes the modal.
*/
closeOnOverlayClick?: boolean
/**
* Whether pressing Escape closes the modal.
*/
closeOnEscape?: boolean
/**
* Footer content (typically action buttons).
*/
footer?: Children
/**
* Whether the modal is centered vertically.
*/
centered?: boolean
/**
* Whether to prevent body scroll when open.
*/
preventScroll?: boolean
/**
* Accessible label for the close button.
* @default 'Close'
*/
closeLabel?: string
}PaginationProps
Props for the Pagination component (page navigation with current page, total, page size, and change callbacks).
interface PaginationProps extends BaseProps {
/**
* Current page (1-indexed).
*/
page: number
/**
* Total number of pages.
*/
totalPages: number
/**
* Page change handler.
*/
onChange: (page: number) => void
/**
* Number of sibling pages to show.
*/
siblings?: number
/**
* Number of boundary pages to show.
*/
boundaries?: number
/**
* Pagination size.
*/
size?: Size
/**
* Whether to show first/last buttons.
*/
showFirstLast?: boolean
/**
* Whether to show previous/next buttons.
*/
showPrevNext?: boolean
/**
* Accessible labels for pagination controls.
*/
labels?: {
nav?: string
first?: string
previous?: string
next?: string
last?: string
goToPage?: (page: number) => string
}
}PanelCloseProviderProps
Props for {@link PanelCloseProvider}.
interface PanelCloseProviderProps {
/** Callback that dismisses the enclosing drawer/modal. */
close: () => void
/** Panel content that may call {@link usePanelClose}. */
children: ReactNode
}ProgressProps
Props for the Progress component.
interface ProgressProps extends BaseProps {
/**
* Progress value (0-100).
*/
value: number
/**
* Maximum value.
*/
max?: number
/**
* Progress size.
*/
size?: Size
/**
* Progress color.
*/
color?: ColorVariant
/**
* Whether to show the value label.
*/
showValue?: boolean
/**
* Accessible label.
*/
label?: string
/**
* Whether the progress is indeterminate.
*/
indeterminate?: boolean
}PromptDialogProps
Props for {@link PromptDialog}.
interface PromptDialogProps {
/** Whether the dialog is open. */
open: boolean
/** Called when the dialog should close (escape, backdrop, cancel, or a fulfilled {@link PromptDialogProps.onSubmit}). */
onClose: () => void
/** Dialog heading. */
title: React.ReactNode
/** Explanatory line under the title. */
description?: React.ReactNode
/** Input placeholder. */
placeholder?: string
/** Value the input starts from every time the dialog opens. */
initialValue?: string
/**
* Called with the entered value on confirm. Resolve to close the dialog;
* reject or throw to keep it open (show the error via {@link PromptDialogProps.children}).
*/
onSubmit: (value: string) => void | Promise<void>
/** Confirm-button label. Falls back to a localized "Confirm". */
confirmLabel?: React.ReactNode
/** Cancel-button label. Falls back to a localized "Cancel". */
cancelLabel?: React.ReactNode
/** Render the confirm button in the error color (e.g. an irreversible reset). */
destructive?: boolean
/** `data-mol-id` for the text input. */
inputMolId?: string
/** `data-mol-id` for the confirm button. */
confirmMolId?: string
/** `data-mol-id` for the cancel button. */
cancelMolId?: string
/** Extra body content under the input (error banners, hints). */
children?: React.ReactNode
}RadioGroupProps
Props for the RadioGroup component.
interface RadioGroupProps<T = string> extends BaseProps {
/**
* Radio options.
*/
options: RadioOption<T>[]
/**
* Current value.
*/
value?: T
/**
* Change handler.
*/
onChange?: (value: T) => void
/**
* Radio size.
*/
size?: Size
/**
* Group label.
*/
label?: string
/**
* Shared `name` attribute for the group's radio inputs (used for native
* form submission). When omitted, a unique per-instance name is generated
* so separate groups never merge — the visible `label` is deliberately
* NOT used as the name, because two groups with the same label (e.g. two
* "Size" pickers) would otherwise form ONE native radio group and
* deselect each other.
*/
name?: string
/**
* Layout direction.
*/
direction?: 'horizontal' | 'vertical'
/**
* Error message.
*/
error?: string
}RadioOption
A single option in a RadioGroup.
interface RadioOption<T = string> {
/**
* Option value.
*/
value: T
/**
* Display label.
*/
label: Children
/**
* Whether the option is disabled.
*/
disabled?: boolean
}ResponsiveAppShellContentProps
Props for the {@link ResponsiveAppShellContent} sub-component.
interface ResponsiveAppShellContentProps {
/** The routed page content — typically an `<Outlet />`. */
children: ReactNode
/** Extra classes on the `<main>`. */
className?: string
/** Inline styles on the `<main>` (rarely needed — layout is owned). */
style?: React.CSSProperties
/** `data-mol-id` override. Default: `'shell-content'`. */
dataMolId?: string
/** `data-testid` override. */
testId?: string
}ResponsiveAppShellDrawerProps
Props for the {@link ResponsiveAppShellDrawer} sub-component.
interface ResponsiveAppShellDrawerProps {
/**
* Nav content — the links, same as (or adapted from) the Sidebar's. Only
* mounted while the drawer is open on a below-breakpoint viewport.
*/
children: ReactNode
/**
* Header row content (typically the brand), rendered next to the close
* button.
*/
header?: ReactNode
/**
* Accessible name for the dialog and its `<nav>` landmark. Defaults to the
* `appShell.primaryNav` translation (English fallback `"Primary
* navigation"`).
*/
navLabel?: string
/** Below-nav content (user card, sign-out), after the `<nav>`. */
footer?: ReactNode
/** Whether the panel shows a close (X) button. Default: `true`. */
showCloseButton?: boolean
/** Extra classes on the dialog panel. */
className?: string
/** `data-mol-id` override for the panel. Default: `'shell-drawer'`. */
dataMolId?: string
/** `data-mol-id` override for the close button. Default: `'shell-drawer-close'`. */
closeDataMolId?: string
/** `data-testid` override for the panel. */
testId?: string
}ResponsiveAppShellProps
Props for the {@link ResponsiveAppShell} root.
interface ResponsiveAppShellProps {
/**
* The shell sub-components — `<ResponsiveAppShell.TopBar />`,
* `<ResponsiveAppShell.Sidebar />`, `<ResponsiveAppShell.Drawer />` and
* `<ResponsiveAppShell.Content />`.
*/
children: ReactNode
/**
* Sidebar (and drawer) width: `'sm'` (208px), `'md'` (240px, default),
* `'lg'` (256px) or an exact pixel number.
*/
sidebarWidth?: ShellSidebarWidth
/** Extra classes on the root flex-row container. */
className?: string
/**
* `data-mol-id` for the root container. Defaults to `'shell-root'`.
*/
dataMolId?: string
}ResponsiveAppShellSidebarProps
Props for the {@link ResponsiveAppShellSidebar} sub-component.
interface ResponsiveAppShellSidebarProps {
/**
* Nav content — the links (they land inside the sidebar's `<nav>` landmark;
* pass `aria-current="page"` from the active one yourself). Typically the
* SAME element variable the Drawer receives, so only the mounted
* breakpoint's copy ever instantiates.
*/
children: ReactNode
/**
* Accessible name for the sidebar's `<nav>` landmark. Defaults to the
* `appShell.primaryNav` translation (English fallback `"Primary
* navigation"`).
*/
navLabel?: string
/**
* Below-nav content (user card, quick action) — rendered after the `<nav>`
* in a bordered footer row, so it does not sit inside the nav landmark.
*/
footer?: ReactNode
/** Extra classes on the `<aside>`. */
className?: string
/** `data-mol-id` override. Default: `'shell-sidebar'`. */
dataMolId?: string
/** `data-testid` override. */
testId?: string
}ResponsiveAppShellTopBarProps
Props for the {@link ResponsiveAppShellTopBar} sub-component.
interface ResponsiveAppShellTopBarProps {
/**
* Brand/title node, rendered after the menu trigger — typically a
* `<Link to="/…">` with the app name or logo. The shell wraps it in a
* flex row; style the node itself.
*/
brand?: ReactNode
/** Trailing actions — user menu, theme toggle, search, etc. */
actions?: ReactNode
/**
* Render the top bar only below the breakpoint (mount-conditioned, not
* CSS-hidden — no dead DOM on desktop). For apps whose desktop shell has
* no top bar (e.g. the sidebar carries everything). Default: `false`
* (top bar on every breakpoint).
*/
mobileOnly?: boolean
/** Extra classes on the `<header>`. */
className?: string
/** `data-mol-id` override. Default: `'shell-topbar'`. */
dataMolId?: string
/** `data-testid` override. */
testId?: string
}SelectElementProps
Base props for select elements.
interface SelectElementProps extends HTMLElementProps {
name?: string
required?: boolean
autoFocus?: boolean
multiple?: boolean
onChange?: ChangeEventHandler
}SelectOption
A single option in a Select dropdown.
interface SelectOption<T = string> {
/**
* Option value.
*/
value: T
/**
* Display label.
*/
label: string
/**
* Whether the option is disabled.
*/
disabled?: boolean
/**
* Option group (for grouped selects).
*/
group?: string
}SelectProps
Props for the Select dropdown component (single or multi-select).
interface SelectProps<T = string> extends SelectElementProps {
/**
* Select options.
*/
options: SelectOption<T>[]
/**
* Current value.
*/
value?: T
/**
* Change handler (with typed value).
*/
onValueChange?: (value: T) => void
/**
* Select size.
*/
size?: Size
/**
* Label text.
*/
label?: string
/**
* Placeholder text.
*/
placeholder?: string
/**
* Error message.
*/
error?: string
/**
* Hint/help text.
*/
hint?: string
/**
* Whether to allow clearing the selection.
*/
clearable?: boolean
}SeparatorProps
Props for the Separator component.
interface SeparatorProps extends BaseProps {
/**
* Orientation of the separator.
*/
orientation?: 'horizontal' | 'vertical'
/**
* Decorative separators are purely visual.
*/
decorative?: boolean
}SidebarUserCardProps
Props for the {@link SidebarUserCard} component.
Extends standard <button> attributes so callers can pass extra
data-*, aria-*, style, or event handler props onto the trigger
button without forking. The named props below cover the common
customization points.
interface SidebarUserCardProps extends Omit<
ButtonHTMLAttributes<HTMLButtonElement>,
'aria-label' | 'onClick' | 'children'
> {
/**
* Panel content shown inside the drawer/modal (typically the app's
* `SettingsPanel`). It can dismiss the drawer by calling
* `usePanelClose()` — no `onClose` prop-threading required.
*/
children: ReactNode
/**
* Display name override. When omitted, falls back to
* `useAuth().user?.name`, then `email`, then a guest label.
*/
name?: string
/**
* Secondary line under the name (role, plan, status, etc.).
* Apps typically pass something like `t('sidebar.memberStatus', {}, { defaultValue: 'Premium Member' })`.
* When omitted and the auth user has an email, the email is shown instead.
*/
secondaryLine?: string
/** Optional avatar image URL — overrides `useAuth().user?.avatarUrl`. */
avatarUrl?: string
/** i18n key for the trigger button's aria-label. Default: `'sidebarUserCard.open'`. */
ariaLabelKey?: string
/** Fallback aria-label if the i18n key is missing. Default: `'Open account menu'`. */
ariaLabelDefault?: string
/**
* `data-mol-id` for the trigger button. Defaults to
* `'sidebar-user-card'`. Pass a different value (e.g. `'user-menu'`)
* to disambiguate or align with an app's existing e2e selectors.
*/
dataMolId?: string
}SkeletonProps
Props for the Skeleton loading placeholder component.
interface SkeletonProps extends BaseProps {
/**
* Skeleton width.
*/
width?: string | number
/**
* Skeleton height.
*/
height?: string | number
/**
* Whether the skeleton is circular.
*/
circle?: boolean
/**
* Border radius.
*/
borderRadius?: string | number
/**
* Animation type.
*/
animation?: 'pulse' | 'wave' | 'none'
}SpacerProps
Props for the Spacer layout component (adds whitespace between elements).
interface SpacerProps extends BaseProps {
/**
* Space size.
*/
size?: Size | string | number
/**
* Whether the spacer is horizontal.
*/
horizontal?: boolean
}SpinnerProps
Props for the Spinner/loading indicator component.
interface SpinnerProps extends BaseProps {
/**
* Spinner size.
*/
size?: Size
/**
* Spinner color.
*/
color?: ColorVariant | string
/**
* Loading label (for accessibility).
*/
label?: string
/**
* Spinner thickness.
*/
thickness?: number
}SwitchProps
Props for the Switch/Toggle component.
interface SwitchProps extends InputElementProps {
/**
* Switch label.
*/
label?: Children
/**
* Whether the switch is on.
*/
checked?: boolean
/**
* Switch size.
*/
size?: Size
/**
* Color when on.
*/
color?: ColorVariant
}TabItem
A single tab in a Tabs component.
interface TabItem<T = string> {
/**
* Tab value/id.
*/
value: T
/**
* Tab label.
*/
label: Children
/**
* Tab content.
*/
content?: Children
/**
* Whether the tab is disabled.
*/
disabled?: boolean
/**
* Icon to display.
*/
icon?: Children
}TableColumn
Table column definition.
interface TableColumn<T> {
/**
* Column key (data property).
*/
key: keyof T | string
/**
* Column header.
*/
header: Children
/**
* Custom cell renderer.
*/
render?: (value: unknown, row: T, index: number) => Children
/**
* Column width.
*/
width?: string | number
/**
* Whether the column is sortable.
*/
sortable?: boolean
/**
* Text alignment.
*/
align?: 'left' | 'center' | 'right'
}TableProps
Props for the Table component.
interface TableProps<T> extends HTMLElementProps {
/**
* Table data.
*/
data: T[]
/**
* Column definitions.
*/
columns: TableColumn<T>[]
/**
* Row key extractor.
*/
rowKey?: keyof T | ((row: T) => string | number)
/**
* Whether to show borders.
*/
bordered?: boolean
/**
* Whether rows are striped.
*/
striped?: boolean
/**
* Whether rows are hoverable.
*/
hoverable?: boolean
/**
* Table size.
*/
size?: Size
/**
* Empty state content.
*/
emptyContent?: Children
/**
* Loading state.
*/
loading?: boolean
/**
* Sort configuration.
*/
sort?: {
key: string
direction: 'asc' | 'desc'
}
/**
* Sort change handler.
*/
onSort?: (key: string, direction: 'asc' | 'desc') => void
/**
* Row click handler.
*/
onRowClick?: (row: T, index: number) => void
}TabsProps
Props for the Tabs component (switchable tabbed content panels).
interface TabsProps<T = string> extends BaseProps {
/**
* Tab items.
*/
items: TabItem<T>[]
/**
* Current active tab.
*/
value?: T
/**
* Default active tab.
*/
defaultValue?: T
/**
* Change handler.
*/
onChange?: (value: T) => void
/**
* Tab variant.
*/
variant?: 'line' | 'enclosed' | 'soft-rounded' | 'solid-rounded'
/**
* Tab size.
*/
size?: Size
/**
* Whether tabs are fitted (take full width).
*/
fitted?: boolean
}TextareaElementProps
Base props for textarea elements.
interface TextareaElementProps extends HTMLElementProps {
name?: string
value?: string
defaultValue?: string
placeholder?: string
required?: boolean
readOnly?: boolean
autoFocus?: boolean
rows?: number
cols?: number
maxLength?: number
minLength?: number
wrap?: 'hard' | 'soft' | 'off'
onChange?: ChangeEventHandler
onInput?: FormEventHandler
}TextareaProps
Props for the Textarea component.
interface TextareaProps extends TextareaElementProps {
/**
* Text size tier (see {@link TextareaClassOptions.size}) — pass the same
* `size` as a neighboring Input for identical font sizes.
*/
size?: Size
/**
* Label text.
*/
label?: string
/**
* Error message.
*/
error?: string
/**
* Hint/help text.
*/
hint?: string
/**
* Whether the textarea auto-resizes.
*/
autoResize?: boolean
/**
* Minimum number of rows.
*/
minRows?: number
/**
* Maximum number of rows.
*/
maxRows?: number
}ThemeToggleProps
Props for {@link ThemeToggle}.
Extends standard <button> attributes so callers can pass any extra
data-*, aria-*, event handler, or style prop without forking the
component. The handful of explicitly named props below let apps swap
the icon glyphs, label, or size without spreading attribute concerns.
interface ThemeToggleProps extends Omit<
ButtonHTMLAttributes<HTMLButtonElement>,
'aria-label' | 'aria-pressed' | 'onClick' | 'type'
> {
/** i18n key for the `aria-label`. Defaults to `'theme.toggle'`. */
ariaLabelKey?: string
/** Fallback `aria-label` if the i18n key is missing. Defaults to `'Toggle theme'`. */
ariaLabelDefault?: string
/** Icon name to render in dark mode. Defaults to `'moon'`. */
darkIcon?: IconName
/** Icon name to render in light mode. Defaults to `'sun'`. */
lightIcon?: IconName
/** Pixel size for the rendered icon. Defaults to `20`. */
iconSize?: number
}ToastProps
Props for the Toast/notification component.
interface ToastProps extends HTMLElementProps {
/**
* Toast content.
*/
children?: Children
/**
* Toast title.
*/
title?: string
/**
* Toast description.
*/
description?: string
/**
* Toast status/type.
*/
status?: ColorVariant
/**
* Duration in milliseconds (0 for persistent).
*/
duration?: number
/**
* Whether the toast is dismissible.
*/
dismissible?: boolean
/**
* Called when dismissed.
*/
onDismiss?: () => void
/**
* Toast position.
*/
position?: 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left'
/**
* Accessible label for the close button.
* @default 'Close'
*/
closeLabel?: string
}TooltipProps
Props for the Tooltip component (hover/focus popover with informational text).
interface TooltipProps extends HTMLElementProps {
/**
* Tooltip content.
*/
content: Children
/**
* Element that triggers the tooltip.
*/
children: Children
/**
* Tooltip placement.
*/
placement?: TooltipPlacement
/**
* Delay before showing (ms).
*/
delay?: number
/**
* Whether the tooltip has an arrow.
*/
hasArrow?: boolean
}UserMenuPopoverPanelProps
Props for {@link UserMenuPopoverPanel}.
interface UserMenuPopoverPanelProps {
/**
* Panel body — typically a set of `<Link>` nav items and a
* `<UserMenuPopoverSignOut />`. Rendered inside a `<nav>` below the
* built-in identity header.
*/
children: ReactNode
/** Extra className composed onto the absolute-positioned panel. */
className?: string
/** i18n key for the panel's aria-label. Default: `'userMenu.panelLabel'`. */
ariaLabelKey?: string
/** Fallback aria-label if the i18n key is missing. Default: `'Account menu'`. */
ariaLabelDefault?: string
/** `data-mol-id` for the panel. Default: `'user-menu-panel'`. */
dataMolId?: string
}UserMenuPopoverProps
Props for {@link UserMenuPopover}.
interface UserMenuPopoverProps {
/**
* The trigger and panel — typically `<UserMenuPopoverTrigger />` and
* `<UserMenuPopoverPanel>`.
*/
children: ReactNode
/**
* Label shown when there is no authenticated user. Defaults to the
* `userMenuPopover.guest` translation (English fallback `"Account"`).
*/
guestName?: string
/** Extra className composed onto the relative-positioned container. */
className?: string
}UserMenuPopoverSignOutProps
Props for {@link UserMenuPopoverSignOut}.
interface UserMenuPopoverSignOutProps {
/** i18n key for the button label. Default: `'userMenu.signOut'`. */
labelKey?: string
/** Fallback label if the i18n key is missing. Default: `'Sign out'`. */
labelDefault?: string
/** `data-mol-id` for the button. Default: `'user-menu-sign-out'`. */
dataMolId?: string
/** Extra className composed onto the button. */
className?: string
}UserMenuPopoverTriggerProps
Props for {@link UserMenuPopoverTrigger}.
interface UserMenuPopoverTriggerProps {
/** i18n key for the trigger's aria-label. Default: `'userMenu.open'`. */
ariaLabelKey?: string
/** Fallback aria-label if the i18n key is missing. Default: `'Open user menu'`. */
ariaLabelDefault?: string
/** `data-mol-id` for the trigger button. Default: `'user-menu'`. */
dataMolId?: string
/** Extra className composed onto the trigger button. */
className?: string
}UserMenuProps
Props for {@link UserMenu}.
The inner trigger is a Molecule <Button> whose own prop set
conflicts with raw ButtonHTMLAttributes (color, value, size enums),
so this component exposes a curated set of customization points
instead of extending HTML attributes. For one-off extra attributes,
pass them via dataMolId / className / style props.
interface UserMenuProps {
/**
* Panel content shown inside the drawer/modal (typically the app's
* `SettingsPanel`). It can dismiss the drawer by calling
* `usePanelClose()` — no `onClose` prop-threading required.
*/
children: ReactNode
/**
* i18n key for the trigger button's aria-label. Defaults to
* `'userMenu.open'`. Apps whose existing locales use a different key
* (e.g. `'userMenu.openButton'`) can override.
*/
ariaLabelKey?: string
/** Fallback aria-label if the i18n key is missing. Defaults to `"Open user menu"`. */
ariaLabelDefault?: string
/** Icon name for the trigger button. Defaults to `'user'`. */
triggerIcon?: IconName
/** Pixel size for the trigger icon. Defaults to 20. */
triggerIconSize?: number
/**
* `data-mol-id` for the trigger button. Defaults to `'user-menu'`.
* Pass an explicit value to disambiguate when the same page mounts
* more than one UserMenu.
*/
dataMolId?: string
/** Extra className composed onto the trigger button. */
className?: string
/** Whether the trigger button is disabled. */
disabled?: boolean
/**
* Override the trigger button's click handler. When provided, called
* instead of opening the panel — hosts use this to intercept the click
* (e.g. to open an auth modal for guest users).
*/
onClick?: () => void
/**
* Which side of the viewport the panel opens from. Defaults to
* `'right'`. Apps whose sidebar trigger sits on the left should pass
* `'left'` so the panel opens adjacent to the trigger.
*/
side?: 'left' | 'right'
}Types
ButtonVariant
Button visual variant styles.
type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'ChangeEventHandler
Framework-agnostic change event handler.
type ChangeEventHandler = EventHandler<Event>Children
Framework-agnostic child content.
Use unknown to allow any framework's node type (ReactNode, VNode, etc.).
type Children = unknownColorVariant
Semantic color variants used across components for status indication.
type ColorVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'EventHandler
Framework-agnostic event handler.
type EventHandler<E = Event> = (event: E) => voidFocusEventHandler
Framework-agnostic focus event handler.
type FocusEventHandler = EventHandler<FocusEvent>FormEventHandler
Framework-agnostic form event handler.
type FormEventHandler = EventHandler<Event>InputType
Allowed HTML input type attribute values for the Input component.
type InputType =
| 'text'
| 'email'
| 'password'
| 'number'
| 'tel'
| 'url'
| 'search'
| 'date'
| 'time'
| 'datetime-local'KeyboardEventHandler
Framework-agnostic keyboard event handler.
type KeyboardEventHandler = EventHandler<KeyboardEvent>ModalSize
Modal size variants including full-screen.
type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'MouseEventHandler
Framework-agnostic mouse event handler.
type MouseEventHandler = EventHandler<MouseEvent>ShellSidebarWidth
Semantic sidebar width — the same stack-agnostic presets
@molecule/app-sidebar-layout-react uses, so both shells render the same
fleet geometry: sm → 208px, md → 240px (default), lg → 256px. A raw
number is an exact pixel width. Applied via inline style (a specific
pixel width is the documented "value a swappable ClassMap cannot express
as a token" case).
type ShellSidebarWidth = 'sm' | 'md' | 'lg' | numberSize
Standard size scale used across all molecule UI components (buttons, inputs, badges, etc.).
type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'TooltipPlacement
Position where a tooltip renders relative to its trigger element (top, bottom, left, right, and corner variants).
type TooltipPlacement =
'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'Functions
AuthGuard(props)
Route-element guard for authenticated sections of a React Router tree.
- While
useAuth().state.initializedisfalse, renders theloadingFallback(or the default<div data-mol-id="auth-guard-loading">{t('common.loading')}</div>). - If the user is not authenticated, redirects to
loginPathcarrying the attempted location instate.fromfor post-login restoration. - Otherwise renders
children(or<Outlet />if none).
The default loading tag carries data-mol-id="auth-guard-loading"
so AI agents and e2e tests can target it reliably. When the caller
passes a custom loadingFallback, it's the caller's responsibility
to include any data-mol-id they need.
function AuthGuard({
loadingFallback,
loadingKey = 'common.loading',
loadingDefault = 'Loading...',
loginPath = '/login',
onAuthenticated,
children,
}?: AuthGuardProps): ReactNodeprops— {@link AuthGuardProps}
cn(inputs)
Merge class name strings, filtering out falsy values (undefined, null, false).
function cn(inputs?: (string | false | null | undefined)[]): stringinputs— Class name strings or falsy values to be filtered out.
Returns: A single space-separated class string.
ConfirmDialog(props)
Are-you-sure-style confirmation modal for destructive actions.
Use standalone (around delete buttons, revoke tokens, irreversible migrations) or with a DangerZoneSection action.
function ConfirmDialog({
open,
onClose,
title,
description,
confirmLabel,
cancelLabel,
onConfirm,
destructive = true,
children,
loading,
}: ConfirmDialogProps): JSX.Elementprops— Component props (see {@link ConfirmDialogProps}).
Icon(props)
Renders an SVG glyph looked up by name from the bonded
@molecule/app-icons set.
Handles two icon-data shapes returned by the bond:
- Pre-rendered SVG markup (
icon.svg) — injected viadangerouslySetInnerHTML. The bond is the trust boundary; only bond a set that controls its own SVG strings. - Structured paths (
icon.paths) — rendered as discrete<path>children, with optional stroke styling forwarded from the icon set.
Any extra HTML/SVG attribute (e.g. data-mol-id, aria-label,
role="img", onClick) is forwarded to the root <svg> via spread.
Decorative by default: when the caller passes no aria-label /
aria-labelledby / role, the SVG is rendered aria-hidden +
focusable="false" so screen readers skip it (an unnamed inline SVG is
announced as a stray "image" by some combos). Passing any of those props
opts the icon into the accessibility tree.
function Icon({ name, size = 20, className, ...rest }: IconProps): React.JSX.Elementprops— {@link IconProps}
Returns: An <svg> element rendering the named glyph.
LanguagePicker(props)
Globe-icon button that opens a modal grid of every locale registered
with the bonded i18n provider. Clicking a locale calls setLocale
and closes the modal.
Reads locale, setLocale, and locales from {@link useTranslation},
so the list of choices stays in sync with whatever set the
setupI18nDefault (or any other i18n setup) registered. No hardcoded
language list — adding a locale to the i18n bond adds it to the picker.
Molecule-convention defaults baked in:
data-mol-id="language-picker-trigger"on the trigger buttondata-mol-id="language-picker-modal"on the modal dialogdata-mol-id="language-picker-option-<code>"on each locale buttondata-activeon the currently-selected locale buttonaria-labelfrom thefooter.languagei18n key (default"Language")
function LanguagePicker({
labelKey = 'footer.language',
labelDefault = 'Language',
modalTitleKey = 'languagePicker.modalTitle',
modalTitleDefault = 'Choose language',
icon = 'globe',
iconSize = 16,
display = 'name',
className,
renderTrigger,
...rest
}?: LanguagePickerProps): JSX.Elementprops— {@link LanguagePickerProps}
LoadErrorBanner(props)
Error banner with an owned pending-state Retry button.
function LoadErrorBanner({
message,
detail,
onRetry,
retryLabel,
retryMolId = 'load-error-retry',
children,
...rest
}: LoadErrorBannerProps): JSX.Elementprops— Component props (see {@link LoadErrorBannerProps}).
PanelCloseProvider(props)
Provides the panel-close callback to descendants. Rendered internally
by UserMenu and SidebarUserCard around their children; apps do
not normally render this directly.
function PanelCloseProvider({ close, children }: PanelCloseProviderProps): JSX.Elementprops— The close callback and the panel content.
Returns: The children wrapped in the close-context provider.
PromptDialog(props)
Modal that asks the user for a short string, replacing window.prompt.
function PromptDialog({
open,
onClose,
title,
description,
placeholder,
initialValue = '',
onSubmit,
confirmLabel,
cancelLabel,
destructive = false,
inputMolId,
confirmMolId,
cancelMolId,
children,
}: PromptDialogProps): JSX.Elementprops— Component props (see {@link PromptDialogProps}).
ResponsiveAppShellContent(props)
The shell's <main> landmark. Grows to fill the row and may shrink below
its content width, so page-level overflow-x strips scroll inside the
page instead of widening the whole shell.
function ResponsiveAppShellContent({
children,
className,
style,
dataMolId = 'shell-content',
testId,
}: ResponsiveAppShellContentProps): JSX.Elementprops— The page content and class/id overrides.
Returns: The main landmark.
ResponsiveAppShellDrawer(props)
The mobile nav drawer (<768px): a left-anchored dialog panel over a backdrop, opened by the menu trigger the TopBar renders.
Implements the WAI-ARIA APG dialog pattern — focus moves into the panel on
open and returns to the previously focused element (the trigger) on close,
Tab is trapped inside, Escape and backdrop clicks close, body scroll locks
(reference-counted with any stacked <Modal>), and the shell closes it on
SPA navigation. Renders nothing on desktop or while closed.
function ResponsiveAppShellDrawer({
children,
header,
navLabel,
footer,
showCloseButton = true,
className,
dataMolId = 'shell-drawer',
closeDataMolId = 'shell-drawer-close',
testId,
}: ResponsiveAppShellDrawerProps): JSX.Element | nullprops— Nav children, header/nav-label/footer slots, close-button and class/id overrides.
Returns: The drawer portal while open on mobile, otherwise null.
ResponsiveAppShellSidebar(props)
The desktop sidebar (<aside> + <nav> landmarks). Renders NOTHING below
768px — the {@link ResponsiveAppShellDrawer} carries the nav there.
Full viewport height, sticky at the top edge, scrolls internally when its content outgrows the viewport.
function ResponsiveAppShellSidebar({
children,
navLabel,
footer,
className,
dataMolId = 'shell-sidebar',
testId,
}: ResponsiveAppShellSidebarProps): JSX.Element | nullprops— Nav children, nav label, footer slot, class/id overrides.
Returns: The sidebar landmarks, or null below the breakpoint.
ResponsiveAppShellTopBar(props)
The shell's <header> landmark: menu trigger (mobile, when a Drawer is
composed), brand, and trailing actions.
Sticks to the top of the viewport by default. The menu trigger renders
only while a ResponsiveAppShell.Drawer is part of the composition AND
the viewport is below the breakpoint.
function ResponsiveAppShellTopBar({
brand,
actions,
mobileOnly = false,
className,
dataMolId = 'shell-topbar',
testId,
}: ResponsiveAppShellTopBarProps): JSX.Element | nullprops— Brand/actions slots,mobileOnly, and class/id overrides.
Returns: The header landmark, or null when mobileOnly is set on desktop.
SidebarUserCard(props)
Sidebar-resident user-account card: avatar + name + status line, opens the app's settings drawer on click.
Drop-in replacement for <UserMenu /> when the trigger lives inside a
vertical sidebar (e.g. as the userMenu slot of <SidebarLayout>).
Reads name/email/avatar from useAuth() by default; pass explicit
name / secondaryLine / avatarUrl props to override.
Ships with data-mol-id="sidebar-user-card" on the trigger button
by default for AI-agent / e2e selection. Callers can override by
passing data-mol-id as an extra prop.
function SidebarUserCard({
children,
name,
secondaryLine,
avatarUrl,
ariaLabelKey = 'sidebarUserCard.open',
ariaLabelDefault = 'Open account menu',
dataMolId = 'sidebar-user-card',
className,
...rest
}: SidebarUserCardProps): JSX.ElementThemeToggle(props)
Button that flips the wired theme bond between light and dark.
Reads mode and toggleTheme from useTheme() and shows the
configured dark/light icon accordingly. Ships with molecule
conventions out of the box:
data-mol-id="theme-toggle"for AI-agent / e2e selectiondata-mode={mode}so tests can assert current state via DOMaria-pressed={mode === 'dark'}for screen-reader statearia-labelfrom thetheme.togglei18n key (default"Toggle theme")
Every per-app variant the fleet was carrying — extra data-* attrs,
additional aria-* flags, custom event handlers — is now absorbed
via the spread of unknown props. Apps that need different icons or
label text use the named props.
function ThemeToggle({
ariaLabelKey = 'theme.toggle',
ariaLabelDefault = 'Toggle theme',
darkIcon = 'moon',
lightIcon = 'sun',
iconSize = 20,
className,
...rest
}?: ThemeToggleProps): JSX.Elementprops— {@link ThemeToggleProps}
ToastProvider(props)
Provider component that manages global toast state.
function ToastProvider({
children,
position = 'bottom-right',
}: ToastProviderProps): React.JSX.Elementprops— The component props.props.children— The child elements to render within the provider.props.position— The default position for toasts.
Returns: The rendered provider with toast container.
useIsDesktop(query)
Whether the viewport is at least 768px wide (the fleet's md breakpoint).
Reads window.matchMedia synchronously in the state initializer, so the
FIRST client render is already correct — no mobile-then-desktop swap frame
(this is time-tracking's QA-hardened version; the naive
"state starts false, sync in an effect" variant mounts the wrong shell for
one frame and double-fetches route data on desktop). Subscribes to
change events afterwards. Guarded for non-browser environments
(SSR/node): returns false (the mobile shell) when no window.matchMedia
exists.
function useIsDesktop(query?: string): booleanquery— Override the media query. Defaults to(min-width: 768px).
Returns: Whether the desktop shell should mount.
usePanelClose()
Returns the callback that dismisses the drawer the current panel is
mounted in. Safe to call anywhere — returns a no-op when no enclosing
UserMenu / SidebarUserCard provides one (e.g. a SettingsPanel
rendered as a standalone page).
function usePanelClose(): () => voidReturns: A function that closes the enclosing drawer, or a no-op.
UserMenu(props)
Avatar-style trigger that opens the app's settings panel in a drawer.
The panel content is passed as children so apps can mount their own
SettingsPanel (which diverges per app) inside the shared drawer
chrome. Panel content dismisses the drawer via usePanelClose().
Ships with data-mol-id="user-menu" on the trigger button by
default for AI-agent / e2e selection.
function UserMenu({
children,
ariaLabelKey = 'userMenu.open',
ariaLabelDefault = 'Open user menu',
triggerIcon = 'user',
triggerIconSize = 20,
dataMolId = 'user-menu',
className,
disabled,
onClick,
side = 'right',
}: UserMenuProps): JSX.ElementUserMenuPopover(props)
Container for the inline popover account menu. Owns the open state and
the auto-dismiss behaviour (route change, popstate, outside click,
Escape), and provides the resolved account identity to its
sub-components via context.
function UserMenuPopover({
children,
guestName,
className,
}: UserMenuPopoverProps): React.JSX.Elementprops— The popover children, optional guest label, and className.
Returns: The relative-positioned popover container.
UserMenuPopoverPanel(props)
The popover panel: an absolutely-positioned card with a built-in
identity header (name + email) and a <nav> wrapping the caller's nav
items. Renders nothing while the popover is closed.
Provides only the structural concerns (absolute positioning above the
trigger, rounded-xl border frame, the header/nav layout). Cosmetic
choices — width, background, padding, shadow — are per-app: pass them
via className. cn() concatenates (it does not tailwind-merge), so
the panel never bakes a width/background the caller would have to
fight.
function UserMenuPopoverPanel({
children,
className,
ariaLabelKey = 'userMenu.panelLabel',
ariaLabelDefault = 'Account menu',
dataMolId = 'user-menu-panel',
}: UserMenuPopoverPanelProps): React.JSX.Element | nullprops— The nav children, className, and aria-label overrides.
Returns: The popover panel, or null when closed.
UserMenuPopoverSignOut(props)
The sign-out nav item — closes the popover and calls auth.logout().
Drop it in as the last child of <UserMenuPopoverPanel>.
function UserMenuPopoverSignOut({
labelKey = 'userMenu.signOut',
labelDefault = 'Sign out',
dataMolId = 'user-menu-sign-out',
className,
}: UserMenuPopoverSignOutProps): React.JSX.Elementprops— Label overrides,data-mol-id, and className.
Returns: The sign-out button.
UserMenuPopoverTrigger(props)
The trigger button: an initials avatar plus the account name and email, styled as a full-width sidebar card. Toggles the popover panel.
function UserMenuPopoverTrigger({
ariaLabelKey = 'userMenu.open',
ariaLabelDefault = 'Open user menu',
dataMolId = 'user-menu',
className,
}: UserMenuPopoverTriggerProps): React.JSX.Elementprops— aria-label overrides,data-mol-id, and className.
Returns: The popover trigger button.
useToast()
Hook to access the toast context for adding and removing toasts.
function useToast(): ToastContextValueReturns: The toast context value with toast management methods.
useUserMenuPopoverClose()
Returns a callback that closes the enclosing UserMenuPopover. Useful
for nav-item onClick handlers that should dismiss the popover even
when they don't change the route. Returns a no-op when called outside
a UserMenuPopover.
function useUserMenuPopoverClose(): () => voidReturns: A function that closes the popover.
Constants
Accordion
Accordion component.
const Accordion: React.ForwardRefExoticComponent<
AccordionProps<string> & React.RefAttributes<HTMLDivElement>
>Alert
Alert component.
role="alert" is assertive: it interrupts a screen reader immediately,
which is correct ONLY for content that appears dynamically (a validation
error after submit, a save failure). An Alert rendered statically with
the rest of the page (an informational banner already in the initial
render) has nothing to interrupt — announcing it assertively on mount is
the same over-announcing trap the Toast role fix addresses. live
(default true, matching the previous unconditional behavior so no
existing dynamic-error usage silently goes quiet) makes this honest and
caller-controlled: pass live={false} for a banner that is part of the
page's normal content, and it announces politely (role="status")
instead of interrupting.
const Alert: React.ForwardRefExoticComponent<
AlertProps & { live?: boolean } & React.RefAttributes<HTMLDivElement>
>Avatar
Avatar component.
const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLDivElement>>Badge
Badge component.
const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>Button
Button component.
const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>Card
Card component.
const Card: React.ForwardRefExoticComponent<
CardProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
>CardContent
Card content component.
const CardContent: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>CardDescription
Card description component.
const CardDescription: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>
>CardFooter
Card footer component.
const CardFooter: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>CardHeader
Card header component.
const CardHeader: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>CardTitle
Card title component.
const CardTitle: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>
>Checkbox
Checkbox component.
const Checkbox: React.ForwardRefExoticComponent<
CheckboxProps & React.RefAttributes<HTMLInputElement>
>ConfirmButton
Two-step destructive-action button: the first click ARMS it ("Confirm?"), the second commits. Auto-disarms after {@link ConfirmButtonProps.disarmSecond
