# Aback UI > Aback UI is an open-source React component library and design system from Aback Group. Components are copied into your project as source by the aback-ui CLI, or imported from the @aback-ui/ui npm package. They use square corners, neutral ink actions, the Aback Blue brand ramp, and semantic CSS tokens with light and dark themes. - Website: https://abackui.com - CLI: `npx aback-ui@latest ` (npm package `aback-ui`; the registry ships inside it) - Components package: `@aback-ui/ui`, theme package: `@aback-ui/tokens` - Registry item JSON: https://abackui.com/r/{name}.json, index: https://abackui.com/r/index.json - License: MIT (code). The Aback name and mark are trademarks. - Status: pre-1.0. APIs may change before the first stable release. - Requirements: React 19, Tailwind CSS v4, a `@/` path alias. ## Install with the CLI ```bash npx aback-ui@latest init npx aback-ui@latest add button ``` `init` writes aback-ui.json, styles/aback.css, and lib/utils.ts, and imports the theme in your global stylesheet. `add` copies each component and the components it uses into components/ui. ## Install the npm package ```bash npm install @aback-ui/ui @aback-ui/tokens ``` ```css @import "tailwindcss"; @import "@aback-ui/tokens/tokens.css"; @source "../node_modules/@aback-ui/ui/dist"; ``` ## Documentation - [Introduction](https://abackui.com/docs): What Aback UI is, what is in it, and the two ways to use it. - [Installation](https://abackui.com/docs/installation): Set up a project and add your first component with the aback-ui CLI. - [npm package](https://abackui.com/docs/package): Install @aback-ui/ui and import components instead of copying them. - [CLI](https://abackui.com/docs/cli): Every aback-ui command, option, and the aback-ui.json reference. - [Theming](https://abackui.com/docs/theming): Semantic colour roles and how to override them safely. - [Dark mode](https://abackui.com/docs/dark-mode): Light, dark, and system themes without a flash on load. - [Design tokens](https://abackui.com/docs/tokens): Every colour, the Aback Blue ramp, type, spacing, and shape. - [Accessibility](https://abackui.com/docs/accessibility): Keyboard behavior by component and what has been verified. - [Registry format](https://abackui.com/docs/registry): The item JSON the CLI installs, its schema, and self-hosting. - [Contributing](https://abackui.com/docs/contributing): How the repository is organized and how to propose a component. - [Changelog](https://abackui.com/docs/changelog): What changed in each release. - [Built with Aback UI](https://abackui.com/built-with): The Aback products whose interfaces shaped the system. ## Badge Compact labels for status, counts, and categories, with soft status variants and an optional dot. - Docs: https://abackui.com/docs/components/badge - Install: `npx aback-ui@latest add badge` - Status: stable - npm dependencies: class-variance-authority ### API - `variant` ("default" | "secondary" | "outline" | "brand" | "success" | "warning" | "danger" | "info" | "destructive" | "muted"): Semantic label style. Success, warning, danger, and info are soft status surfaces; destructive is a solid fill. Default: "secondary". - `dot` (boolean): Leads with a small square dot in the badge colour, for live, beta, and planned states. It is decorative. Default: false. - `className` (string): Use for a mono registry type or similar metadata treatment. ### Accessibility - A badge is a label, not a control. It has no hover state and no keyboard behavior. - Keep the text meaningful without the color, since color is supplementary. - For a status that changes, wrap the badge in a live region or pair it with visible text. - Do not put an icon-only badge in place of a labeled action. ## Button The primary action, with ink, brand, outline, ghost, and destructive variants. - Docs: https://abackui.com/docs/components/button - Install: `npx aback-ui@latest add button` - Status: stable - npm dependencies: class-variance-authority, radix-ui ### API - `variant` ("default" | "brand" | "destructive" | "outline" | "secondary" | "ghost" | "link"): default is neutral ink. brand is Aback Blue and is reserved for brand actions. Default: "default". - `size` ("xs" | "sm" | "default" | "lg" | "icon" | "icon-sm" | "icon-xs" | "icon-lg"): Controls height, padding, and icon size on the 36px control grid. Default: "default". - `asChild` (boolean): Renders the child element with button styles, typically a link. Default: false. - `type` ("button" | "submit" | "reset"): Set submit explicitly on form actions. Native buttons submit inside a form. Default: Native default. - `disabled` (boolean): Removes pointer events and reduces opacity. Prefer explaining why when possible. ### Accessibility - Renders a real button unless asChild is used, so Enter and Space both activate it. - Icon-only sizes require an aria-label; the icon itself is hidden from assistive technology. - Focus uses a two-pixel brand ring with an offset on both themes. - Disabled buttons are removed from interaction but remain readable. Do not use disabled as a validation message. ## Card A bordered surface for grouping related content and actions. - Docs: https://abackui.com/docs/components/card - Install: `npx aback-ui@latest add card` - Status: stable ### API - `CardTitle as` ("h2" | "h3" | "h4"): Keeps the heading order correct without changing the visual style. Default: "h3". - `CardHeader / CardContent / CardFooter` (div): Layout slots. Header and content use 24px page insets. - `className` (string): Layout adjustments only. Borders and shadow come from the system. ### Accessibility - A card is a visual grouping, not a landmark. Do not add role region without a label. - CardTitle renders a real heading. Choose the level that continues the page outline. - Interactive cards should put the link on a real anchor inside the title, not on the whole div. - Keep one clear action hierarchy per card; do not place two subtle ghost actions side by side. ## Copy Button Copies a value and confirms it in place, with an announced result and a failure state. - Docs: https://abackui.com/docs/components/copy-button - Install: `npx aback-ui@latest add copy-button` - Status: beta - npm dependencies: @tabler/icons-react ### API - `value` (string): The exact text written to the clipboard. An empty string disables the button. Required. - `label / copiedLabel / errorLabel` (string): Accessible name in each state, and the visible text when showLabel is on. Localize all three. Default: "Copy" / "Copied" / "Copy failed". - `showLabel` (boolean): Shows the label next to the icon. Icon-only buttons keep the label as their accessible name and title. Default: false. - `timeout` (number): Milliseconds before the copied or error state returns to idle. Default: 2000. - `onCopy / onCopyError` ((value: string) => void / (error: unknown) => void): Called after a successful write, or when both the Clipboard API and the fallback fail. - `variant / size` (Button variant / size): Any Button variant and size. The default size follows showLabel. Default: "ghost" / "icon-sm" or "sm". - `copyToClipboard(value)` ((value: string) => Promise): The exported helper the button uses, for copying from your own controls. ### Keyboard - Enter / Space: Copy the value. ### Accessibility - It is a real button with an accessible name in every state, and a polite live region announces "Copied to clipboard" or the failure. - A refused write shows and announces an error state instead of claiming success. - The confirmation stays next to the control. There is no toast that disappears before it can be read. - Icons are decorative. The check and cross also change the label, so colour never carries the result alone. ## Kbd A keycap for documenting shortcuts. - Docs: https://abackui.com/docs/components/kbd - Install: `npx aback-ui@latest add kbd` - Status: stable ### API - `children` (ReactNode): The key label, such as Ctrl, K, or Esc. - `className` (string): Layout adjustments only. ### Accessibility - Renders a real kbd element so assistive technology can identify it. - Always state what the shortcut does in adjacent visible text. - Do not rely on the keycap alone to communicate an action. - Mark decorative keycaps aria-hidden when they only repeat visible text. ## Separator A one-pixel rule for page chrome and grouped content. - Docs: https://abackui.com/docs/components/separator - Install: `npx aback-ui@latest add separator` - Status: stable - npm dependencies: radix-ui ### API - `orientation` ("horizontal" | "vertical"): Direction of the rule. Default: "horizontal". - `decorative` (boolean): Removes the separator from the accessibility tree when it is purely visual. Default: true. - `className` (string): Spacing adjustments only. ### Accessibility - With decorative set to false, Radix exposes role separator and the orientation. - Use the separator token for page chrome and the hairline for content dividers. - Never draw two adjacent one-pixel rules; use divide-y lists instead. - A separator is not a spacing utility. Use gap or padding for rhythm. ## Layout Container, Stack, Group, and Grid primitives that map to the Aback spacing scale. - Docs: https://abackui.com/docs/components/layout - Install: `npx aback-ui@latest add layout` - Status: beta - npm dependencies: radix-ui ### API - `Container size` ("sm" | "md" | "lg" | "xl" | "full"): Max width of a centred column, with the 16px mobile and 24px md gutter. Default: "lg". - `Stack gap` ("none" | "xs" | "sm" | "md" | "lg" | "xl"): Vertical flow: 0, 4, 8, 16, 24, or 32px between children. Default: "md". - `Group gap / align / justify / wrap` (LayoutGap / align / justify / boolean): A horizontal row for toolbars. It wraps by default so action rows never overflow a phone. Default: "sm" / "center" / "start" / true. - `Grid columns / gap` (1 | 2 | 3 | 4 | 6 / LayoutGap): A card grid that starts at one column (two for six) and steps up at sm and lg. Default: 3 / "md". - `asChild` (boolean): Render the child element, so a Container can be the page's main or a section. Default: false. ### Accessibility - The primitives are plain divs by default and add no roles. Use asChild to put landmark elements such as main or section in place. - Visual order follows source order. Do not reorder content with CSS in a way that breaks the reading and focus order. - Group wraps instead of shrinking controls, so touch targets keep their size on narrow screens. - Every gap maps to a literal Tailwind class, so nothing depends on dynamically generated class names. ## Scroll Area A focusable, themed scroll container for long lists and panels. - Docs: https://abackui.com/docs/components/scroll-area - Install: `npx aback-ui@latest add scroll-area` - Status: beta - npm dependencies: radix-ui ### API - `scrollbarVisibility` ("auto" | "always" | "scroll" | "hover"): When the custom scrollbar appears. Use always for a container that must advertise overflow at rest. Default: "hover". - `aria-label / aria-labelledby` (string): Names the focusable scroll region. Give it a name when the content is a distinct list or panel. - `className` (string): Set a height or width; the root clips and the viewport scrolls. ### Accessibility - The viewport is focusable, so the region can be scrolled with the keyboard without a pointer. - When a name is provided, the viewport becomes a named region landmark. Do not wrap it in another landmark with the same name. - The scrollbar thumb uses the published scrollbar tokens and is visible in both themes. - Do not put the only copy of essential content in a fixed-height scroller; keep the full content reachable and avoid nested scroll areas. ## Checkbox A tri-state checkbox with label support and visible focus. - Docs: https://abackui.com/docs/components/checkbox - Install: `npx aback-ui@latest add checkbox` - Status: stable - npm dependencies: radix-ui, @tabler/icons-react ### API - `checked` (boolean | "indeterminate"): Controlled state. Use defaultChecked for uncontrolled usage. - `onCheckedChange` ((checked: boolean | "indeterminate") => void): Fires when the user toggles the control. - `disabled` (boolean): Prevents interaction and reduces opacity. - `name / value / required` (string / string / boolean): Native form integration through a hidden input managed by Radix. ### Keyboard - Space: Toggle the checkbox. - Tab: Move focus into or out of the control. ### Accessibility - Radix exposes role checkbox, aria-checked, and keyboard support. Space toggles the value. - Associate a visible Label with htmlFor; clicking the label toggles the box. - Indeterminate is announced as mixed. Use it for a parent selection, not for a third user state. - Focus is visible on the box itself, so the control must not be wrapped in an overflow-hidden label. ## Combobox A searchable single-select field built on Popover and Command. - Docs: https://abackui.com/docs/components/combobox - Install: `npx aback-ui@latest add combobox` - Status: beta - npm dependencies: @tabler/icons-react ### API - `options` (ComboboxOption[]): The list: { value, label, description?, disabled?, keywords? }. Labels are visible and searchable; keywords add hidden search terms. - `value / onValueChange` (string | undefined / (value: string) => void): Controlled selection. The component renders the matching option's label, so the consumer keeps owning the value. - `placeholder` (string): Shown on the trigger when no option is selected. Default: "Select an option". - `searchPlaceholder / emptyMessage` (string / string): Copy for the search field and the no-results state. Give a recovery hint rather than only saying nothing matched. - `disabled` (boolean): Disables the trigger. Use aria-describedby to explain why when the reason is not obvious. - `name` (string): Renders a hidden input with the selected value so the field submits with a native form. - `aria-label / aria-labelledby / aria-describedby / aria-invalid` (string / string / string / boolean): Names the trigger and dialog and connects help or error text. Pass a visible label through aria-labelledby when one is present. - `className / triggerClassName / align` (string / string / "start" | "center" | "end"): Layout and placement hooks; the selected state and keyboard behavior stay intact. ### Keyboard - Enter / Space: Open the list from the trigger. - Arrow Down / Arrow Up: Move through the filtered options. - Home / End: Jump to the first or last option. - Enter: Select the active option and close the list. - Escape: Close the list and return focus to the trigger. ### Accessibility - The trigger is a button with aria-haspopup=listbox and aria-expanded, so the closed field is announced as a control, not a text input. - The search field is the combobox and owns the listbox. Arrow keys, Home, End, Enter, and Escape operate the list. - The selected option is marked with a check icon and aria-selected; the check is hidden from assistive technology so the announcement is not doubled. - Disabled options stay in the list with aria-disabled, so the option set does not change shape between searches. - The trigger keeps its value label; nothing relies on placeholder text alone to explain the field. Use Combobox when the option set is long enough to need search. For a short, fixed set, the native Select is simpler and keeps the platform's mobile picker. ## Date Picker A date field and a range field, with real keyboard behavior and native form support. - Docs: https://abackui.com/docs/components/date-picker - Install: `npx aback-ui@latest add date-picker` - Status: beta - npm dependencies: @tabler/icons-react, react-day-picker ### API - `value / onChange` (Date | DateRange | undefined / (value) => void): The selected date, or range in DateRangePicker. The consumer owns the value; the field does not drift out of sync with a form library. - `placeholder` (string): Shown when there is no value. It is never the only label for the field. Default: "Pick a date". - `min / max` (Date / Date): Bounds for selectable dates. Days outside the bounds are rendered disabled and cannot be chosen from the grid. - `locale / format` (string / (date: Date) => string): Controls the trigger label. The default uses Intl.DateTimeFormat with the visitor's locale, so no date library is required. - `clearable` (boolean): Shows a Clear action in the popover footer when a value is set. Set it to false for required fields. Default: true. - `name` (string): DatePicker renders a hidden input with a yyyy-mm-dd value for native form submission. DateRangePicker has no name because a range is two values; submit the two dates explicitly. - `defaultMonth / numberOfMonths` (Date / number): Opening month and, for DateRangePicker, how many months are shown side by side. Defaults to the selected date and one month. - `aria-describedby / aria-labelledby / aria-invalid` (string / string / boolean): Connects the field to help text, a visible label, and validation state. ### Keyboard - Enter / Space: Open the calendar from the field. - Arrow keys / Home / End: Move through days in the open calendar. - Page Up / Page Down: Change month; add Shift to change year. - Enter / Space: Choose the focused day. - Escape: Close without changing the value and return focus to the field. ### Accessibility - The field is a button, not a text input pretending to be a calendar. Enter or Space opens the dialog and the current value is part of the button's name. - Focus moves into the calendar grid when the popover opens, and Escape closes it and returns focus to the trigger. - The calendar is labelled Choose a date or Choose a date range, so the dialog is not anonymous. - The Clear action is a real button inside the popover; clearing does not rely on a decorative icon on the trigger. - A DatePicker with a name submits an ISO yyyy-mm-dd value, preserving native form behavior and server-side parsing. Do not close a range picker on the first click: react-day-picker represents that first click as a one-day range. The picker stays open until the two ends differ, and shows the anchor date in the meantime. ## Dropzone A keyboard-operable drag-and-drop file area that validates type, size, and count. - Docs: https://abackui.com/docs/components/dropzone - Install: `npx aback-ui@latest add dropzone` - Status: beta - npm dependencies: @tabler/icons-react ### API - `onFilesAccepted` ((files: File[]) => void): Called with files that passed the type, size, and count checks. Required. - `onFilesRejected` ((rejections: { file, reason }[]) => void): Called with each refused file and a reason of "type", "size", or "count", so the page can explain it. - `accept` (string): Native accept syntax: ".pdf", "image/png", "image/*". It filters the picker and is also enforced for dropped files. - `multiple / maxFiles` (boolean / number): Allow several files, and cap how many one selection may add. Default: false / 1 or unlimited. - `maxSize` (number): Largest accepted file in bytes. - `label / description / hint` (ReactNode): The label is the input's accessible name; the description and hint are its description. Default: "Drop a file here" / "or click to browse". - `icon / disabled / inputProps` (ReactNode / boolean / input props): Replace the upload glyph, disable the area, or pass name, id, or extra aria attributes to the file input. - `fileMatchesAccept / formatFileSize` (helpers): The exported accept check and a 1024-based size formatter for file rows. ### Keyboard - Tab: Focus the file input. - Enter / Space: Open the system file picker. ### Accessibility - A real file input sits under the area, visually hidden but focusable. Tab reaches it, Enter or Space opens the picker, and the frame shows the focus ring. - The visible label names the input and the hint describes it, so the accepted formats are announced before choosing. - Dropping is a convenience, not the only path: the picker always works. - Announce results yourself. The example writes accepted and rejected outcomes to a role=status line instead of relying on colour. ## Field A form field frame that wires labels, help text, and errors. - Docs: https://abackui.com/docs/components/field - Install: `npx aback-ui@latest add field` - Status: stable - npm dependencies: @tabler/icons-react ### API - `htmlFor` (string): The id of the control this field labels. Required. - `label` (ReactNode): Visible label text. Required. - `description` (ReactNode): Rendered under the control with an id of `{htmlFor}-description`. - `error` (ReactNode): Rendered under the control with role alert and an id of `{htmlFor}-error`. - `required` (boolean): Adds a decorative asterisk. Also set required on the control. ### Accessibility - Field renders the label and associates it with htmlFor. It does not inject props into the control. - When a description or error is present, set aria-describedby on the control to the generated id. - Set aria-invalid on the control when error is present; the Input and Select components style it. - Use a visible label. A placeholder is an example, not a label. ## Input A single-line text control aligned to the 36px control grid. - Docs: https://abackui.com/docs/components/input - Install: `npx aback-ui@latest add input` - Status: stable ### API - `type` ("text" | "email" | "password" | "number" | ...): Native input type. Use number with inputMode for numeric keyboard hints. Default: "text". - `aria-invalid` (boolean | "true" | "false"): Turns the border destructive and pairs with a Field error. - `disabled` (boolean): Prevents interaction and reduces opacity. - `className` (string): Layout adjustments only; control height and focus stay on the system grid. ### Accessibility - Always pair with a visible Label or Field. Placeholders disappear and are not a substitute. - Error text must be associated through aria-describedby and the control marked aria-invalid. - The control keeps native autofill, form submission, and mobile keyboard behavior. - Do not use opacity on entered text or value text. ## Input Group Joins an input with units, prefixes, icons, or a compact button inside one 36px frame. - Docs: https://abackui.com/docs/components/input-group - Install: `npx aback-ui@latest add input-group` - Status: beta ### API - `InputGroup` (div): The 36px frame. It owns the border, the focus ring, and the invalid and disabled styling of the control inside it. - `InputGroupInput` (input): The control. Every native input prop passes through, including id, aria-invalid, and aria-describedby. - `InputGroupAddon align` ("start" | "end"): Which side the addon sits on. End addons are ordered after the control. Default: "start". - `InputGroupAddon variant` ("text" | "inline"): text is a boxed segment for units and prefixes. inline sits inside the field for an icon or a compact button. Default: "text". ### Accessibility - Label the InputGroupInput, not the group. Field's htmlFor points at the input id as usual. - When an addon carries meaning, such as a unit or currency, give it an id and add it to the input's aria-describedby so it is announced. - Pressing a non-interactive addon focuses the input, the way a native label does. Buttons and links inside an addon keep their own behavior. - An icon-only button in an addon needs an aria-label, such as Clear search. ## Label An accessible form label with peer-disabled styling. - Docs: https://abackui.com/docs/components/label - Install: `npx aback-ui@latest add label` - Status: stable ### API - `htmlFor` (string): The control id. Required unless the control is nested inside the label. - `className` (string): For example font-normal when the label is a checkbox row. ### Accessibility - Renders a native label. Clicking it focuses or toggles the associated control. - Do not use a label as a heading. Use a real heading for structure. - Peer-disabled styling applies when the control is disabled, but the label remains readable. - Keep labels visible; do not replace them with placeholder text. ## Radio Group Mutually exclusive choices with arrow-key selection and a visible label. - Docs: https://abackui.com/docs/components/radio-group - Install: `npx aback-ui@latest add radio-group` - Status: beta - npm dependencies: radix-ui ### API - `value / defaultValue / onValueChange` (string / string / (value: string) => void): Controlled or uncontrolled selection. - `orientation` ("horizontal" | "vertical"): Arrow-key direction for the group. - `RadioGroupItem value` (string): The value submitted and announced for this option. Required. - `disabled` (boolean): Removes one option or the whole group from interaction. - `aria-label` (string): Names the group when no visible legend or heading does. ### Keyboard - Tab: Enter or leave the group. - ArrowUp / ArrowDown: Move and select in a vertical group. - ArrowLeft / ArrowRight: Move and select in a horizontal group. - Space: Select the focused option without moving. ### Accessibility - Radix exposes radiogroup and radio roles with aria-checked and a single tab stop for the group. - Arrow keys move between options and select as they go; Tab enters and leaves the group. - Associate a visible label with every item using htmlFor. Do not rely on the option value alone. - The checked state uses a solid fill and an inner mark, not colour alone. The square indicator is intentional. ## Rating A star rating built on native radios, with a read-only display for averages. - Docs: https://abackui.com/docs/components/rating - Install: `npx aback-ui@latest add rating` - Status: beta - npm dependencies: @tabler/icons-react ### API - `value / defaultValue / onValueChange` (number / number / (value: number) => void): Controlled or uncontrolled rating. 0 means no rating. - `max` (number): Number of stars. Default: 5. - `name` (string): Form field name. The checked radio submits its value with a native form. - `readOnly` (boolean): Displays a value instead of collecting one. Fractions such as 4.5 render as partial stars inside one image with a text alternative. Default: false. - `clearable` (boolean): A second press on the selected star clears the rating. Default: false. - `size / disabled` ("sm" | "default" | "lg" / boolean): Star size and a disabled state. - `getItemLabel / getValueLabel` ((value, max) => string): Accessible names for each option and for the read-only image. Use them to localize. Default: "3 stars" / "Rated 4.5 out of 5". ### Keyboard - Tab: Enter or leave the rating. - ArrowRight / ArrowUp: Select one more star. - ArrowLeft / ArrowDown: Select one fewer star. - Space: Select the focused star, or clear it when clearable. ### Accessibility - An interactive rating is a native radio group, so screen readers announce "3 stars, radio button, 3 of 5" and form submission works without scripts. - Name the group with aria-label or aria-labelledby pointing at a visible question. - The filled star uses the warning token, which meets non-text contrast. The selected value is also a checked radio, not only a colour. - Read-only ratings are one image with a sentence alternative, not five announced icons. ## Select A native select with a themed chevron and 36px height. - Docs: https://abackui.com/docs/components/select - Install: `npx aback-ui@latest add select` - Status: stable - npm dependencies: @tabler/icons-react ### API - `defaultValue / value / onChange` (native select props): Controlled or uncontrolled native selection. - `disabled` (boolean): Prevents interaction and reduces opacity. - `aria-invalid` (boolean | "true" | "false"): Styles the border as destructive and pairs with a Field error. - `className` (string): Width and layout adjustments. ### Keyboard - Space / Enter: Open the native picker. - ArrowUp / ArrowDown: Change the selected option. - Escape: Close the picker without changing the value. ### Accessibility - Renders a real select, so screen readers, mobile pickers, and keyboard behavior are native. - Always use a visible label. An unlabeled select is not fixed by a placeholder option. - Use optgroup for long lists and keep option labels short and unambiguous. - A native select is not a combobox. If you need search, use a command menu rather than recreating one here. ## Slider A single-value range control with keyboard support and a square thumb. - Docs: https://abackui.com/docs/components/slider - Install: `npx aback-ui@latest add slider` - Status: beta - npm dependencies: radix-ui ### API - `label` (string): Accessible name for the thumb. Required unless you pass aria-labelledby to a visible label. - `value / defaultValue / onValueChange` (number[] / number[] / (value: number[]) => void): Controlled or uncontrolled value. The array holds one entry per thumb. - `min / max / step` (number): Range and increment. Keep steps coarse enough to hit with a keyboard. Default: 0 / 100 / 1. - `orientation` ("horizontal" | "vertical"): Slider direction. Arrow keys follow the orientation. Default: "horizontal". - `disabled` (boolean): Prevents interaction and reduces opacity. ### Keyboard - ArrowLeft / ArrowRight: Change the value by one step. - Home / End: Jump to the minimum or maximum. - PageUp / PageDown: Move in a larger increment. ### Accessibility - Renders role slider on the thumb with aria-valuenow, aria-valuemin, and aria-valuemax. - The thumb needs a name from label or aria-labelledby. A visible label and value beside the slider is the clearest pattern. - Arrow keys change the value, Home and End jump to the range edges, and Page Up/Down move in larger steps. - The square thumb follows the Aback geometry. The checked fill and the numeric value both communicate state, not colour alone. ## Switch A binary toggle with switch semantics. - Docs: https://abackui.com/docs/components/switch - Install: `npx aback-ui@latest add switch` - Status: stable - npm dependencies: radix-ui ### API - `checked / defaultChecked` (boolean): Controlled or uncontrolled on state. - `onCheckedChange` ((checked: boolean) => void): Fires when the user toggles the control. - `disabled` (boolean): Prevents interaction and reduces opacity. - `name / value / required` (string / string / boolean): Native form integration through a hidden input managed by Radix. ### Keyboard - Enter / Space: Toggle the switch. - Tab: Move focus into or out of the control. ### Accessibility - Radix exposes role switch and aria-checked, and Space or Enter toggles it. - Use a switch for a setting that takes effect immediately, not for a form choice that needs saving. - Pair with a visible Label and, where useful, a description of the effect. - The state is conveyed by thumb position and aria-checked, not by color alone. ## Textarea A multi-line text control for longer input. - Docs: https://abackui.com/docs/components/textarea - Install: `npx aback-ui@latest add textarea` - Status: stable ### API - `rows` (number): Initial visible height. The control still resizes vertically. - `aria-invalid` (boolean | "true" | "false"): Turns the border destructive and pairs with a Field error. - `disabled` (boolean): Prevents interaction and reduces opacity. - `className` (string): Width and minimum height adjustments. ### Accessibility - Pair with a visible Label or Field, and associate descriptions and errors with aria-describedby. - The control resizes vertically only, so horizontal layout is never broken. - Use font-mono only when the content is code or data, not for ordinary prose. - Set a sensible maxLength and show a remaining character count when the limit matters. ## Toggle Group A set of related toggles with shared styling and keyboard behavior. - Docs: https://abackui.com/docs/components/toggle-group - Install: `npx aback-ui@latest add toggle-group` - Status: beta - npm dependencies: class-variance-authority, radix-ui ### API - `type` ("single" | "multiple"): One active option or several. Required. - `value / defaultValue / onValueChange` (string | string[]): Controlled or uncontrolled selection, shaped by type. - `variant` ("default" | "outline"): Separated or bordered items. Outline keeps the outer frame. Default: "default". - `size` ("sm" | "default" | "lg"): 32, 36, or 40 pixel control height. Default: "default". - `ToggleGroupItem value` (string): Identifies the option. Required, and must be unique. ### Keyboard - Tab: Enter or leave the group. - ArrowLeft / ArrowRight: Move focus between items. - Space / Enter: Toggle the focused item. ### Accessibility - In single mode Radix exposes a radiogroup with radio items; in multiple mode each item is a button with aria-pressed. - Arrow keys move between items, and the group is a single tab stop. - Icon-only items need an aria-label. Do not rely on the glyph or the selected fill to explain the action. - Use the group for view state such as alignment or density. For settings that save, use Switch or Checkbox. ## Alert Inline status messages for information, success, warning, and destructive feedback. - Docs: https://abackui.com/docs/components/alert - Install: `npx aback-ui@latest add alert` - Status: stable - npm dependencies: class-variance-authority ### API - `variant` ("info" | "success" | "warning" | "destructive" | "muted"): Sets the semantic tone and surface. It never changes the accessible role. Default: "info". - `role` ("alert" | "status"): Set explicitly. Use alert for an error that interrupts, and status for a confirmation. - `className` (string): Layout adjustments only. Do not override the semantic colors. ### Accessibility - Every variant pairs color with an icon and a visible title, so meaning is never carried by hue alone. - Error messages should use role alert and sit next to the control or action that caused them. - A static informational alert needs no live role; adding one announces content on first paint. - Description text inherits the variant color, which meets AA on its tinted surface. ## Progress A determinate or indeterminate bar for work that takes time. - Docs: https://abackui.com/docs/components/progress - Install: `npx aback-ui@latest add progress` - Status: beta - npm dependencies: radix-ui ### API - `value` (number | null): Completed amount. Pass null when the total is unknown; the bar renders indeterminate and no value is announced. Default: null. - `max` (number): Upper bound of the value range. Default: 100. - `label` (string): Accessible name and visible caption. Required unless you pass aria-label on the root. - `showValue` (boolean): Shows the rounded percentage beside the label. Default: false. - `indicatorClassName` (string): Colour override for a semantic result, used sparingly. ### Accessibility - Renders role progressbar with aria-valuenow, aria-valuemin, and aria-valuemax. - The bar needs a name. Use a visible label when the work has a subject, and aria-label when the layout cannot fit one. - Indeterminate work announces no number. Add a status message when the job starts and when it finishes. - The fill uses a transform transition and is disabled under prefers-reduced-motion. ## Reading Progress A decorative bar that fills as the reader moves through an article. - Docs: https://abackui.com/docs/components/reading-progress - Install: `npx aback-ui@latest add reading-progress` - Status: beta ### API - `target` (RefObject): The element being read, such as the article. Without it, progress follows the whole document. - `className` (string): Move or restyle the bar, such as below a fixed header with top-16. ### Accessibility - The bar is decorative and aria-hidden. Scroll position is already available to everyone. - It never intercepts pointer events and is hidden when printing. - Updates run once per animation frame and write a transform directly, so scrolling never re-renders the page. - It sits at z-index 100, the top of the documented stack, so it is not covered by sticky headers. ## Skeleton A loading placeholder that preserves layout. - Docs: https://abackui.com/docs/components/skeleton - Install: `npx aback-ui@latest add skeleton` - Status: stable ### API - `className` (string): Set the size and shape to match the content that will replace it. - `aria-hidden` (boolean): The placeholder is hidden from assistive technology. Default: true. ### Accessibility - Skeletons are decorative. Announce loading on the parent with aria-busy and a status message. - Reserve the final layout size so content does not jump when it arrives. - Do not leave a skeleton on screen indefinitely; show an error or empty state when loading ends. - Pair pulse animation with reduced-motion handling, which the theme applies globally. ## Spinner A loading indicator with a screen-reader label. - Docs: https://abackui.com/docs/components/spinner - Install: `npx aback-ui@latest add spinner` - Status: stable - npm dependencies: @tabler/icons-react ### API - `size` ("sm" | "md" | "lg"): 16, 20, or 24 pixel indicator. Default: "md". - `label` (string): Screen-reader text. Make it specific: Saving, Deploying, Loading invoices. Default: "Loading". - `className` (string): Color and layout adjustments, for example text-primary-foreground in a button. ### Accessibility - Renders role status with a visually hidden label, so the loading state is announced. - Use a specific label. Generic Loading gives no useful context. - Inside a button, keep the visible verb and disable the button while the action runs. - Do not animate indefinitely after a failure; replace the spinner with a message. ## Toast Transient status messages with actions, themed by the Aback tokens. - Docs: https://abackui.com/docs/components/toast - Install: `npx aback-ui@latest add toast` - Status: beta - npm dependencies: @tabler/icons-react, sonner ### API - `theme` ("light" | "dark" | "system"): Pass the app's resolved theme when the theme is a class rather than the OS preference. Default: "system". - `position` ("top-right" | "top-left" | "bottom-right" | "bottom-left" | "top-center" | "bottom-center"): Where the stack appears. Top right keeps it clear of the content being read. Default: "top-right". - `closeButton / richColors / offset` (boolean / boolean / number | object): The close control, status tinting, and the gap from the viewport edge or a sticky header. Default: true / true / 16. - `toast(message, options)` ((message: ReactNode, options?: ToastOptions) => string): Shows a neutral toast and returns its id. Options include description, action, cancel, duration, and id. - `toast.success / error / warning / info` (same signature as toast): Status variants. They use the same soft/strong token pairs as Alert, in both themes. - `toast.dismiss(id?)` ((id?: string) => void): Dismisses one toast, or every toast when no id is given. Use it before a navigation that would otherwise leave a stale message. - `action.label / onClick` (string / () => void): A single reversible action, such as Undo. The toast dismisses after it runs unless you pass `duration: Infinity`. Default: —. ### Keyboard - Tab: Move focus to the action and close buttons while the toast is visible. - Enter / Space: Run the focused action or dismiss the toast. - Alt + T: Move focus into the toast region (sonner's default hotkey). - Escape: Dismiss the focused toast. ### Accessibility - Toasts are announced through a polite live region. Do not use one for a validation error: put the message next to the field so it is read in context and remains on screen. - The close button and the action are real, focusable buttons. They are the only interactive parts; the rest of the toast is not a link. - Never make a toast the only way to reach essential information or the only confirmation that data was saved. Pair it with a persistent state on the page. - Use `duration: Infinity` when the message contains an action the person may need time to consider, and let them dismiss it explicitly. - Emit one toast per outcome. Repeating the same message on every render creates a stream of announcements. - The status colour is never the only signal: every variant also has an icon and a title that names the outcome. - Motion is suppressed when the visitor requests reduced motion. Mount `` once in the root layout — not on each page — then import `toast` from the same module anywhere, including plain event handlers. ## Alert Dialog A modal that requires an explicit response before an irreversible action runs. - Docs: https://abackui.com/docs/components/alert-dialog - Install: `npx aback-ui@latest add alert-dialog` - Status: beta - npm dependencies: radix-ui ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `AlertDialogAction / AlertDialogCancel` (component): Both close the dialog. Action runs the destructive callback; Cancel dismisses. Style Action as destructive when the action is irreversible. - `AlertDialogTitle / AlertDialogDescription` (component): Title names the decision and is required. Description states the consequence in one or two sentences. - `className` (string): Layout adjustments only. ### Keyboard - Escape: Close without running the action. - Tab / Shift+Tab: Move between Cancel and the action. - Enter / Space: Activate the focused action. ### Accessibility - Renders role alertdialog, which screen readers announce as a decision that needs a response. - Radix traps focus, closes on Escape, and returns focus to the trigger. - Use this pattern only when the action is destructive or irreversible; routine forms belong in Dialog. - The action button must name the verb (Delete project), not Yes, so the choice is clear out of context. The action is not a red button by default. Pass the destructive classes when the consequence warrants it, and keep the label specific either way. ## Command A keyboard-first command palette with filtering, groups, and shortcuts. - Docs: https://abackui.com/docs/components/command - Install: `npx aback-ui@latest add command` - Status: beta - npm dependencies: @tabler/icons-react, cmdk ### API - `label` (string): Accessible name for the search input. Required; cmdk renders a visually hidden label from it. - `shouldFilter` (boolean): Filters items by the query. Turn it off when results come from a server and you filter them yourself. Default: true. - `CommandDialog open / onOpenChange` (boolean / (open: boolean) => void): Renders the palette in a modal Dialog. The dialog title and description are visually hidden but announced. - `CommandItem value / onSelect` (string / (value: string) => void): The value used for filtering and the callback that runs on click or Enter. - `CommandShortcut` (component): A right-aligned keyboard hint. It is decorative text; the action must remain understandable without it. ### Keyboard - ArrowUp / ArrowDown: Move the active option. - Enter: Run the active option. - Escape: Close the dialog and return focus to the trigger. ### Accessibility - The `label` prop is not decoration: it names the combobox input. Without it the input is announced as an unnamed edit field. - CommandDialog renders a real Dialog with an accessible title and description, focus trapping, Escape, and focus return. - cmdk manages the combobox, listbox, and option roles, aria-activedescendant, and the selected state. - Filtering keeps the list in sync with aria-activedescendant. Keep items short and do not put a second interactive control inside an item. Open the palette with an explicit trigger or a global shortcut. If you advertise ⌘K, implement it and show Ctrl K on non-Apple platforms. ## Dialog A modal dialog with focus trapping, Escape dismissal, and focus return. - Docs: https://abackui.com/docs/components/dialog - Install: `npx aback-ui@latest add dialog` - Status: stable - npm dependencies: radix-ui, @tabler/icons-react ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `modal` (boolean): Locks background interaction and traps focus while open. Default: true. - `showCloseButton` (boolean): On DialogContent, renders the top-right close control. Default: true. - `DialogTitle / DialogDescription` (component): Title is required for the accessible name. Description supplies the accessible description. ### Keyboard - Escape: Close the dialog and return focus to the trigger. - Tab / Shift+Tab: Cycle focus inside the dialog. - Enter: Activate the focused control. ### Accessibility - Radix traps focus, sets aria-modal, locks page scroll, closes on Escape, and returns focus to the trigger. - Always render DialogTitle. Hide it visually if the design has no title, but never omit the accessible name. - The overlay click closes the dialog. Destructive flows should still require an explicit action in the footer. - The close button is 32px with a visible focus ring and a screen-reader label. ## Dropdown Menu A keyboard-navigable action menu with checkbox and radio items. - Docs: https://abackui.com/docs/components/dropdown-menu - Install: `npx aback-ui@latest add dropdown-menu` - Status: stable - npm dependencies: radix-ui, @tabler/icons-react ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `DropdownMenuContent align` ("start" | "center" | "end"): Alignment relative to the trigger. Default: "center". - `DropdownMenuItem variant` ("default" | "destructive"): Destructive items are separated and styled as danger. Default: "default". - `DropdownMenuCheckboxItem / RadioItem` (component): Stateful items with an indicator and managed selection. ### Keyboard - Enter / Space / ArrowDown: Open the menu and focus the first item. - ArrowUp / ArrowDown: Move focus between items. - Home / End: Jump to the first or last item. - Escape: Close the menu and return focus to the trigger. ### Accessibility - Uses menu semantics, not a listbox or navigation. Use it for actions, not for page links. - Arrow keys move between items, Home and End jump, typeahead selects by label, Escape closes and returns focus. - Keep a destructive action behind a separator and a clear verb. Never make it the default item. - The trigger must have an accessible name; icon-only triggers need an aria-label. ## Hover Card A short profile or context card shown on hover and keyboard focus. - Docs: https://abackui.com/docs/components/hover-card - Install: `npx aback-ui@latest add hover-card` - Status: beta - npm dependencies: radix-ui ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility, usually left to hover and focus. - `openDelay / closeDelay` (number): Milliseconds before opening or closing. Keep the open delay long enough to avoid accidental cards. Default: 700 / 300. - `HoverCardContent align / sideOffset` ("start" | "center" | "end" / number): Placement relative to the trigger. Default: "center" / 8. - `aria-label / aria-labelledby` (string): Names the floating content when it has no visible heading. Pair it with the trigger's accessible name. ### Accessibility - The card supplements the trigger; it must never be the only way to reach essential information or an action. - Radix opens on hover and keyboard focus, so a focusable trigger (link or button) is required. Touch users cannot hover: make the same destination reachable by tapping the trigger. - Keep the content short and non-interactive. Interactive content belongs in Popover, where focus and dismissal are explicit. - Give the content a name when it contains a distinct subject, and keep the trigger text meaningful without the card. HoverCard has no built-in close button and is not a dialog. Do not place destructive actions or required form controls inside it. ## Popover A floating panel anchored to a trigger, for filters and compact detail. - Docs: https://abackui.com/docs/components/popover - Install: `npx aback-ui@latest add popover` - Status: beta - npm dependencies: radix-ui ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `PopoverContent align / sideOffset` ("start" | "center" | "end" / number): Placement relative to the trigger. Default: "center" / 6. - `aria-label / aria-labelledby` (string): The panel is a dialog and needs a name when it has no visible heading. - `className` (string): Width and layout adjustments. The default is 288px. ### Keyboard - Enter / Space: Open the popover from the trigger. - Tab / Shift+Tab: Move through the controls inside the panel. - Escape: Close and return focus to the trigger. ### Accessibility - Content renders in a portal with role dialog and is not modal by default, so the page remains reachable. - Escape closes the panel and returns focus to the trigger; clicking outside also dismisses it. - Give the panel a name with a heading and aria-labelledby, or aria-label when the content has no heading. - Use Popover for interactive content. A sentence of explanation belongs in Tooltip, and a blocking decision belongs in Dialog. ## Sheet A modal panel that slides in from an edge for settings and filters. - Docs: https://abackui.com/docs/components/sheet - Install: `npx aback-ui@latest add sheet` - Status: beta - npm dependencies: @tabler/icons-react, radix-ui ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `side` ("top" | "right" | "bottom" | "left"): Edge the panel slides in from. Right suits settings and filters. Default: "right". - `showCloseButton` (boolean): Renders a labelled 32px close control in the top corner. Default: true. - `SheetTitle / SheetDescription` (component): Title is the accessible name and is required. Description supplies the accessible description. ### Keyboard - Escape: Close and return focus to the trigger. - Tab / Shift+Tab: Cycle focus inside the panel. - Enter / Space: Activate the focused control. ### Accessibility - Renders a modal dialog, traps focus, locks background scroll, closes on Escape, and returns focus to the trigger. - Always render SheetTitle. If the design shows no title, hide it visually instead of omitting the accessible name. - The panel scrolls internally and is capped at 85dvh on top and bottom edges, so long forms stay reachable. - The close button has a screen-reader label. Do not make the overlay the only way to dismiss the sheet. ## Tooltip A short label for icon-only or ambiguous controls. - Docs: https://abackui.com/docs/components/tooltip - Install: `npx aback-ui@latest add tooltip` - Status: stable - npm dependencies: radix-ui ### API - `delayDuration` (number): Milliseconds before the tooltip appears. Default: 200. - `side / align / sideOffset` (Radix placement props): Position relative to the trigger. Default: sideOffset="6". - `TooltipContent` (component): The short label. Render through a portal so it escapes overflow. ### Keyboard - Tab: Focus the trigger and reveal the tooltip. - Escape: Dismiss the tooltip while focus stays on the trigger. ### Accessibility - The tooltip is supplementary. The trigger still needs its own accessible name. - Focus or hover reveals it, and Escape dismisses it without moving focus. - Never put interactive content or essential instructions in a tooltip. - Keep the label short and match the visible action verb. ## Accordion Disclosure sections for FAQs and grouped settings, with full keyboard support. - Docs: https://abackui.com/docs/components/accordion - Install: `npx aback-ui@latest add accordion` - Status: stable - npm dependencies: radix-ui, @tabler/icons-react ### API - `type` ("single" | "multiple"): Whether one or several panels can be open at once. Required. - `collapsible` (boolean): In single mode, allows the open panel to close when activated again. Default: false. - `defaultValue` (string | string[]): Panels open on first render in uncontrolled mode. - `value / onValueChange` (string | string[] / (value) => void): Controlled open state. Use either the uncontrolled or controlled API. - `forceMount` (boolean): On AccordionContent, keeps closed answers in the DOM for SEO. Pair with hidden styling. ### Keyboard - Enter / Space: Toggle the focused panel. - ArrowDown / ArrowUp: Move focus to the next or previous header. - Home / End: Move focus to the first or last header. ### Accessibility - Each trigger is a real button inside a heading, with aria-expanded and aria-controls managed by Radix. - The trigger order forms a single tab stop; arrow keys, Home, and End move between headers. - Closed content is unmounted by default. Pass forceMount when the answer must exist in the initial HTML. - The chevron is decorative and hidden from assistive technology; the label alone names the control. Avoid fixed max heights on answers. The content animates from its measured height so long localized text is never clipped. ## Breadcrumbs A hierarchical trail back to parent pages with current-page semantics. - Docs: https://abackui.com/docs/components/breadcrumbs - Install: `npx aback-ui@latest add breadcrumbs` - Status: stable - npm dependencies: @tabler/icons-react ### API - `items` (BreadcrumbItem[]): Ordered trail. The last item renders as the current page. - `aria-label` (string): Names the navigation landmark. Default: "Breadcrumb". - `className` (string): Layout adjustments only. ### Accessibility - Renders nav and ol semantics, with a chevron separator hidden from assistive technology. - The final item uses aria-current=page and is not a link, even if an href is supplied. - The component uses native anchors so it works in any framework. Swap in your router link for client-side navigation. - Place breadcrumbs directly below the page H1, not above it. ## Collapsible A single disclosure region for optional or advanced content. - Docs: https://abackui.com/docs/components/collapsible - Install: `npx aback-ui@latest add collapsible` - Status: beta - npm dependencies: radix-ui ### API - `open / defaultOpen / onOpenChange` (boolean / boolean / (open: boolean) => void): Controlled or uncontrolled visibility. - `CollapsibleTrigger asChild` (boolean): Renders the trigger styles onto a child button or link. The child keeps its native semantics. Default: false. - `CollapsibleContent forceMount` (boolean): Keeps closed content in the DOM for search or measurement. Hide it visually and from assistive technology. Default: false. - `className` (string): Layout adjustments only. The content is overflow-hidden so animated height cannot escape. ### Accessibility - Radix sets aria-expanded and aria-controls on the trigger and removes collapsed content from the accessibility tree. - The trigger is a real button. If you use asChild, keep the child focusable and do not nest another interactive control inside it. - Do not animate height with a fixed pixel value; let the content size itself or use the Radix content-height variable. - A collapsible is not navigation. Use Accordion when several related sections form one set, and Tabs when the content is a view switch. ## Pagination Page controls with a current-page marker, collapsing ranges, and link mode. - Docs: https://abackui.com/docs/components/pagination - Install: `npx aback-ui@latest add pagination` - Status: beta ### API - `page / pageCount` (number): Current page (1-based) and the number of pages. Values are clamped to the valid range. - `onPageChange` ((page: number) => void): Called when a page button is activated. Required in button mode. - `hrefFor` ((page: number) => string): Renders real links instead of buttons. Use this for server-rendered lists so URLs remain shareable. - `siblingCount` (number): Pages shown on each side of the current page before collapsing into an ellipsis. Default: 1. - `labels` ({ previous?, next?, navigation? }): Localized control labels. The navigation label defaults to Pagination. ### Accessibility - Renders a nav landmark with an accessible name, so it appears in the landmark list and can be skipped. - The current page uses aria-current=page and is not a control. Disabled previous and next are aria-disabled spans, not focusable dead ends. - Use hrefFor whenever the list has real URLs; buttons alone lose deep links, back/forward, and open-in-new-tab. - Ellipses are decorative and hidden from assistive technology. Every numbered page keeps a descriptive accessible name. Keep the page size stable across navigation and move focus to the results heading after a page change so keyboard users do not start at the end of the list. ## Skip Link The first focusable element, which jumps keyboard users past the header to the content. - Docs: https://abackui.com/docs/components/skip-link - Install: `npx aback-ui@latest add skip-link` - Status: beta ### API - `href` (string): The hash of the main content's id. Default: "#main-content". - `children` (ReactNode): The link text. Localize it. Default: "Skip to content". - `className` (string): Adjust the revealed position, for example below a fixed banner. ### Keyboard - Tab: Reveal the link from the top of the page. - Enter: Move focus to the main content. ### Accessibility - Place it first in the body so it is the first tab stop on every page. - It is visually hidden until focused, then appears at the top left with a visible focus ring. - Give the target an id and tabIndex={-1} if it is not natively focusable, so focus actually moves there. - This satisfies WCAG 2.4.1 Bypass Blocks for repeated headers and navigation. ## Table of Contents An "On this page" list of anchors that tracks the section in view. - Docs: https://abackui.com/docs/components/table-of-contents - Install: `npx aback-ui@latest add table-of-contents` - Status: beta - npm dependencies: @tabler/icons-react ### API - `items` ({ id: string; title: ReactNode; depth?: 1 | 2 | 3 }[]): One entry per heading, using the heading's id. Required. An empty list renders nothing. - `title` (ReactNode): The visible heading of the list. It also names the navigation landmark. Default: "On this page". - `offset` (number): Pixels from the top of the viewport where a heading counts as reached. Match your sticky header. Default: 96. - `trackActive` (boolean): Follow the section in view. Turn it off for a static list. Default: true. ### Accessibility - It is a nav landmark named by its visible title, with a list of ordinary anchor links. - The active entry has aria-current=location, and a brand left border as well as colour. - Links work before JavaScript loads and update the URL hash, so they can be shared. - Give each heading scroll-margin-top so it is not hidden under a sticky header after the jump. ## Tabs Switch between related panels with arrow-key navigation. - Docs: https://abackui.com/docs/components/tabs - Install: `npx aback-ui@latest add tabs` - Status: stable - npm dependencies: radix-ui ### API - `defaultValue / value / onValueChange` (string / string / (value: string) => void): Controlled or uncontrolled selected tab. - `orientation` ("horizontal" | "vertical"): Arrow-key direction. Also set aria-orientation on the list. Default: "horizontal". - `TabsTrigger value` (string): Matches the corresponding TabsContent value. Required. - `disabled` (boolean): On TabsTrigger, removes it from the tab order. ### Keyboard - ArrowLeft / ArrowRight: Move between horizontal tabs. - ArrowUp / ArrowDown: Move between vertical tabs. - Home / End: Move to the first or last tab. ### Accessibility - Radix manages tablist, tab, and tabpanel roles, aria-selected, and aria-controls. - Arrow keys move between tabs, Home and End jump to the ends, and activation follows focus. - Give the tab list an accessible name with aria-label so it is distinguishable from other tab groups. - Only the selected panel is rendered, so do not hide essential page content behind a tab. ## Avatar A square identity chip with an initials fallback, and an overlapping group with a counted overflow. - Docs: https://abackui.com/docs/components/avatar - Install: `npx aback-ui@latest add avatar` - Status: beta - npm dependencies: radix-ui ### API - `size` ("xs" | "sm" | "default" | "lg" | "xl"): Sets the square footprint and the fallback type size. Default: "default". - `AvatarImage src / alt` (string / string): Alt text is required when the avatar identifies a person. Use an empty alt for a decorative avatar. - `AvatarFallback` (component): Rendered while the image loads and whenever it fails. Keep it to one or two initials. - `className` (string): Layout adjustments only. - `AvatarGroup max / total / size` (number / number / AvatarSize): Overlap avatars, collapse the rest into a +N count, and count people beyond the rendered ones. Size the count to match the avatars. ### Accessibility - The image keeps real alt text. If the person's name appears next to it, the avatar is decorative and the alt can be empty. - Initials are a fallback, not a substitute for the name in the surrounding row. - Do not signal presence or role with avatar colour alone; add text or a labelled status. - The square shape is deliberate. Do not add rounded-full for a circle that conflicts with the system geometry. - AvatarGroup is a group; name it with aria-label. The overflow count reads as "and 5 more". ## Calendar A square-cornered month grid with single, multiple, and range selection. - Docs: https://abackui.com/docs/components/calendar - Install: `npx aback-ui@latest add calendar` - Status: beta - npm dependencies: @tabler/icons-react, react-day-picker ### API - `mode` ("single" | "multiple" | "range"): Selection mode. It also determines the shape of selected and the argument passed to onSelect. Default: "single". - `selected / onSelect` (Date | Date[] | DateRange | undefined / (value) => void): Controlled selection. In range mode the value is { from, to } and either end may be missing while the visitor is choosing. - `defaultMonth / month / onMonthChange` (Date / Date / (month: Date) => void): The visible month. Use defaultMonth for an initial month and month for full control, such as a month picker. - `disabled` (Matcher | Matcher[]): Dates that cannot be selected, for example { before: min } or { dayOfWeek: [0, 6] }. Disabled days remain announced but are not focusable targets for selection. - `numberOfMonths` (number): Months rendered side by side. Two months suit range selection on wide screens; check the narrow layout before using more than two. Default: 1. - `captionLayout` ("label" | "dropdown" | "dropdown-months" | "dropdown-years"): Adds month or year dropdowns for jumping across a long range. Keep startMonth and endMonth set so the options stay bounded. Default: "label". - `showOutsideDays` (boolean): Shows the adjacent month's days in the leading and trailing cells. They are styled muted and remain selectable unless disabled. Default: true. - `autoFocus` (boolean): Moves focus into the grid when the calendar mounts. DatePicker sets this when its popover opens. Default: false. - `classNames / className` (Partial / string): Adjust one slot or add layout around the calendar. Omitted slots keep the Aback token styling. ### Keyboard - Arrow keys: Move focus by one day or one week. - Home / End: Move to the first or last day of the focused week. - Page Up / Page Down: Move to the previous or next month. - Shift + Page Up / Page Down: Move to the previous or next year. - Enter / Space: Select the focused day. ### Accessibility - Days are buttons in a labelled grid, not a pile of divs. The grid announces the month, and each day announces its full date and selected state. - Keyboard navigation follows the ARIA grid pattern: arrows move by day or week, Home and End move within the week, Page Up and Page Down change month, and Shift with Page Up or Page Down changes year. - Disabled dates keep their place in the grid so the month structure does not jump, but they cannot be selected. - The month caption is a polite live region, so a keyboard month change is announced without interrupting the user. - The calendar is a non-modal surface. Do not trap focus in it; inside a dialog, let the dialog own Escape and focus return. Dates are local calendar days. If the value must represent an instant across time zones, store an ISO timestamp and convert deliberately rather than passing a UTC midnight into the grid. ## Code Block A captioned, scrollable code sample with a copy button and optional line numbers. - Docs: https://abackui.com/docs/components/code-block - Install: `npx aback-ui@latest add code-block` - Status: beta ### API - `code` (string): The exact source. It is rendered as text and is what the copy button writes. Required. - `language / filename` (string): Shown in the caption bar. The filename also names the scroll region. - `copyable / copyLabel` (boolean / string): Show the copy button and set its accessible name. Default: true / "Copy code". - `showLineNumbers` (boolean): Numbers lines with a CSS counter. Numbers are never selected or copied. Default: false. - `maxHeight` (number | string): Caps the height and scrolls, for long files. ### Keyboard - Tab: Focus the code region, then the copy button. - Arrow keys: Scroll the focused code region. ### Accessibility - The pre element is focusable and named, so keyboard users can scroll long lines. - The copy button is a Copy Button: it announces the result and reports a refused write. - Code renders as text, never as injected HTML. Pass pre-highlighted markup through your own wrapper if you need colour. - Line numbers are generated content and are not read as part of the code. ## Description List Key and value rows for metadata, breakdowns, and totals, as a real description list. - Docs: https://abackui.com/docs/components/description-list - Install: `npx aback-ui@latest add description-list` - Status: beta ### API - `DescriptionList bordered` (boolean): Draws the outer border. Turn it off inside a card that already has one. Default: true. - `DescriptionListItem emphasis` (boolean): A bold row with a heavier rule, for a total. Default: false. - `DescriptionListTerm mono` (boolean): Monospace terms for header names and other technical keys. Default: false. - `DescriptionListDetails tone` ("neutral" | "success" | "warning" | "danger" | "info"): Colours a value, such as a discount. Keep a sign or a word with it. Default: "neutral". ### Accessibility - It renders dl, dt, and dd, so assistive technology pairs every term with its value. - Rows wrap on narrow screens instead of truncating, so long values such as header contents stay readable. - Name a standalone list with aria-label when nearby text does not already describe it. - Tone is supplementary. A discount reads as -$29.00, not as a green number alone. ## Relative Time A hydration-safe "3 hours ago" timestamp, localized by Intl and refreshed on one shared clock. - Docs: https://abackui.com/docs/components/relative-time - Install: `npx aback-ui@latest add relative-time` - Status: beta ### API - `date` (Date | string | number): The moment to describe: a Date, an ISO string, or a timestamp. Invalid dates render nothing. Required. - `locale` (string): BCP 47 locale for Intl. Defaults to the browser's language on the client. - `refreshInterval` (number): How often the phrase updates. Components with the same interval share one timer; 0 renders once. Default: 60000. - `absoluteFormat` (Intl.DateTimeFormatOptions): The format of the server render and of the hover title. Default: medium date, short time, UTC. - `formatRelativeTime(date, now, locale)` (function): The exported formatter, for places where you need the phrase as a string. ### Accessibility - It renders a time element with a machine-readable dateTime, and the exact date is the title. - The server and the first client render show the absolute date, so cached pages hydrate without a mismatch. - The phrase updates silently. It is not a live region, so a feed of timestamps does not chatter. - Counts are truncated, never rounded up: 2 hours 50 minutes is "2 hours ago". ## Stat A labelled number with unit, trend, hint, and tone, plus a responsive grid. - Docs: https://abackui.com/docs/components/stat - Install: `npx aback-ui@latest add stat` - Status: beta - npm dependencies: @tabler/icons-react ### API - `label / value` (ReactNode): The term and the formatted number. Format the value before passing it, with Intl.NumberFormat for locales. Required. - `unit / hint` (ReactNode): A muted unit after the value and a sub-line under it. - `icon / badge` (ReactNode): A decorative 16px icon in a brand chip, and a badge after the label. - `tone / emphasis` ("neutral" | "success" | "warning" | "danger" | "info" / boolean): Colours the value, and with emphasis tints the tile. Always pair a tone with words. Default: "neutral" / false. - `trend` ({ direction: "up" | "down" | "flat"; label: string; tone? }): A change with an arrow. The label must carry the change on its own, such as "+8 vs last week". Up is success and down is danger unless you set tone, for metrics where lower is better. - `size` ("sm" | "default" | "lg"): Value size: a compact result tile, a KPI tile, or a headline number. Default: "default". - `StatGrid columns / joined` (2 | 3 | 4 / boolean): Responsive columns that start at one on phones, and a joined panel with hairline dividers. Default: 3 / false. ### Accessibility - The label and value are a dt and dd pair, so the value is announced with its label rather than as a stray number. - The value is not a live region. A ticking counter does not interrupt a screen reader; announce important changes separately. - Trend direction is shown by an arrow and stated in the trend label. Colour is supplementary. - Icons are decorative and hidden from assistive technology. ## Steps An ordered sequence with complete, current, and upcoming states for onboarding and how-it-works sections. - Docs: https://abackui.com/docs/components/steps - Install: `npx aback-ui@latest add steps` - Status: beta - npm dependencies: @tabler/icons-react ### API - `Steps orientation` ("vertical" | "horizontal"): Vertical for onboarding and checklists. Horizontal for how-it-works rows; it stacks on phones. Default: "vertical". - `Step title / description` (ReactNode): The step name and a sentence about it. Required title. - `Step status` ("complete" | "current" | "upcoming"): Complete shows a check, current is highlighted and marked aria-current=step. Default: "upcoming". - `Step statusLabel` (string): Replaces the screen-reader status prefix, such as "Completed", for localization. - `Step children` (ReactNode): Extra content under the description, such as the action for the current step. ### Accessibility - Steps is an ordered list, so the count and each position are announced. - Each step starts with a visually hidden status: Completed, Current step, or Not started. Status is never colour alone. - The current step carries aria-current=step. - Step numbers come from a CSS counter and markers are decorative, so numbers are not read twice. ## Table Semantic table primitives for dense data. - Docs: https://abackui.com/docs/components/table - Install: `npx aback-ui@latest add table` - Status: stable ### API - `TableCaption` (component): A visible caption that also names the table for assistive technology. - `TableHead scope` ("col" | "row"): Set to row for a table whose first cell in each row is a header. Default: "col". - `containerProps` (React.ComponentProps<'div'>): Props for the scroll container. Pass an aria-label to name a horizontally scrollable region. - `className` (string): Column width and alignment adjustments. ### Accessibility - Use a caption or a nearby heading to name the table. A table without a name is hard to navigate. - Keep header cells in thead and set scope row when the first column identifies each row. - The scroll container is keyboard focusable so wide tables can be scrolled without a pointer. - Do not use table layout for page structure. Use CSS grid or flex instead. - Numbers belong in tabular-nums cells and should be right aligned with their header. ## Empty State A clear zero-data state with an optional action. - Docs: https://abackui.com/docs/components/empty-state - Install: `npx aback-ui@latest add empty-state` - Status: stable - npm dependencies: @tabler/icons-react ### API - `title` (ReactNode): Short statement of the empty condition. - `description` (ReactNode): What will appear and the first step to create it. - `icon` (ReactNode): Optional decorative icon. Defaults to an inbox. - `action` (ReactNode): The primary next step, usually a Button or link. ### Accessibility - The title is a paragraph so it cannot break the page heading order. The surrounding section owns the heading. - The icon is decorative. Do not put meaning in it only. - The action should be the same action named in the description. - Announce a newly emptied list with a status message in addition to rendering the empty state. ## Page Header The page title block with one H1, a description, and actions. - Docs: https://abackui.com/docs/components/page-header - Install: `npx aback-ui@latest add page-header` - Status: stable ### API - `title` (ReactNode): Rendered as the page's single h1. Required. - `description` (ReactNode): One or two sentences that state the outcome of the page. - `eyebrow` (ReactNode): Optional uppercase context label above the title. - `actions` (ReactNode): Primary and secondary actions for the page. - `as` ("h1" | "h2" | "h3"): Heading element for the title. Use the default on a page, or h2 in a section or preview that already has a page heading. Default: "h1". ### Accessibility - Renders one heading at the level you choose. A page should contain exactly one h1. - Breadcrumbs belong below the header, not inside it. - Actions are rendered in source order, which is also the keyboard order. - Keep the description factual and under roughly three lines at desktop width. ## Section Heading The eyebrow, title, description, and action that open a page section. - Docs: https://abackui.com/docs/components/section-heading - Install: `npx aback-ui@latest add section-heading` - Status: beta ### API - `title` (ReactNode): The section heading. Required. - `eyebrow / description` (ReactNode): A short brand-coloured label above the title and a sentence below it. - `action` (ReactNode): A link or button for the section, such as View all. It moves to the right from md. - `as` ("h2" | "h3" | "h4"): The heading level. Keep the outline in order under the page's h1. Default: "h2". - `size / align` ("sm" | "default" | "lg" / "start" | "center"): Title scale and alignment. Centre is for marketing sections, start for product pages. Default: "default" / "start". - `headingId` (string): An id for the heading, so the wrapping section can use aria-labelledby. ### Accessibility - Renders a real heading at the level you choose, so the page outline stays navigable. - Pair it with a section labelled by headingId to create a named region. - The eyebrow uses the link token, which meets text contrast in both themes. - Use PageHeader for the page's h1. SectionHeading is for everything below it. ## Share Buttons Share links for X, LinkedIn, and more, with copy link and the native share sheet. - Docs: https://abackui.com/docs/components/share-buttons - Install: `npx aback-ui@latest add share-buttons` - Status: beta - npm dependencies: @tabler/icons-react ### API - `url / title` (string / string): The absolute URL to share, and the text or subject where a network supports it. url is required. - `networks` (("x" | "linkedin" | "facebook" | "whatsapp" | "reddit" | "email")[]): Which share links to render, in order. Default: ["x", "linkedin"]. - `copyLink / nativeShare` (boolean / boolean): Add a copy-link button, and a native share button where the browser offers the Web Share API. Default: true / false. - `showLabels` (boolean): Show network names next to the icons. Default: false. - `shareUrl(network, url, title)` (function): The exported URL builder, for your own share layout. ### Accessibility - The controls are a named group, and every icon-only link has a name such as Share on LinkedIn. - Network links are plain anchors that open in a new tab with noopener. Nothing loads from a third party until someone chooses to share. - Copy link announces the result through Copy Button's live region. - The native share button only renders where the browser supports it, so there is never a dead control. ## Theme Toggle A light and dark switch, a useTheme hook, and a no-flash theme script. - Docs: https://abackui.com/docs/components/theme-toggle - Install: `npx aback-ui@latest add theme-toggle` - Status: beta - npm dependencies: @tabler/icons-react ### API - `ThemeToggle storageKey` (string): The localStorage key that remembers the choice. Default: "theme". - `ThemeToggle toDarkLabel / toLightLabel` (string): The accessible name in each state. Localize both. Default: "Switch to dark theme" / "Switch to light theme". - `ThemeToggle variant / size` (Button variant / size): Any Button variant and size. Default: "ghost" / "icon". - `useTheme(storageKey?)` (() => { theme, resolvedTheme, setTheme }): theme is "light", "dark", or "system"; resolvedTheme is what is on screen. Every hook and toggle stays in sync, across tabs too. - `ThemeScript storageKey / nonce` (string / string): Render in head to apply the stored theme before paint. Pass a CSP nonce if your policy requires one. ### Keyboard - Enter / Space: Switch between light and dark. ### Accessibility - The toggle is a button whose name says what it will do, such as Switch to dark theme. - The icon follows the dark class through CSS, so it is correct before hydration, and the name updates after. - A system preference is respected until the visitor chooses, and system changes apply live. - Blocked storage does not break the toggle; the theme still changes for the current page. The contract matches the Aback theme CSS: a dark class on html. Add suppressHydrationWarning to the html element, because ThemeScript changes its class before React hydrates. ## Block: Article layout A long-form page with meta bar, scoped typography, sticky contents, share links, and reading progress. - Docs: https://abackui.com/docs/blocks/article-layout - Install: `npx aback-ui@latest add article-layout` - Pass your rendered article as children. Plain h2, h3, p, lists, blockquotes, links, and inline code are styled inside the block only. - Give each h2 and h3 an id and list them in `toc`. Generate both from your Markdown or CMS headings so they cannot drift. - The contents aside appears when the block's container is at least 48rem wide (a container query), so it also works inside a narrow layout. - `readingTime` should come from the real word count. `publishedAt` renders as a stable absolute date, so cached pages do not change. ## Block: Call to action A closing banner with one primary and one optional secondary action, in brand or neutral tone. - Docs: https://abackui.com/docs/blocks/cta-banner - Install: `npx aback-ui@latest add cta-banner` - One primary action. A second, quieter action is optional. More than two dilutes the banner. - Use the brand tone at the end of a marketing page and the muted tone on dense product pages. ## Block: Contact form A contact form with field-level errors, focus on the first error, a character count, and submit states. - Docs: https://abackui.com/docs/blocks/contact-form - Install: `npx aback-ui@latest add contact-form` - Implement `onSubmit` with your server action or API route and validate again on the server. Client checks only catch typos. - Return `{ ok: false, message }` for a failure you can explain, such as a rate limit. Thrown errors show a generic retry message. - Change `topics` to match how your team triages messages, and keep a catch-all option. - Add spam protection on the server, such as Turnstile, before going live. ## Block: Cookie consent A non-blocking consent banner with equally prominent accept and decline, remembered per browser. - Docs: https://abackui.com/docs/blocks/cookie-consent - Install: `npx aback-ui@latest add cookie-consent` - Load optional scripts only after `onDecision("accepted")`. The block decides nothing for you. - Write `message` plainly: what you ask for, and what happens if the visitor declines. - The choice is stored under `storageKey`. Give people a way to change it later, such as a link on your cookie policy page that clears the key. - Check the rules where you operate. This block is a pattern, not legal advice or a consent management platform. ## Block: Dashboard shell A responsive application shell with persistent navigation, a mobile sheet, top bar, and page header. - Docs: https://abackui.com/docs/blocks/dashboard-shell - Install: `npx aback-ui@latest add dashboard-shell` - Pass your real navigation as `nav` with `href`s from your router. The shell renders anchors; swap them for your link component if you need client-side navigation. - `activeHref` is matched exactly against the item's `href`. For nested sections, pass the parent item's href as the active one, or compute it from the current path. - `onSearch` and `onSignOut` are optional. Omit them and the corresponding controls are not rendered, so the shipped page never shows a button that does nothing. - The content region is a div so the shell can sit inside an existing `
`. When the shell owns the page, replace that container with `
`; do not end up with two main landmarks. - The preview adds example metrics and activity. Those live outside the block source; replace them with your own data and keep the labelled example badge off the real page. ## Block: FAQ Questions in an accordion with indexable closed answers and optional FAQPage structured data. - Docs: https://abackui.com/docs/blocks/faq - Install: `npx aback-ui@latest add faq` - Answers are plain strings so they can be mirrored into structured data. Separate paragraphs with a blank line. - Set `structuredData` only for questions answered on this page. Search engines treat mismatched FAQ markup as spam. - The first answer starts open; all answers stay in the HTML, so in-page search and crawlers can find them. ## Block: Feature grid A titled grid of features with brand icon chips and optional links, joined by hairlines. - Docs: https://abackui.com/docs/blocks/feature-grid - Install: `npx aback-ui@latest add feature-grid` - Use three or four features with icons that mean something. Six is the most a reader will scan. - Give a feature an `href` to make the whole cell one link to its page. The title is the link's name. - Pass a unique `headingId` when a page has more than one feature grid. ## Block: Hero A landing-page opening with announcement, h1, highlight line, actions, proof points, and an aside. - Docs: https://abackui.com/docs/blocks/hero - Install: `npx aback-ui@latest add hero` - The hero renders the page's h1. Use it once, at the top of a landing page. - `highlight` is the second line of the same h1 in the link colour. Do not use gradient text; it fails contrast and the design system bans it. - Only claim `highlights` you can back up. The preview's numbers are labelled example data; pass real figures from your server. - Put a product shot, a live stat panel, or a demo in `aside`. It moves below the actions on narrow screens. ## Block: Newsletter signup An email signup with real submitting, success, and error states driven by your subscribe call. - Docs: https://abackui.com/docs/blocks/newsletter - Install: `npx aback-ui@latest add newsletter` - Implement `onSubscribe` with your email provider and return `{ ok, message }`. The block shows exactly that message; it never claims success on its own. - Use double opt-in and say so in the success message: "Check your inbox to confirm." - Say what you send and how to leave in `consent`. Do not pre-tick anything. - The inline variant fits a sidebar or footer column; the card variant suits the end of an article. ## Block: Not found A 404 page with a way forward: home, an alternative, and the destinations people usually want. - Docs: https://abackui.com/docs/blocks/not-found - Install: `npx aback-ui@latest add not-found` - Render it from your framework's not-found route so the response is a real 404, not a 200 with an error message. - Fill `links` from your analytics: the pages people were most likely looking for. - Only pass `searchHint` if your site actually has search and the shortcut works. ## Block: Pricing Plan cards with a monthly or yearly switch, Intl prices, included and excluded features, and aligned actions. - Docs: https://abackui.com/docs/blocks/pricing - Install: `npx aback-ui@latest add pricing` - Prices are monthly amounts per period: `{ monthly: 29, yearly: 23 }` shows $23 per month, billed yearly. 0 renders as Free. - Pass `currency` and `locale` so Intl formats the amount. Never concatenate a currency symbol. - Keep `yearlyLabel` truthful. If you say "save 20%", make the yearly prices 20% lower. - Use `footnote` for tax, trial, and refund terms that belong next to the prices. ## Block: Settings section A workspace settings section with identity fields, preferences, a save bar, and a confirmed danger zone. - Docs: https://abackui.com/docs/blocks/settings-section - Install: `npx aback-ui@latest add settings-section` - Pass `initialValues` from the server and implement `onSave`. Until then the block is local state and says so. - Extend the preference rows as you add settings. Each Switch needs a Label and a sentence that explains the effect, not just the name. - The danger zone is deliberate. Keep the AlertDialog and the explicit Delete workspace action; do not replace it with an immediate delete. - Wire `onDelete` to a server action and return a result the page can announce. The block does not navigate or toast on success. ## Block: Sign in A complete sign-in card with email, password, remember me, and account links. - Docs: https://abackui.com/docs/blocks/sign-in - Install: `npx aback-ui@latest add sign-in` - Replace `onSubmit` with your auth client call. The block owns no authentication, network request, or session state. - Swap the two anchors for your router's link component so the auth flow keeps client-side navigation. - Render server errors by passing them into the form: mark the field `aria-invalid` and add a Field error. Do not rely on the password length or an empty email as validation. - If your product supports passkeys or SSO, add them above the divider and keep the email form as the fallback. ## Block: Site footer Brand column, link columns, and a legal bar that collapse cleanly from four columns to one. - Docs: https://abackui.com/docs/blocks/site-footer - Install: `npx aback-ui@latest add site-footer` - Each column is a navigation landmark named by its title. Keep column titles short and distinct. - Mark links to other sites `external`: they open in a new tab with noopener, show an arrow, and say so to screen readers. - Put legal links such as privacy and terms in `legal`, not in a column, so they stay in the bottom bar on every page. ## Block: Site header A sticky header with brand, primary navigation, optional search, theme toggle, actions, and a mobile sheet. - Docs: https://abackui.com/docs/blocks/site-header - Install: `npx aback-ui@latest add site-header` - Pass `brand` as your logo link and `links` from your route config. Swap the anchors for your router's link component to keep client-side navigation. - `activePath` marks a link active when the current path equals or starts with its href, so nested pages keep their section highlighted. - `onSearch` is optional. Without it no search control renders; with it, wire the same handler to your keyboard shortcut and pass that shortcut as `searchShortcut`. - `actions` render on the right from md and at the bottom of the mobile sheet, so a sign-in or CTA is never lost on phones. ## Block: Users table A searchable member directory with role filters, sorting, row actions, empty state, and pagination. - Docs: https://abackui.com/docs/blocks/users-table - Install: `npx aback-ui@latest add users-table` - Pass real members from a server component. The built-in list is clearly example data and should be replaced, not fetched by the block. - `onInvite` and `onManage` are optional by design. When provided, the toolbar and row menu call your dialogs or routes; when absent, no dead actions are rendered. - Filtering, sorting, and paging run locally over the provided array. For a large directory, move the query to the server and keep the same table, empty-state, and pagination contract. - Copy email writes to the clipboard and announces the result in a visually hidden status region. Replace it if your workspace does not expose member emails.