← All @molecule/* packages · App templates
@molecule/app-ui-reactFramework · ui · App (browser) · v1.0.1 · Apache-2.0
React UI primitive bundle for molecule.dev — Button, Modal, Tooltip, Toast, Alert, Card, Badge, Avatar, Tabs, Accordion, Dropdown, Select, Checkbox, Switch, Input, Table, Spinner, Skeleton, Progress and more. Import these primitives; do not rebuild them.
npm install @molecule/app-ui-reactnpm · Source on GitHub · Implements @molecule/app-ui
@molecule/app-ui-react adapts the @molecule/* cores to the ui framework on the app (browser) side.
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>
</>
)
}Works with: @molecule/app-i18n, @molecule/app-icons, @molecule/app-react, @molecule/app-ui
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.
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>
</>
)
}
framework
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-dom
AccordionItemA 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
}
AccordionPropsProps 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
}
AlertPropsProps 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
}
AuthGuardPropsProps 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
}
AvatarPropsProps 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
}
BadgePropsProps 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
}
BasePropsBase 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
}
ButtonElementPropsBase props for button elements.
interface ButtonElementProps extends HTMLElementProps {
type?: 'button' | 'submit' | 'reset'
name?: string
value?: string
form?: string
}
ButtonPropsProps 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
}
CardPropsProps 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'
}
CheckboxPropsProps 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
}
ContainerPropsProps 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
}
CSSPropertiesFramework-agnostic CSS properties. Mirrors React.CSSProperties but without React dependency.
interface CSSProperties {
[key: string]: string | number | undefined
}
FlexPropsFlex 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
}
FormElementPropsBase 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
}
FormFieldPropsForm 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
}
FormPropsProps 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
}
GridPropsGrid 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
}
HTMLElementPropsBase 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
}
IconPropsProps 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
}
InputElementPropsBase 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
}
InputPropsProps 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
}
LanguagePickerPropsProps 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
}
ModalPropsProps 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
}
PaginationPropsProps 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
}
}
PanelCloseProviderPropsProps for {@link PanelCloseProvider}.
interface PanelCloseProviderProps {
/** Callback that dismisses the enclosing drawer/modal. */
close: () => void
/** Panel content that may call {@link usePanelClose}. */
children: ReactNode
}
ProgressPropsProps 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
}
RadioGroupPropsProps 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
}
RadioOptionA single option in a RadioGroup.
interface RadioOption<T = string> {
/**
* Option value.
*/
value: T
/**
* Display label.
*/
label: Children
/**
* Whether the option is disabled.
*/
disabled?: boolean
}
SelectElementPropsBase props for select elements.
interface SelectElementProps extends HTMLElementProps {
name?: string
required?: boolean
autoFocus?: boolean
multiple?: boolean
onChange?: ChangeEventHandler
}
SelectOptionA 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
}
SelectPropsProps 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
}
SeparatorPropsProps for the Separator component.
interface SeparatorProps extends BaseProps {
/**
* Orientation of the separator.
*/
orientation?: 'horizontal' | 'vertical'
/**
* Decorative separators are purely visual.
*/
decorative?: boolean
}
SidebarUserCardPropsProps 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
}
SkeletonPropsProps 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'
}
SpacerPropsProps 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
}
SpinnerPropsProps 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
}
SwitchPropsProps 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
}
TabItemA 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
}
TableColumnTable 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'
}
TablePropsProps 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
}
TabsPropsProps 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
}
TextareaElementPropsBase 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
}
TextareaPropsProps 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
}
ThemeTogglePropsProps 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
}
ToastPropsProps 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
}
TooltipPropsProps 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
}
UserMenuPopoverPanelPropsProps 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
}
UserMenuPopoverPropsProps 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
}
UserMenuPopoverSignOutPropsProps 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
}
UserMenuPopoverTriggerPropsProps 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
}
UserMenuPropsProps 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
}
ButtonVariantButton visual variant styles.
type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'
ChangeEventHandlerFramework-agnostic change event handler.
type ChangeEventHandler = EventHandler<Event>
ChildrenFramework-agnostic child content.
Use unknown to allow any framework's node type (ReactNode, VNode, etc.).
type Children = unknown
ColorVariantSemantic color variants used across components for status indication.
type ColorVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'
EventHandlerFramework-agnostic event handler.
type EventHandler<E = Event> = (event: E) => void
FocusEventHandlerFramework-agnostic focus event handler.
type FocusEventHandler = EventHandler<FocusEvent>
FormEventHandlerFramework-agnostic form event handler.
type FormEventHandler = EventHandler<Event>
InputTypeAllowed HTML input type attribute values for the Input component.
type InputType =
| 'text'
| 'email'
| 'password'
| 'number'
| 'tel'
| 'url'
| 'search'
| 'date'
| 'time'
| 'datetime-local'
KeyboardEventHandlerFramework-agnostic keyboard event handler.
type KeyboardEventHandler = EventHandler<KeyboardEvent>
ModalSizeModal size variants including full-screen.
type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'
MouseEventHandlerFramework-agnostic mouse event handler.
type MouseEventHandler = EventHandler<MouseEvent>
SizeStandard size scale used across all molecule UI components (buttons, inputs, badges, etc.).
type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
TooltipPlacementPosition 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'
AuthGuard(props)Route-element guard for authenticated sections of a React Router tree.
useAuth().state.initialized is false, renders the
loadingFallback (or the default <div data-mol-id="auth-guard-loading">{t('common.loading')}</div>).loginPath carrying
the attempted location in state.from for post-login restoration.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): ReactNode
props — {@link AuthGuardProps}cn(inputs)Merge class name strings, filtering out falsy values (undefined, null, false).
function cn(inputs?: (string | false | null | undefined)[]): string
inputs — Class name strings or falsy values to be filtered out.Returns: A single space-separated class string.
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:
icon.svg) — injected via
dangerouslySetInnerHTML. The bond is the trust boundary; only
bond a set that controls its own SVG strings.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.Element
props — {@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-active on the currently-selected locale buttonaria-label from the footer.language i18n 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.Element
props — {@link LanguagePickerProps}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.Element
props — The close callback and the panel content.Returns: The children wrapped in the close-context provider.
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.Element
ThemeToggle(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-label from the theme.toggle i18n 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.Element
props — {@link ThemeToggleProps}ToastProvider(props)Provider component that manages global toast state.
function ToastProvider({
children,
position = 'bottom-right',
}: ToastProviderProps): React.JSX.Element
props — 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.
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(): () => void
Returns: 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,
}: UserMenuProps): JSX.Element
UserMenuPopover(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.Element
props — 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 | null
props — 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.Element
props — 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.Element
props — 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(): ToastContextValue
Returns: 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(): () => void
Returns: A function that closes the popover.
AccordionAccordion component.
const Accordion: React.ForwardRefExoticComponent<
AccordionProps<string> & React.RefAttributes<HTMLDivElement>
>
AlertAlert 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>
>
AvatarAvatar component.
const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLDivElement>>
BadgeBadge component.
const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>
ButtonButton component.
const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>
CardCard component.
const Card: React.ForwardRefExoticComponent<
CardProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
>
CardContentCard content component.
const CardContent: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>
CardDescriptionCard description component.
const CardDescription: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>
>
CardFooterCard footer component.
const CardFooter: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>
CardHeaderCard header component.
const CardHeader: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
>
CardTitleCard title component.
const CardTitle: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>
>
CheckboxCheckbox component.
const Checkbox: React.ForwardRefExoticComponent<
CheckboxProps & React.RefAttributes<HTMLInputElement>
>
ContainerContainer component.
const Container: React.ForwardRefExoticComponent<
ContainerProps & React.RefAttributes<HTMLDivElement>
>
DropdownDropdown component.
Implements the WAI-ARIA APG menu-button pattern. The trigger is made a
real, keyboard-operable control: if trigger is a single element (a
<button>, an icon <Button>, …) it is cloned with aria-haspopup,
aria-expanded, aria-controls, and the open/keyboard handlers merged
onto it directly — no extra wrapper, no double focus stop. If trigger
is not a single element (text, a fragment, multiple nodes), it is wrapped
in a role="button" tabIndex={0} container instead so keyboard/AT users
can still reach it. Enter/Space/ArrowDown open the menu and move focus to
the first item (ArrowUp opens to the last item); once open, ArrowUp/Down/
Home/End roving-navigate the role="menuitem" items, Escape closes and
returns focus to the trigger, and Tab closes the menu in sync with focus
leaving it (matching native menus, which do not trap Tab).
const Dropdown: React.ForwardRefExoticComponent<
DropdownProps<string> & React.RefAttributes<HTMLDivElement>
>
DropdownLabelDropdown label for grouping items.
const DropdownLabel: React.ForwardRefExoticComponent<
{ children: React.ReactNode; className?: string } & React.RefAttributes<HTMLDivElement>
>
DropdownSeparatorDropdown separator for dividing groups.
const DropdownSeparator: React.ForwardRefExoticComponent<
{ className?: string } & React.RefAttributes<HTMLDivElement>
>
EmptyStateEmptyState component.
Displays a centered placeholder with an optional icon, title, description, and a primary action when a list or section has no content.
const EmptyState: React.ForwardRefExoticComponent<
EmptyStateProps & React.RefAttributes<HTMLDivElement>
>
FlexFlex container component.
const Flex: React.ForwardRefExoticComponent<FlexProps & React.RefAttributes<HTMLDivElement>>
FloatingInputAn input with a floating label.
Shows the placeholder text as a small uppercase label always visible at the top of the input. On focus the label turns primary-colored.
Works as both a controlled and an uncontrolled input: when value is
omitted, the component tracks its own state seeded from defaultValue
and still forwards every onChange event to the caller.
The floating text is a real <label htmlFor> (not a bare <span>), so
it is the input's programmatic accessible name via label association —
previously the accessible name came only from placeholder (stripped by
some AT/browser combos once the field has a value), and clicking the
floating text did nothing because it wasn't associated with anything.
id falls back to useId() when the caller doesn't pass one, mirroring
Input/Select/Textarea's id-collision fix.
const FloatingInput: ForwardRefExoticComponent<FloatingInputProps & RefAttributes<HTMLInputElement>>
FormForm component.
const Form: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>
FormFieldForm field wrapper component.
const FormField: React.ForwardRefExoticComponent<
FormFieldProps & React.RefAttributes<HTMLDivElement>
>
GridGrid container component.
const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLDivElement>>
InputInput component.
const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>
LabelLabel component.
const Label: React.ForwardRefExoticComponent<
React.LabelHTMLAttributes<HTMLLabelElement> & {
required?: boolean
} & React.RefAttributes<HTMLLabelElement>
>
ModalModal component.
Renders into a document.body portal. Forwards any extra data-* or
aria-* props on the rest spread to the inner dialog <div> (e.g.
callers commonly pass data-mol-id="some-modal" for AI-agent / e2e
selectors).
The internal close button always carries data-mol-id="modal-close"
as the molecule-convention default for the one fixed interactive
element inside the chrome.
Implements the WAI-ARIA APG dialog (modal) pattern: on open, focus moves to the first focusable element inside the dialog (or the dialog itself when it has none); Tab/Shift+Tab are trapped inside the dialog; on close, focus returns to whatever was focused before the dialog opened. Stacked dialogs (a confirm above a drawer) each register on a module-level stack — Escape and the Tab trap only act for the TOPMOST dialog, and the body scroll lock is reference-counted so closing one of several open dialogs never unlocks scroll behind the ones still open.
const Modal: React.ForwardRefExoticComponent<
ModalProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
>
PageHeaderPageHeader component.
Renders a page title with optional breadcrumb trail, description, and action buttons for a consistent page heading area.
const PageHeader: React.ForwardRefExoticComponent<
PageHeaderProps & React.RefAttributes<HTMLDivElement>
>
PageShellPageShell component.
Provides the top-level layout for authenticated pages with an optional collapsible sidebar, a top bar, and a scrollable main content area.
const PageShell: React.ForwardRefExoticComponent<
PageShellProps & React.RefAttributes<HTMLDivElement>
>
PaginationPagination component.
const Pagination: React.ForwardRefExoticComponent<
PaginationProps & React.RefAttributes<HTMLElement>
>
ProgressProgress component.
const Progress: React.ForwardRefExoticComponent<ProgressProps & React.RefAttributes<HTMLDivElement>>
RadioGroupRadioGroup component.
const RadioGroup: React.ForwardRefExoticComponent<
RadioGroupProps<string> & React.RefAttributes<HTMLDivElement>
>
SelectSelect component.
const Select: React.ForwardRefExoticComponent<
SelectProps<string> & React.RefAttributes<HTMLSelectElement>
>
SeparatorSeparator component.
const Separator: React.ForwardRefExoticComponent<
SeparatorProps & React.RefAttributes<HTMLDivElement>
>
SkeletonSkeleton component.
const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>
SkeletonCircleSkeleton circle (avatar placeholder).
const SkeletonCircle: React.ForwardRefExoticComponent<
{ size?: number; className?: string } & React.RefAttributes<HTMLDivElement>
>
SkeletonTextSkeleton text line.
const SkeletonText: React.ForwardRefExoticComponent<
{ lines?: number; className?: string } & React.RefAttributes<HTMLDivElement>
>
SpacerSpacer component.
const Spacer: React.ForwardRefExoticComponent<SpacerProps & React.RefAttributes<HTMLDivElement>>
SpinnerSpinner component.
Extracts data-* and aria-* props from the rest spread so callers can
pass data-mol-id, custom aria-* overrides, etc. without forking.
const Spinner: React.ForwardRefExoticComponent<
SpinnerProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
>
SwitchSwitch component.
const Switch: React.ForwardRefExoticComponent<SwitchProps & React.RefAttributes<HTMLButtonElement>>
TableTable component.
const Table: React.ForwardRefExoticComponent<
TableProps<Record<string, unknown>> & React.RefAttributes<HTMLTableElement>
>
TabsTabs component.
const Tabs: React.ForwardRefExoticComponent<TabsProps<string> & React.RefAttributes<HTMLDivElement>>
TextareaTextarea component.
const Textarea: React.ForwardRefExoticComponent<
TextareaProps & React.RefAttributes<HTMLTextAreaElement>
>
ToastSingle Toast component.
The auto-dismiss countdown pauses on hover AND focus (WCAG 2.2.1) and
resumes with whatever time was left — a slow reader or a keyboard/AT
user interacting with the toast never has it disappear mid-read. The
announced role follows status: warning/error get the assertive
role="alert"; every other status (info, success, the default) gets
the polite role="status" so routine confirmations don't interrupt a
screen reader mid-sentence the way an assertive announcement does.
const Toast: React.ForwardRefExoticComponent<ToastProps & React.RefAttributes<HTMLDivElement>>
ToastContainerContainer that positions toasts on screen via a portal.
const ToastContainer: React.ForwardRefExoticComponent<
ToastContainerProps & React.RefAttributes<HTMLDivElement>
>
TooltipTooltip component.
children must be a single valid React element (e.g. one <button> or
one custom component that forwards aria-describedby) for the tooltip's
content to be programmatically associated with it — this is what lets a
screen reader announce the tooltip text for the actually-focused control.
A non-element children (plain text, a fragment, multiple nodes) still
shows the tooltip visually on hover/focus, but without that association.
hasArrow renders a small themed pointer at the resolved placement
edge.
const Tooltip: React.ForwardRefExoticComponent<TooltipProps & React.RefAttributes<HTMLDivElement>>
Peer dependencies:
@molecule/app-i18n ^1.0.1@molecule/app-icons ^1.0.1@molecule/app-react ^1.0.1@molecule/app-ui ^1.0.1react ^18.0.0 || ^19.0.0react-dom ^18.0.0 || ^19.0.0react-router ^7.0.0 || ^8.0.0@molecule/app-i18n@molecule/app-icons@molecule/app-react@molecule/app-uireactreact-domreact-routerWiring prerequisites — get these right before debugging anything else:
getClassMap() from @molecule/app-ui, which THROWS ("No UIClassMap has been set") until
setClassMap(...) runs with a bond like @molecule/app-ui-tailwind. Scaffolded apps do
this in bonds/index.ts — keep that import first in main.tsx.@molecule/app-react and throw without
them: UserMenu, UserMenuPopover, LanguagePicker, SidebarUserCard, AuthGuard, and
ThemeToggle need I18nProvider (via MoleculeProvider i18n={...}); ThemeToggle also
needs ThemeProvider; AuthGuard also needs AuthProvider. The primitive components
(Button, Modal, Input, …) need only the ClassMap.UserMenu, UserMenuPopover, SidebarUserCard, Dropdown
item hrefs, AuthGuard redirects) render react-router <Link>/navigation — they need a
react-router context (<BrowserRouter>) and, in workspace dev setups, the Vite
resolve.dedupe: ['react', 'react-dom', 'react-router', 'react-router'] entry; a
duplicate copy surfaces as "useHref may be used only in the context of a <Router>".UserMenu panel content is children (rendered inside the popover, with
PanelClose/usePanelClose available) — there is no renderPanel prop.Icon names are kebab-case IconNames from @molecule/app-icons — an unknown name is
a runtime error, not a blank. Extend via CustomIconNames augmentation, never raw SVG.EmptyState — also @molecule/app-empty-state-react (adds an icon badge,
per-brand className/dataMolId, and a companion <CtaCard>). THIS one is the
primitive icon/title/description/action variant.PageHeader — also @molecule/app-page-chrome-react (adds subtitle, icon,
meta, emphasis + a <HeroSection>). THIS one takes
title/description/actions/breadcrumbs.Pagination — the low-level page-window control (no "showing X of Y" text, no
page-size selector); for those use <PaginationBar> from
@molecule/app-pagination-bar-react.A11y contracts worth knowing before you debug "it doesn't look like it's doing anything" on these components:
Modal implements the WAI-ARIA APG dialog pattern: opening moves
focus to the first focusable element inside the dialog (or the dialog
itself when it has none); Tab/Shift+Tab are trapped inside; closing
restores focus to whatever opened it. Stacked dialogs (a confirm above a
drawer) register on a module-level stack — Escape and the Tab trap only
act for the TOPMOST dialog, and the body scroll lock is
reference-counted, so closing one of several open dialogs never unlocks
scroll behind the ones still open. centered={false} top-anchors the
dialog instead of vertically centering it (an inline-style exception —
UIClassMap has no dialogWrapper({ centered }) resolver yet).Dropdown implements the WAI-ARIA APG menu-button pattern: the
trigger is made a real, keyboard-operable control (cloned with
aria-haspopup/aria-expanded/aria-controls when it's a single
element; wrapped in a role="button" tabIndex={0} container otherwise).
Enter/Space/ArrowDown open the menu and focus the first item (ArrowUp
opens to the last); once open, ArrowUp/Down/Home/End roving-navigate the
menuitems, Escape closes and returns focus to the trigger, and Tab
closes the menu in sync with focus leaving it (native menus don't trap
Tab). width="trigger" never renders literal width: 'trigger' CSS on
the not-yet-measurable first-open frame — it renders unset instead.Tooltip requires a single element as children for its content to
be programmatically associated (aria-describedby, injected via
cloneElement) with the actually-focused/hovered control — a non-element
children still shows visually but without that association.
hasArrow renders a small themed pointer at the resolved placement.Toast pauses its auto-dismiss countdown on hover AND focus (WCAG
2.2.1) and resumes with whatever time was left. The announced role
follows status: warning/error get the assertive role="alert";
every other status gets the polite role="status" so a routine
confirmation doesn't interrupt a screen reader mid-sentence.Alert takes a live prop (default true, matching the previous
unconditional behavior): live={false} switches it from the assertive
role="alert" to the polite role="status" for a banner that's part of
the page's normal (not dynamically-appearing) content.UserMenuPopover*: UserMenuPopoverPanel is a disclosure region
(aria-expanded + aria-controls on the trigger, no role on the panel
itself), NOT role="menu" — it renders a header plus a <nav> of
arbitrary links, which is invalid content for role="menu" (that role
may contain ONLY menuitem descendants).Switch dispatches a REAL native change Event through its hidden
checkbox — event.preventDefault(), event.currentTarget, and
event.stopPropagation() all behave like they do for any native input
(previously the handler received a synthesized { target: { checked } }
object that crashed on any of those).Tabs implements the WAI-ARIA APG tabs pattern: roving tabindex
(only the active tab is in the Tab order) with ArrowLeft/ArrowRight/
Home/End moving focus and selection.FormField wires aria-describedby from its error paragraph onto
the child input automatically (falling back to a useId()-derived id
when no name prop is given) — don't duplicate the association by hand.Progress clamps aria-valuenow into [0, max] to match the
clamped visual bar, so out-of-range values never announce impossible
percentages.Textarea autoResize also works uncontrolled (defaultValue +
user typing): it listens to input events rather than only reacting to
the controlled value prop.Translation strings are provided by @molecule/app-locales-ui.