# Honest UI Full Documentation > Full Markdown snapshot generated from the same MDX source as the Honest UI documentation site. ## Accessibility > Understand Honest UI's accessibility foundation and the checks your application still needs. Source: https://www.honestui.com/docs/accessibility Markdown: https://www.honestui.com/docs/accessibility.md --- title: Accessibility metaTitle: Accessibility foundations description: Understand Honest UI's accessibility foundation and the checks your application still needs. --- Accessibility starts with the component structure and continues through your content, composition, styling, and testing. Honest UI provides a foundation; it does not make an assembled application conformant by itself. ## What Honest UI provides Honest UI prefers native HTML for familiar controls. Complex interactions such as dialogs, menus, popovers, comboboxes, and tabs use primitives that provide roles, state, focus management, and documented keyboard behavior. Depending on the component, that foundation can include: - Native roles and states. - Keyboard operation and focus management. - Visible focus styles. - Connections among form controls, labels, descriptions, and errors. - Disabled and invalid states. - Reduced-motion handling for documented animated components. Read the component's Accessibility section because responsibilities differ. An Input needs a useful label, an icon-only Button needs an accessible name, and a chart needs an equivalent way to understand important values. ## Give controls useful names Every form control needs an accessible name. Use a persistent visible label for fields that people must identify, understand, or revisit. [Field](/docs/components/field) connects a label, description, validation message, and control with consistent spacing. Write labels for the information or decision: - `Email address`, not `Email` when the expected value could be unclear. - `Project visibility`, not `Visibility` when several settings use that word. - `Receive product updates`, not `Updates` for a preference switch. Descriptions should explain a constraint or consequence rather than repeat the label. Place essential requirements before submission instead of teaching them only through an error. ## Preserve documented keyboard behavior Test each interaction without a mouse. Do not apply one keyboard pattern to every control: native buttons, checkboxes, tabs, menus, sliders, and comboboxes have different expected keys. Check that: - `Tab` and `Shift+Tab` move through interactive elements in a logical order. - Buttons and links respond to their native activation keys. - Composite controls support the arrow-key behavior documented by their primitive. - `Escape` closes dismissible dialogs and popups when supported. - Focus moves into modal content when it opens and returns to a logical place when it closes. - Every pointer-only action has an equivalent keyboard path. ## Keep focus visible Do not remove focus styles. Focus must remain visible against the component and adjacent colors, including in dark themes and forced-colors modes. Check that sticky headers, dialogs, and other overlays do not hide the focused element. Avoid moving focus unless the interaction requires it and the destination is predictable. ## Explain unavailable and loading actions Use a disabled state only when the control cannot be used. If the reason is not obvious, explain it nearby. A disabled control cannot normally reveal its own tooltip or receive keyboard focus, so required instructions must remain available elsewhere. For an action in progress, preserve the layout, communicate the busy state, and prevent accidental duplicate work when necessary. Do not announce success until the requested work has completed. ## Write errors that support recovery Connect validation messages to their controls and identify the specific correction: - `Enter an email address in the format name@example.com.` - `Choose at least one role.` - `Enter 12 or more characters.` Avoid `Invalid`, `Required`, and `Something went wrong` when the cause or recovery step is known. Preserve entered values after an error whenever it is safe to do so. ## Do not rely on one sensory cue Do not communicate meaning through color, position, shape, sound, motion, hover, or drag alone. Pair important states with visible text and expose the same meaning to assistive technology. Pointer targets should be at least 24 by 24 CSS pixels unless a WCAG 2.2 spacing or other defined exception applies. Prefer larger targets, including 44 by 44 CSS pixels, for important controls and touch-heavy interfaces. ## Test the complete task Automated checks catch only some problems. For each changed task, verify: 1. Semantic structure and accessible names. 2. Complete keyboard operation and visible focus. 3. The task with a supported screen-reader and browser combination. 4. Text enlargement and reflow at 200% and 400% zoom where applicable. 5. Light, dark, and forced-colors presentations. 6. Reduced-motion behavior. 7. Labels, errors, loading, empty, disabled, and success states. 8. Touch target size and operation without precise pointer movement. Document which environments you tested. Do not claim WCAG conformance from a component primitive or automated scan alone. --- ## Components > Choose, install, and adapt Honest UI components for product interfaces. Source: https://www.honestui.com/docs/component-guide Markdown: https://www.honestui.com/docs/component-guide.md --- title: Components description: Choose, install, and adapt Honest UI components for product interfaces. --- Component pages follow a shared structure so you can decide whether a component fits, install it, and adapt it without guessing which behavior must remain intact. Each page explains what the component is for, how to install it, how to import it, and which examples show the important states. ## Page structure Component pages include: - **What it does:** the task the component supports. - **When to use it:** where it fits and which component to use instead when it does not. - **Anatomy:** the parts and how they work together. - **Behavior and states:** controlled values, loading, errors, disabled states, and forms when they apply. - **Accessibility:** behavior supplied by the component and responsibilities that remain in your application. - **Installation:** the CLI command and manual source. - **Usage:** the smallest useful example. - **Examples:** variants, sizes, states, form usage, and composition patterns. If a component is built on Base UI, the page may link to the Base UI API reference for lower-level behavior and props. ## Choosing a component Use the component that matches the user's task: - Use **Button** for actions. - Use a **link** for navigation. Use Button's link rendering only when you need Button styling on a real link destination. - Use **Checkbox** for independent yes/no choices. - Use **Radio Group** when only one option can be selected. - Use **Select** when the user chooses from a known list. - Use **Combobox** or **Autocomplete** when search helps the user find an option. - Use **Dialog** for focused work that interrupts the page. - Use **Sheet** for side panels, details, and secondary workflows. - Use **Toast** for short feedback that does not need a response. - Use a **Dialog with an explicit confirmation action** when the user must make a consequential decision before continuing. ## Copying examples Examples are not only visual demos. They show recommended structure. When you copy an example: 1. Keep the accessibility parts, such as labels, descriptions, and triggers. 2. Replace sample text with copy that names the real task and outcome. 3. Keep disabled, loading, and error states if the workflow can reach those states. 4. Update imports to match your project. 5. Test the complete example with keyboard navigation and the assistive technologies your product supports. ## Building larger screens Combine components by responsibility: - Use **Field** around form controls so labels and errors stay consistent. - Use **Card** or **Frame** to group related content. - Use **Tabs** when related views share the same page context. - Use **Menu** for compact command lists. - Use **Toolbar** when controls act on the same surface. - Use **Empty** when a section has no data yet. Start with the smallest component that solves the interaction. Add more structure only when the user needs it. ## Customizing components Copied Honest UI components are meant to be edited. Common customizations include: - Changing class names. - Adjusting color variables. - Adding variants. - Replacing icons. - Renaming files or import paths. - Wrapping a component in your app-specific API. Keep behavior and accessibility intact when customizing. Style changes are usually safe. Changes to focus management, keyboard navigation, roles, labels, and portals need more care. --- ## Contributing Guide > How to make focused, useful contributions to Honest UI. Source: https://www.honestui.com/docs/contributing Markdown: https://www.honestui.com/docs/contributing.md --- title: Contributing Guide description: How to make focused, useful contributions to Honest UI. --- The best contributions are focused, easy to review, and clear about the user problem they solve. ## What you can contribute You can help by: - Fixing bugs. - Improving docs. - Adding new UI components. - Adding examples. - Improving accessibility. ## Before you start Open an issue before starting a large change so maintainers can confirm the problem and scope. Small fixes, documentation edits, and example improvements can usually go straight to a pull request. Good first changes include: - Fixing unclear docs. - Adding a missing example state. - Improving labels or keyboard behavior. - Cleaning up a component prop or class name. - Fixing a bug with a small reproduction. ## Quick steps 1. Fork the repo and clone it. 2. Create a new branch. 3. Make a small, focused change. 4. Run the checks that apply to the changed files. 5. Open a pull request with a clear description. ## Commands to run before you open a PR ```bash npm run lint -- path/to/changed-file.tsx npm run build npm run build:package npm --prefix package/honestui run typecheck ``` If you changed docs, check that the docs site still builds and the changed pages render correctly. ## Write clear pull requests Please include: - What changed. - Why you changed it. - Screenshots if UI changed. - Any breaking changes. - The checks you ran. Keep unrelated changes in separate pull requests so each change can be reviewed and verified on its own. ## Component contribution checklist When adding or changing a component, check: - The default example is useful. - Important states are documented. - The component works with keyboard navigation. - Labels, descriptions, and errors are connected where needed. - The manual installation block lists required dependencies and CSS variables. - The component source and examples use the same import style as the rest of the registry. ## Docs contribution checklist When changing docs, use simple language. Prefer short paragraphs and specific examples. Explain when to use a component, when not to use it, and what each example demonstrates. ## Need more details? For the full technical process, file conventions, and registry details, see: [Full CONTRIBUTING.md](https://github.com/honestui/honestui/blob/main/CONTRIBUTING.md) --- ## Honest UI Developer Resources > Integrate with the public Honest UI Registry API, parse errors, and plan for version changes. Source: https://www.honestui.com/docs/developers Markdown: https://www.honestui.com/docs/developers.md --- title: Honest UI Developer Resources description: Integrate with the public Honest UI Registry API, parse errors, and plan for version changes. --- Honest UI publishes a public, read-only REST API for registry discovery and initialization presets. Start with the [OpenAPI 3.1 specification](/openapi.json) for the complete machine-readable contract or request the [API v1 index](/api/v1) for links to its resources. ## Honest UI REST API v1 The current base URL is: ```text https://www.honestui.com/api/v1 ``` | Resource | Purpose | | --- | --- | | `GET /api/v1` | Discover the current version, documentation, specification, and primary resources. | | `GET /api/v1/registry` | Retrieve the public shadcn-compatible registry catalog. | | `GET /api/v1/registry/index` | List public registry item names and types. | | `GET /api/v1/registry/{name}` | Retrieve one public registry item. | | `GET /api/v1/colors/{name}` | Retrieve the registry base-color definition. | | `GET /api/v1/init` | Generate an initialization preset from documented query parameters. | The existing `/r/*` and `/init` URLs remain available for CLI and registry compatibility. New HTTP integrations should use `/api/v1` so their major API version is explicit. ## Authentication and access The documented API is public and read-only. It does not require an API key, OAuth token, session cookie, or other credentials. Honest UI does not currently publish webhooks or an MCP server. Use the [agent skill](/skill.md) and [llms.txt](/llms.txt) for agent-oriented discovery. ## JSON error responses Versioned API errors follow [RFC 9457 Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457) and use `Content-Type: application/problem+json`. Every problem includes the standard `type`, `title`, `status`, `detail`, and `instance` members plus stable `code`, `message`, and `resolution` extensions. ```json { "type": "https://www.honestui.com/docs/developers#registry-item-not-found", "title": "Registry item not found", "status": 404, "detail": "No public Honest UI registry item is named \"missing-item\".", "instance": "https://www.honestui.com/api/v1/registry/missing-item", "code": "REGISTRY_ITEM_NOT_FOUND", "message": "Registry item not found", "resolution": "GET /api/v1/registry to find a valid item name." } ``` Clients should branch on the HTTP status and `code`, not parse the human-readable `detail`, `message`, or `resolution` strings. ### Registry item not found `REGISTRY_ITEM_NOT_FOUND` uses HTTP 404 when no public registry item matches the requested name. Retrieve `/api/v1/registry` before retrying with a valid name. ### Invalid preset configuration `INVALID_PRESET_CONFIGURATION` uses HTTP 400 when an `/api/v1/init` query parameter has an unsupported value. Read `/openapi.json` for the accepted values. ### Invalid only value `INVALID_ONLY_VALUE` uses HTTP 400 when the `only` query parameter contains a registry subset other than `theme`, `font`, or `fonts`. ### API route not found `API_ROUTE_NOT_FOUND` uses HTTP 404 when the requested `/api/v1` path is not part of the published contract. Start at `/api/v1` or inspect `/openapi.json`. ### Method not allowed `API_METHOD_NOT_ALLOWED` uses HTTP 405 when a client sends a modifying method to a read-only resource. The response includes `Allow: GET, HEAD`. ## Versioning and compatibility Honest UI versions the REST API in the URL path. The current major version is `v1`. Additive fields and endpoints may be introduced within `v1`; clients should ignore JSON object members they do not recognize. A change that removes or renames a documented field or changes its meaning requires a new major path such as `/api/v2`. The `X-Api-Version` response header identifies the major version. The OpenAPI `info.version` field identifies the contract release within that major version. ## Deprecation policy No `/api/v1` endpoint is currently deprecated or scheduled for retirement. Every versioned API response links to this policy with `Link: ; rel="deprecation"; type="text/html"`. When an endpoint is scheduled for deprecation, Honest UI will add the RFC 9745 `Deprecation` header using its Structured Field date syntax and publish a migration guide with the replacement and effective date. If a deprecated endpoint is scheduled to stop responding, Honest UI will also send the RFC 8594 `Sunset` header with that retirement date. A Sunset date will never be earlier than its Deprecation date. Until those headers and dates are published, clients should not infer a retirement date. ## Agent-readable resources - [OpenAPI specification](/openapi.json) - [Documentation index](/llms.txt) - [Full documentation snapshot](/llms-full.txt) - [Honest UI agent skill](/skill.md) - [Agent Skills discovery index](/.well-known/agent-skills/index.json) - [XML sitemap](/sitemap.xml) Use the [GitHub repository](https://github.com/honestui/honestui) to report a contract or documentation problem. --- ## Examples > Complete interfaces built with Honest UI components. Source: https://www.honestui.com/docs/examples Markdown: https://www.honestui.com/docs/examples.md --- title: Examples description: Complete interfaces built with Honest UI components. --- --- ## Get Started > Set up Honest UI, add a component, and verify the files in your project. Source: https://www.honestui.com/docs/get-started Markdown: https://www.honestui.com/docs/get-started.md --- title: Get Started description: Set up Honest UI, add a component, and verify the files in your project. --- Set up Honest UI, add a Button, and confirm that its source is part of your project. The CLI creates the shared configuration, copies component files, and installs the dependencies they need. ## Before you start Run this guide from the root of an existing project with: - Node.js 20.18.1 or later. - React 19. - Tailwind CSS v4. - A global stylesheet, such as `app/globals.css`. The CLI detects supported project structures and asks where shared styles and copied files should go. You can use aliases such as `@/components` and `@/lib`, but the exact aliases are your choice. ## 1. Initialize Honest UI Run: ```bash npx honestui@latest init ``` The CLI creates `components.json`, records your aliases and stylesheet path, and installs the base styles and dependencies used by copied components. Review the prompts before accepting them because they determine where later components are written. If `components.json` already exists, the CLI asks before replacing it. Review the current file and commit or save your work before choosing to overwrite it. ## 2. Add your first component Add Button after initialization: ### npm ```bash npx honestui@latest add button ``` ### yarn ```bash yarn dlx honestui@latest add button ``` ### bun ```bash bunx --bun honestui@latest add button ``` ### pnpm ```bash pnpm dlx honestui@latest add button ``` ### shadcn ```bash npx shadcn@latest add @honestui/button ``` The CLI shows the files and packages it plans to add. To inspect the change without writing files, run: ```bash npx honestui@latest add button --dry-run ``` With the common `@/components/ui` alias, the copied source is available from `@/components/ui/button`. Your configured path may differ. ## 3. Render the component ```tsx import { Button } from "@/components/ui/button" export function SaveProfileButton() { return } ``` Start your application and confirm that: - The button renders with the base styles. - The focus indicator is visible when you reach it with `Tab`. - The copied component file is present at the path configured in `components.json`. You can now edit the component source and its variants as normal project code. ## Add more UI components Every component page includes its CLI name. For example: ### npm ```bash npx honestui@latest add dialog select tabs ``` ### yarn ```bash yarn dlx honestui@latest add dialog select tabs ``` ### bun ```bash bunx --bun honestui@latest add dialog select tabs ``` ### pnpm ```bash pnpm dlx honestui@latest add dialog select tabs ``` ### shadcn ```bash npx shadcn@latest add @honestui/dialog @honestui/select @honestui/tabs ``` Start with [Field](/docs/components/field) and the specific controls you need for forms. Use [Dialog](/docs/components/dialog) for focused work, [Table](/docs/components/table) for tabular data, and [Toast](/docs/components/toast) for brief, noncritical feedback. ## Install manually Use manual installation when you want to review and place every file yourself: 1. Open the component page. 2. Select the manual installation tab. 3. Copy the component source and any supporting files. 4. Install the listed dependencies. 5. Confirm that the shared Honest UI styles are available. 6. Update imports to match your aliases. 7. Test the rendered component and its keyboard behavior. Copy the complete component structure. Removing labels, descriptions, focus handling, or primitive parts can change its behavior and accessibility. ## Package-based collections The component CLI is not the installation path for every Honest UI collection. Charts, icons, logos, vectors, and shaders are installed from the `honestui` package and imported through dedicated entry points. | Collection | Next step | | --- | --- | | Charts | [Install charts](/docs/charts/installation) | | Icons, logos, and vectors | [Install visual assets](/docs/icons/installation) | | Shaders | [Install shaders](/docs/shaders/installation) | Read [Theme](/docs/theme/overview) before changing shared tokens, [Styling](/docs/styling) before changing copied component classes, and [Accessibility](/docs/accessibility) before changing component semantics or interaction behavior. --- ## Introduction > Understand what Honest UI provides, how the code is distributed, and where to begin. Source: https://www.honestui.com/docs Markdown: https://www.honestui.com/docs.md --- title: Introduction description: Understand what Honest UI provides, how the code is distributed, and where to begin. --- **Good interfaces. Honest code.** Honest UI gives you thoughtful React components, charts, icons, and visual effects that you can adapt to your product. UI components are copied into your project, while charts, icons, logos, vectors, and shaders remain package dependencies with explicit entry points. You can edit copied component source directly and choose which parts to keep. ## Choose what you need Honest UI uses two distribution models. Check a feature's installation page before you begin so you know whether its source will be copied or imported from the package. | Collection | How you add it | Where it lives | | --- | --- | --- | | UI components | Honest UI CLI | Copied into your project | | Animated components | Honest UI CLI | Copied into your project | | Charts | `honestui/charts` | Installed package dependency | | Icons | `honestui/icons` | Installed package dependency | | Logos | `honestui/logos` | Installed package dependency | | Vectors | `honestui/vectors` | Installed package dependency | | Shaders | `honestui/shaders` | Installed package dependency | Copied components can be edited, renamed, or removed like any other project file. Package entry points keep larger collections available through named imports without copying every source file into your application. ## What we live by - **Good defaults, without giving up control.** Start with a considered implementation, then change it to fit your product. - **Clear code over clever abstractions.** The code should explain its structure and behavior to the people maintaining it. - **Useful design over unnecessary decoration.** Components and effects should support a task or communicate meaning. - **Accessibility from the start.** Native HTML and accessible primitives provide a foundation; your content and composition still matter. - **No lock-in. You own the code.** Copied component source stays in your project, and package features use explicit entry points. - **Quality over hype.** The docs state what the code does, where its limits are, and what you still need to verify. ## Start here Use [Get Started](/docs/get-started) to initialize an existing React project and add your first UI component. Then use the collection that matches your task: - [Components](/docs/component-guide) explains how to choose, install, and adapt interface components. - [Theme](/docs/theme/overview) explains the color, typography, spacing, radius, and effects shared by UI components. - [Animated components](/docs/animated) adds motion where it clarifies state, direction, or spatial relationships. - [Charts](/docs/charts) provides composable ECharts-based visualizations. - [Icons, logos, and vectors](/docs/icons) provides React SVG assets through dedicated package entry points. - [Shaders](/docs/shaders) provides progressive-enhancement effects for expressive surfaces. Each component page includes the smallest useful example, installation instructions, component anatomy, accessibility responsibilities, and examples for important states when they apply. ## Accessibility is shared work Honest UI provides native elements and interaction primitives where they fit. A component cannot make an entire application accessible by itself. You are still responsible for meaningful labels, logical focus order, useful validation, sufficient contrast, equivalent access to information, and testing the assembled task. Read [Accessibility](/docs/accessibility) before changing semantics, keyboard behavior, focus management, validation, or motion. ## Open source Honest UI is available under the MIT license. Read the [Contributing Guide](/docs/contributing) to report a problem, improve the documentation, or propose a focused change. --- ## Styling > Customize Honest UI's semantic CSS tokens, themes, and copied component classes. Source: https://www.honestui.com/docs/styling Markdown: https://www.honestui.com/docs/styling.md --- title: Styling description: Customize Honest UI's semantic CSS tokens, themes, and copied component classes. --- Honest UI separates visual decisions into CSS tokens and component classes. Tokens keep shared decisions consistent; copied component files give you local control when one component needs to change. For the complete token reference, start with [Theme](/docs/theme/overview), then open the page for [colors](/docs/theme/colors), [typography](/docs/theme/typography), [spacing](/docs/theme/spacing), [radius](/docs/theme/radius), or [effects](/docs/theme/effects). This page focuses on deciding where a customization belongs. ## Install the shared styles The `init` command installs the shared style setup and records the stylesheet path in `components.json`: ```bash npx honestui@latest init ``` Run initialization once before adding UI components. If the project is already initialized, inspect `components.json` instead of replacing it. ## How the token system works Every Honest UI token starts with `--hui-`; `hui` stands for Honest UI. Tokens are organized from low-level values to semantic roles: | Layer | Examples | Use it for | | --- | --- | --- | | Primitive colors | `--hui-neutral-9`, `--hui-accent-10` | Building or replacing a palette | | Semantic colors | `--hui-color-background-base-primary`, `--hui-color-foreground-danger-primary` | Styling components by purpose | | Spacing | `--hui-space-3`, `--hui-space-6` | Gaps, padding, and layout rhythm | | Radius | `--hui-radius-2`, `--hui-radius-full` | Corners and pill shapes | | Typography | `--hui-font-body`, `--hui-font-size-regular` | Type families, sizes, and weights | | Effects | `--hui-shadow-floating`, `--hui-focus-ring` | Elevation and focus visibility | Components should normally use semantic tokens rather than primitive palette values. For example, a destructive action uses a danger role so the component remains meaningful when the palette changes. ## Use tokens in Tailwind Copied Honest UI components pass tokens through Tailwind CSS arbitrary-value utilities. Use the same pattern in your own component code: ```tsx
``` The same classes resolve in light and dark themes because the browser reads the current variable values. Tailwind v4 also supports shorter custom-property syntax and optional semantic aliases; see [Tailwind CSS](/docs/theme/tailwind) for the complete guidance. ## Light and dark themes Theme values are scoped with `data-theme`: ```html ``` Switch the value to `dark` for the dark theme. If you use a theme library, configure it to write the same `data-theme` values. The primitive gray and accent scales resolve differently for each theme, while semantic roles keep their names. A component can therefore continue using `--hui-color-background-base-primary` without knowing which theme is active. ## Change the palette Set theme and palette attributes on a shared ancestor: ```html ``` Change primitive palette values when you are adapting the entire system. Change semantic values when your product needs a different meaning for a role. Keep semantic token names stable when possible. Changing a token's value updates every component that uses that role; renaming it requires updating each reference. ## Customize one component Copied UI components are normal source files. Edit their class names when a change belongs to one component: ```tsx ``` Add or adjust a variant when the same option must be reused. Do not create a new shared token for a single isolated value unless it represents a product-wide decision. ## Check every state After changing tokens or classes, verify: - Default, hover, active, focus, disabled, and invalid states. - Light and dark themes. - Text and non-text contrast. - Focus visibility in keyboard use. - Meaning without color alone. - Content at 200% and 400% zoom or equivalent reflow. - Forced-colors behavior where the component supports system colors. Use text, icons, labels, or patterns alongside color when a state must be understood. A new palette should not turn warning, success, or destructive states into color-only distinctions. --- ## Action Swap > Cycle an action's label and icon with blur, roll, or letter-cascade transitions. Source: https://www.honestui.com/docs/animated/action-swap Markdown: https://www.honestui.com/docs/animated/action-swap.md --- title: Action Swap description: Cycle an action's label and icon with blur, roll, or letter-cascade transitions. links: github: https://github.com/honestui/honestui/blob/main/registry/default/animated/action-swap.tsx --- ```tsx "use client"; import { Bell, BellOff, Volume2 } from "lucide-react"; import { ActionSwapButton } from "@/registry/default/animated/action-swap"; const items = [ { id: "every-update", label: "Every update", icon: }, { id: "priority-only", label: "Priority only", icon: }, { id: "paused", label: "Alerts paused", icon: }, ]; export function ActionSwapDemo() { return (
); } ``` ## Overview Use Action Swap when one compact control moves through a small, predictable set of related modes. The button can animate its label, icon, or both while preserving a stable hit target. ## Installation ### npm ```bash npx honestui@latest add action-swap ``` ### yarn ```bash yarn dlx honestui@latest add action-swap ``` ### bun ```bash bunx --bun honestui@latest add action-swap ``` ### pnpm ```bash pnpm dlx honestui@latest add action-swap ``` ### shadcn ```bash npx shadcn@latest add @honestui/action-swap ``` ## Usage ```tsx import { ActionSwapButton } from "@/components/animated/action-swap" const items = [ { id: "digest", label: "Daily digest" }, { id: "paused", label: "Digest paused" }, ] ``` Use `ActionSwapText` and `ActionSwapIcon` directly when another control owns the interaction. The `action-swap-blur`, `action-swap-roll`, and `action-swap-cascade` entry points provide fixed-animation wrappers. ## Accessibility Keep every state label specific. Icon-only items need an `ariaLabel`. Reduced-motion users receive an immediate, legible state change without the full transition. ## API Reference ### `items` (required) type: `ActionSwapItem[]` Ordered states with an `id`, visible `label`, optional `icon`, and optional `ariaLabel`. ### `value` type: `string` Controlled active item id. ### `defaultValue` type: `string` Initial item id for uncontrolled use. ### `onValueChange` void">Runs after the active item changes. ### `animation` type: `"blur" | "roll" | "cascade"` · default: `"blur"` Transition used for the label and icon. ### `variant` type: `"primary" | "secondary" | "outline" | "ghost"` · default: `"secondary"` Visual emphasis of the button. ### `size` type: `"sm" | "md" | "lg" | "icon"` · default: `"md"` Button size. ### `cycle` type: `boolean` · default: `true` Advances to the next item when clicked. --- ## Bouncy Accordion > A connected accordion whose rows separate and settle around expanded content. Source: https://www.honestui.com/docs/animated/bouncy-accordion Markdown: https://www.honestui.com/docs/animated/bouncy-accordion.md --- title: Bouncy Accordion description: A connected accordion whose rows separate and settle around expanded content. --- ```tsx import { Bell, CreditCard, ShieldCheck } from "lucide-react"; import { BouncyAccordion } from "@/registry/default/animated/bouncy-accordion"; const items = [ { id: "payment", title: "Payment method", description: "Change the card used for your team plan and future renewals.", icon: , }, { id: "security", title: "Security checks", description: "Review sign-in devices, backup codes, and account recovery.", icon: , }, { id: "email-updates", title: "Email updates", description: "Choose which team activity and weekly summaries you receive.", icon: , }, ]; export function BouncyAccordionDemo() { return ( ); } ``` ## Overview Use Bouncy Accordion for a short list of mutually exclusive details. Opening a row separates it from its neighbors and reveals its content with coordinated layout motion. ## Installation ### npm ```bash npx honestui@latest add bouncy-accordion ``` ### yarn ```bash yarn dlx honestui@latest add bouncy-accordion ``` ### bun ```bash bunx --bun honestui@latest add bouncy-accordion ``` ### pnpm ```bash pnpm dlx honestui@latest add bouncy-accordion ``` ### shadcn ```bash npx shadcn@latest add @honestui/bouncy-accordion ``` ## Usage ```tsx import { BouncyAccordion } from "@/components/animated/bouncy-accordion" ``` ## Accessibility Each row uses a button with `aria-expanded` and `aria-controls`; the panel is a labeled region. Disabled rows stay out of the interaction path, and reduced motion removes spring movement. ## API Reference ### `items` (required) type: `BouncyAccordionItem[]` Rows with `id`, `title`, optional `description`, `icon`, and `disabled`. ### `value` type: `string | null` Controlled open row. ### `defaultValue` type: `string | null` · default: `null` Initially open row. ### `onValueChange` void">Runs when the open row changes. ### `collapsible` type: `boolean` · default: `true` Lets the open row close without opening another. ### `classNames` type: `BouncyAccordionClassNames` Classes for the root, item, trigger, icon, title, chevron, content, and description slots. --- ## Chromatic Text Reveal > Reveal rotating words with a moving multicolor edge. Source: https://www.honestui.com/docs/animated/chromatic-text-reveal Markdown: https://www.honestui.com/docs/animated/chromatic-text-reveal.md --- title: Chromatic Text Reveal description: Reveal rotating words with a moving multicolor edge. --- ```tsx import { ChromaticTextReveal } from "@/registry/default/animated/chromatic-text-reveal"; export function ChromaticTextRevealDemo() { return ( ); } ``` ## Overview Chromatic Text Reveal keeps a sentence prefix fixed while revealing a sequence of final words. Use it for a focused product statement, not for essential instructions or rapidly changing status. ## Installation ### npm ```bash npx honestui@latest add chromatic-text-reveal ``` ### yarn ```bash yarn dlx honestui@latest add chromatic-text-reveal ``` ### bun ```bash bunx --bun honestui@latest add chromatic-text-reveal ``` ### pnpm ```bash pnpm dlx honestui@latest add chromatic-text-reveal ``` ### shadcn ```bash npx shadcn@latest add @honestui/chromatic-text-reveal ``` ## Usage ```tsx import { ChromaticTextReveal } from "@/components/animated/chromatic-text-reveal" ``` ## Accessibility The current full word remains available to assistive technology while visual gradient layers are hidden. Reduced motion shows the word without the sweep. ## API Reference ### `prefix` (required) type: `string` Text that remains fixed. ### `words` (required) type: `string[]` Words revealed in order. ### `colors` type: `string[]` Colors along the reveal edge. ### `duration` type: `number` · default: `1.2` Sweep duration in seconds. ### `pauseDuration` type: `number` · default: `0.8` Rest between words in seconds. ### `loop` type: `boolean` · default: `true` Returns to the first word. ### `startOnView` type: `boolean` · default: `true` Waits until the text enters the viewport. ### `once` type: `boolean` · default: `true` Observes only the first viewport entry. --- ## Dock > A compact action dock with a shared animated active indicator. Source: https://www.honestui.com/docs/animated/dock Markdown: https://www.honestui.com/docs/animated/dock.md --- title: Dock description: A compact action dock with a shared animated active indicator. --- ```tsx "use client"; import { Bell, Home, Search, Settings } from "lucide-react"; import { useState } from "react"; import { Dock, DockItem, DockSeparator } from "@/registry/default/animated/dock"; const items = [ { id: "dashboard", label: "Dashboard", icon: Home }, { id: "browse", label: "Browse", icon: Search }, { id: "updates", label: "Updates", icon: Bell }, ]; export function DockDemo() { const [active, setActive] = useState("dashboard"); return ( {items.map(({ id, label, icon: Icon }) => ( setActive(id)} aria-label={label}> ))} setActive("preferences")} active={active === "preferences"} aria-label="Preferences"> ); } ``` ## Overview Dock groups a small set of high-frequency destinations or actions. The active pill moves between items using shared-layout motion while item dimensions remain stable. ## Installation ### npm ```bash npx honestui@latest add dock ``` ### yarn ```bash yarn dlx honestui@latest add dock ``` ### bun ```bash bunx --bun honestui@latest add dock ``` ### pnpm ```bash pnpm dlx honestui@latest add dock ``` ### shadcn ```bash npx shadcn@latest add @honestui/dock ``` ## Usage ```tsx import { Dock, DockItem, DockSeparator } from "@/components/animated/dock" ``` ## Accessibility Items with `onClick` render as buttons and expose `aria-pressed` for the active state. Icon-only items require an `aria-label`. Keep the dock to a short, recognizable action set. ## API Reference ### `size` type: `number` · default: `44` Width and height of each Dock Item in pixels. ### `active` type: `boolean` Shows the shared active indicator. ### `onClick` void">Renders the item as a button and handles activation. ### `aria-label` type: `string` Accessible name for an icon-only item. --- ## Animated Components > Copied React components that use motion to clarify state and spatial change. Source: https://www.honestui.com/docs/animated Markdown: https://www.honestui.com/docs/animated.md --- title: Animated Components description: Copied React components that use motion to clarify state and spatial change. image: /og/og-image.png --- Animated components add movement to state changes, spatial relationships, progress, and direct manipulation. The CLI copies their source into your project so you can change the timing, styling, fallback, or remove the effect entirely. ## Use motion for a reason Choose an animated component when movement helps people understand what changed or where an element went. Avoid adding motion only to make a static surface feel busier. The collection includes: - State and label transitions for compact actions. - Layout motion for disclosures and active indicators. - Text and number reveals for short, deliberate moments. - Pointer-responsive effects for optional visual emphasis. - Repeating movement for nonessential ambient content. ## Accessibility responsibilities Components document their reduced-motion behavior and preserve native semantics where they own an interactive element. The application is still responsible for meaningful labels, visible focus, keyboard operation, readable status updates, and ensuring that motion is not the only way to understand a change. Pointer-responsive effects must remain optional. Their content and actions need to work on touch devices, with a keyboard, and when reduced motion is enabled. ## Choose carefully - Use **Action Swap** when one compact action moves through a small set of named states. - Use **Bouncy Accordion** when opening one disclosure should explain a layout change. - Use **Number Ticker** for occasional metric changes, not rapid critical updates. - Use **Text Shimmer** for a short in-progress label with a separate programmatic busy state. - Use **Magnetic** or **Tilt Card** only as progressive visual enhancement. - Use **Marquee** only for nonessential content that remains understandable when the loop stops. ## Get started Follow [Installation](/docs/animated/installation), then open a component page to review its purpose, reduced-motion behavior, and API before adding it. --- ## Installation > Copy an animated component into your project and verify its fallback behavior. Source: https://www.honestui.com/docs/animated/installation Markdown: https://www.honestui.com/docs/animated/installation.md --- title: Installation metaTitle: Install animated components description: Copy an animated component into your project and verify its fallback behavior. --- Animated components use the same CLI as Honest UI components. The CLI copies the selected source and supporting utilities into your project, then installs dependencies such as Motion when required. ## Requirements - Node.js 20.18.1 or later. - React 19. - Tailwind CSS v4. - An initialized Honest UI project. If the project does not have `components.json`, initialize it first: ```bash npx honestui@latest init ``` ## Add a component Pass the component name to the CLI: ### npm ```bash npx honestui@latest add text-reveal ``` ### yarn ```bash yarn dlx honestui@latest add text-reveal ``` ### bun ```bash bunx --bun honestui@latest add text-reveal ``` ### pnpm ```bash pnpm dlx honestui@latest add text-reveal ``` ### shadcn ```bash npx shadcn@latest add @honestui/text-reveal ``` The default animated-component alias writes source under `components/animated`. Supporting easing functions or input-capability helpers use the `lib` or `hooks` aliases in `components.json`. Review the reported files and dependencies before committing. You can edit the installed source directly. ## Dependencies Most animated components use Motion for React. The CLI installs it when the selected registry item requires it. For manual installation: ```bash npm install motion ``` Components that render icons may also require the icon dependency listed in their manual installation instructions. ## Verify the result After adding a component: 1. Render its smallest usage example. 2. Confirm the content is understandable before, during, and after the transition. 3. Test the interaction with a keyboard when it is interactive. 4. Enable reduced motion in the operating system and confirm the documented fallback. 5. Test touch behavior for pointer-responsive components. 6. Confirm that disabling animation does not remove content, status, or an action. If you change an effect, preserve or improve the fallback described on that component's page. --- ## Magnetic > Add subtle pointer attraction to a child element. Source: https://www.honestui.com/docs/animated/magnetic Markdown: https://www.honestui.com/docs/animated/magnetic.md --- title: Magnetic description: Add subtle pointer attraction to a child element. --- ```tsx import { ArrowUpRight } from "lucide-react"; import { Magnetic } from "@/registry/default/animated/magnetic"; export function MagneticDemo() { return ( ); } ``` ## Overview Magnetic is a decorative wrapper that moves toward a fine pointer while hovered. Use it sparingly for prominent actions where the attraction supports focus without changing layout. ## Installation ### npm ```bash npx honestui@latest add magnetic ``` ### yarn ```bash yarn dlx honestui@latest add magnetic ``` ### bun ```bash bunx --bun honestui@latest add magnetic ``` ### pnpm ```bash pnpm dlx honestui@latest add magnetic ``` ### shadcn ```bash npx shadcn@latest add @honestui/magnetic ``` ## Usage ```tsx import { Magnetic } from "@/components/animated/magnetic" ``` ## Accessibility The effect disables itself for touch input and reduced motion. The child remains responsible for semantics, focus styling, accessible naming, and keyboard behavior. ## API Reference ### `children` (required) type: `ReactNode` Element that follows the pointer. ### `strength` type: `number` · default: `0.35` Fraction of the pointer offset applied to the child. ### `className` type: `string` Class for the motion wrapper. --- ## Marquee > Loop a row or column of content with optional fade and hover pause. Source: https://www.honestui.com/docs/animated/marquee Markdown: https://www.honestui.com/docs/animated/marquee.md --- title: Marquee description: Loop a row or column of content with optional fade and hover pause. --- ```tsx import { Marquee } from "@/registry/default/animated/marquee"; const items = ["Clear by default", "Motion aware", "Easy to adapt", "Built in React", "Ready for touch"]; export function MarqueeDemo() { return ( {items.map((item) => ( {item} ))} ); } ``` ## Overview Use Marquee for non-essential collections such as partner marks, short tags, or ambient highlights. It duplicates a static set to create a seamless CSS loop. ## Installation ### npm ```bash npx honestui@latest add marquee ``` ### yarn ```bash yarn dlx honestui@latest add marquee ``` ### bun ```bash bunx --bun honestui@latest add marquee ``` ### pnpm ```bash pnpm dlx honestui@latest add marquee ``` ### shadcn ```bash npx shadcn@latest add @honestui/marquee ``` ## Usage ```tsx import { Marquee } from "@/components/animated/marquee" {items.map((item) => {item})} ``` ## Accessibility The duplicate track is hidden from assistive technology, hover can pause the loop, and reduced-motion preferences stop the animation. Never place time-sensitive or uniquely actionable content only inside a marquee. ## API Reference ### `direction` type: `"left" | "right" | "up" | "down"` · default: `"left"` Movement direction. ### `speed` type: `number` · default: `30` Loop duration in seconds. ### `pauseOnHover` type: `boolean` · default: `true` Pauses while the pointer is over the marquee. ### `gap` type: `string` · default: `"1rem"` Space between items and tracks. ### `fade` type: `boolean` · default: `true` Fades the leading and trailing edges. --- ## Number Ticker > Roll changing digits independently while preserving place value. Source: https://www.honestui.com/docs/animated/number-ticker Markdown: https://www.honestui.com/docs/animated/number-ticker.md --- title: Number Ticker description: Roll changing digits independently while preserving place value. --- ```tsx "use client"; import { useState } from "react"; import { NumberTicker } from "@/registry/default/animated/number-ticker"; export function NumberTickerDemo() { const [value, setValue] = useState(8360); return ( ); } ``` ## Overview Number Ticker animates each numeric place without re-keying the rest of the value. Use it for metrics whose changes matter, such as balances, counts, scores, or progress totals. ## Installation ### npm ```bash npx honestui@latest add number-ticker ``` ### yarn ```bash yarn dlx honestui@latest add number-ticker ``` ### bun ```bash bunx --bun honestui@latest add number-ticker ``` ### pnpm ```bash pnpm dlx honestui@latest add number-ticker ``` ### shadcn ```bash npx shadcn@latest add @honestui/number-ticker ``` ## Usage ```tsx import { NumberTicker } from "@/components/animated/number-ticker" ``` ## Accessibility Assistive technology receives the complete formatted value instead of individual visual digits. Keep updates at a readable pace and avoid using rapid rolls for critical live data. ## API Reference ### `value` (required) type: `number` Value to display, rounded to an integer. ### `pad` type: `number` Minimum number of digits. ### `duration` type: `number` · default: `0.9` Per-digit roll duration in seconds. ### `stagger` type: `number` · default: `0.04` Delay between digit places. ### `prefix` type: `string` Text before the value. ### `suffix` type: `string` Text after the value. ### `locale` type: `boolean` Adds locale group separators. ### `blur` type: `boolean` · default: `false` Adds a small blur during rolls. --- ## Shared Layout Background > Move one hover background between related rows. Source: https://www.honestui.com/docs/animated/shared-layout-bg Markdown: https://www.honestui.com/docs/animated/shared-layout-bg.md --- title: Shared Layout Background description: Move one hover background between related rows. --- ```tsx import { ArrowUpRight } from "lucide-react"; import { SharedLayoutBg } from "@/registry/default/animated/shared-layout-bg"; const links = ["Guides", "Templates", "Changelog"]; export function SharedLayoutBgDemo() { return ( {links.map((label) => ( {label} ))} ); } ``` ## Overview Shared Layout Background adds a single animated pill behind hovered children. Use it to connect a small list of related navigation or action rows without changing their semantics. ## Installation ### npm ```bash npx honestui@latest add shared-layout-bg ``` ### yarn ```bash yarn dlx honestui@latest add shared-layout-bg ``` ### bun ```bash bunx --bun honestui@latest add shared-layout-bg ``` ### pnpm ```bash pnpm dlx honestui@latest add shared-layout-bg ``` ### shadcn ```bash npx shadcn@latest add @honestui/shared-layout-bg ``` ## Usage ```tsx import { SharedLayoutBg } from "@/components/animated/shared-layout-bg" {links.map((link) => )} ``` ## Accessibility The moving background is decorative. Children must provide their own focus indicators, labels, roles, and activation behavior. Reduced motion swaps the background without traveling between rows. ## API Reference ### `children` (required) type: `ReactNode` Rows that receive hover tracking. ### `pillClassName` type: `string` Class applied to the moving pill. ### `inset` type: `number` · default: `20` Horizontal pill inset relative to each row, in pixels. --- ## Text Reveal > Reveal text by word or character with stagger, blur, and spring motion. Source: https://www.honestui.com/docs/animated/text-reveal Markdown: https://www.honestui.com/docs/animated/text-reveal.md --- title: Text Reveal description: Reveal text by word or character with stagger, blur, and spring motion. --- ```tsx import { TextReveal } from "@/registry/default/animated/text-reveal"; export function TextRevealDemo() { return ( ); } ``` ## Overview Text Reveal introduces one or more lines in reading order. Use word splitting for headings and statements; reserve character splitting for short decorative text. ## Installation ### npm ```bash npx honestui@latest add text-reveal ``` ### yarn ```bash yarn dlx honestui@latest add text-reveal ``` ### bun ```bash bunx --bun honestui@latest add text-reveal ``` ### pnpm ```bash pnpm dlx honestui@latest add text-reveal ``` ### shadcn ```bash npx shadcn@latest add @honestui/text-reveal ``` ## Usage ```tsx import { TextReveal } from "@/components/animated/text-reveal" ``` ## Accessibility The content remains real text in document order. Reduced motion keeps a short opacity transition, and `whileInView` can defer the effect until the text is visible. ## API Reference ### `text` (required) type: `string | string[]` One line or an ordered list of lines. ### `as` type: `ElementType` · default: `"span"` Rendered element. ### `split` type: `"word" | "char"` · default: `"word"` Animation unit. ### `stagger` type: `number` · default: `0.09` Delay between units. ### `delay` type: `number` · default: `0` Delay before the first unit. ### `blur` type: `number` · default: `12` Starting blur in pixels. ### `yOffset` type: `string | number` · default: `"40%"` Starting vertical offset. ### `whileInView` type: `boolean` · default: `false` Waits for viewport entry. --- ## Text Shimmer > Sweep a theme-aware highlight through a short text label. Source: https://www.honestui.com/docs/animated/text-shimmer Markdown: https://www.honestui.com/docs/animated/text-shimmer.md --- title: Text Shimmer description: Sweep a theme-aware highlight through a short text label. --- ```tsx import { TextShimmer } from "@/registry/default/animated/text-shimmer"; export function TextShimmerDemo() { return Preparing your workspace…; } ``` ## Overview Text Shimmer is a lightweight CSS effect for short, temporary states such as generation or loading labels. It inherits theme colors and does not require Motion. ## Installation ### npm ```bash npx honestui@latest add text-shimmer ``` ### yarn ```bash yarn dlx honestui@latest add text-shimmer ``` ### bun ```bash bunx --bun honestui@latest add text-shimmer ``` ### pnpm ```bash pnpm dlx honestui@latest add text-shimmer ``` ### shadcn ```bash npx shadcn@latest add @honestui/text-shimmer ``` ## Usage ```tsx import { TextShimmer } from "@/components/animated/text-shimmer" Preparing your workspace… ``` ## Accessibility Use direct status text and pair ongoing work with `aria-busy` on the affected region when appropriate. The shimmer stops for reduced-motion preferences. ## API Reference ### `children` (required) type: `ReactNode` Text content. ### `as` type: `ElementType` · default: `"span"` Rendered element. ### `duration` type: `number` · default: `2.5` Sweep duration in seconds. ### `className` type: `string` Text and layout classes. --- ## Tilt Card > Add pointer-responsive perspective and optional glare to a card. Source: https://www.honestui.com/docs/animated/tilt-card Markdown: https://www.honestui.com/docs/animated/tilt-card.md --- title: Tilt Card description: Add pointer-responsive perspective and optional glare to a card. --- ```tsx import { ArrowUpRight } from "lucide-react"; import { TiltCard } from "@/registry/default/animated/tilt-card"; export function TiltCardDemo() { return (
Spotlight

Motion systems

A gentle layer of depth that responds as you explore the card.

); } ``` ## Overview Tilt Card provides a restrained depth cue for visual or featured content. Its children remain normal document content while the wrapper handles perspective and glare. ## Installation ### npm ```bash npx honestui@latest add tilt-card ``` ### yarn ```bash yarn dlx honestui@latest add tilt-card ``` ### bun ```bash bunx --bun honestui@latest add tilt-card ``` ### pnpm ```bash pnpm dlx honestui@latest add tilt-card ``` ### shadcn ```bash npx shadcn@latest add @honestui/tilt-card ``` ## Usage ```tsx import { TiltCard } from "@/components/animated/tilt-card" ``` ## Accessibility Pointer tilt and glare disable themselves for touch and reduced motion. The card's content must remain understandable and operable without the effect. ## API Reference ### `children` (required) type: `ReactNode` Card content. ### `max` type: `number` · default: `12` Maximum rotation in degrees. ### `glare` type: `boolean` · default: `true` Shows a pointer-positioned highlight. ### `className` type: `string` Card surface and layout classes. --- ## Chart Config > Define labels, theme colors, and icons for each chart series. Source: https://www.honestui.com/docs/charts/chart-config Markdown: https://www.honestui.com/docs/charts/chart-config.md --- title: Chart Config description: Define labels, theme colors, and icons for each chart series. image: /og/chart-config.png --- Every Honest UI chart accepts a `config` prop. Pass it a `ChartConfig` object that maps data keys to visible labels, theme colors, and optional icons used by tooltips and legends. ## Structure ```tsx import { type ChartConfig } from "honestui/charts"; const chartConfig = { harvested: { label: "Harvested", icon: WheatIcon, colors: { light: ["#047857"], dark: ["#10b981"], }, }, packed: { label: "Packed", icon: PackageCheckIcon, colors: { light: ["#be123c"], dark: ["#f43f5e"], }, }, } satisfies ChartConfig; ``` Each key, such as `harvested` or `packed`, must match a data key used by the corresponding series. The object has this type: ```tsx type ChartConfig = Record< string, { label?: React.ReactNode; icon?: React.ComponentType; colors?: { light?: string[]; dark?: string[]; }; } >; ``` ## Properties ### label The name shown in tooltips and legends. Use a concise label that makes sense outside the chart. ```tsx const chartConfig = { harvested: { label: "Harvested", // [!code highlight] // ... }, } satisfies ChartConfig; ``` ### colors Theme-aware color arrays. Provide at least one theme key (`light` or `dark`); each holds an array of CSS color strings. Use one color per theme for a solid fill: ```tsx colors: { light: ["#047857"], dark: ["#10b981"], } ``` Use multiple colors to create a gradient. The chart distributes the stops across the rendered series: ```tsx colors: { light: ["#a855f7", "#6366f1", "#3b82f6"], dark: ["#f43f5e", "#ec4899", "#a855f7", "#6366f1", "#3b82f6"], } ``` Light and dark themes may define different numbers of color stops. The chart uses the larger count when distributing them. ### icon An optional React component that replaces the default color indicator in the tooltip and legend. Icons can reinforce a distinction, but visible labels must still identify each series. ```tsx import { PackageCheck, Wheat } from "lucide-react"; const chartConfig = { harvested: { label: "Harvested", icon: Wheat, // [!code highlight] [!code word:Wheat] colors: { light: ["#047857"], dark: ["#10b981"] }, }, packed: { label: "Packed", icon: PackageCheck, // [!code highlight] [!code word:PackageCheck] colors: { light: ["#be123c"], dark: ["#f43f5e"] }, }, } satisfies ChartConfig; ``` The icon replaces the color indicator in tooltips and legends. Tooltips render it at `h-2.5 w-2.5`; legends render it at `h-3 w-3`. ## How Colors Work The chart config generates CSS custom properties scoped to each chart instance. A key `harvested` with colors `["#a855f7", "#6366f1"]` produces: ```css --color-harvested-0: #a855f7; --color-harvested-1: #6366f1; ``` Chart components, tooltips, and legends read these variables. When the application changes between the supported light and dark themes, the chart reads the corresponding values. ### Color Distribution When you provide fewer colors than segments need, they're **evenly distributed** across slots: - 2 colors for 4 slots: `[red, red, pink, pink]` - 3 colors for 4 slots: `[red, pink, blue, blue]` Use enough stops to communicate the intended progression, then verify the result with representative data in both themes. ## Runtime Validation The config is validated at runtime. An empty `colors` object, or one without a valid theme key, throws a clear error: ```plaintext [Honest UI] Invalid chart config for "harvested": colors object must have at least one theme key (light, dark). Received empty object or invalid keys. ``` ## Examples ### Default (Labels + Colors) Labels and theme-aware colors. The label shows in the tooltip and legend; the colors control the fill. ### With Icons Pass an `icon` component per entry to replace the default color indicator in the tooltip and legend. ### Gradient Colors Pass multiple colors per theme for gradient fills. Each array value is a stop distributed across the chart elements. ## API Reference ### `label` type: `React.ReactNode` Name for the data series, shown in tooltips and legends. ### `colors` type: `{ light?: string[]; dark?: string[] }` Theme-aware colors. Include at least one theme key (`light` or `dark`), each mapping to an array of CSS color strings. One color is a solid fill; multiple create a gradient. ### `icon` type: `React.ComponentType` Optional React component rendered in place of the default color indicator in tooltips and legends. --- ## Charts > Choose and compose Honest UI charts for product data. Source: https://www.honestui.com/docs/charts Markdown: https://www.honestui.com/docs/charts.md --- title: Charts description: Choose and compose Honest UI charts for product data. image: /og/og-image.png --- Honest UI charts are React components built on [Apache ECharts](https://echarts.apache.org/). Install them from `honestui/charts`, then compose the axes, series, legend, tooltip, and controls your visualization needs. Charts are package imports rather than CLI-copied UI components. You can inspect their source in the Honest UI repository and use ECharts options when the component API does not expose a setting directly. ## Choose a chart | Chart | Use it to | Use something else when | | --- | --- | --- | | Area | Show change over time when magnitude or contribution to a total matters | A filled area would make close comparisons harder | | Bar | Compare values across categories | The primary question is change over a continuous sequence | | Line | Show trends and rate of change across an ordered dimension | The data is unordered or category comparison matters more | | Pie or donut | Show a simple part-to-whole relationship with a few categories | Values are close, there are many categories, or precision matters | | Scatter | Find relationships, clusters, and outliers across numeric measures | One axis is categorical | | Heatmap | Find patterns across two categorical dimensions | Readers need frequent point-by-point comparison | ## How composition works The chart root owns the data, theme configuration, loading state, and selection. Add only the parts you need. For example: ```tsx ``` The child components describe ECharts configuration; they do not render separate DOM elements. Omitting a child removes that chart part. Use [Chart Config](/docs/charts/chart-config) to connect data keys to visible labels, colors, and optional icons. ## Canvas and performance ECharts renders the plot to canvas, avoiding one DOM element for every bar, point, or cell. That can reduce DOM size for dense visualizations, but performance still depends on the dataset, enabled interactions, animation, device, and surrounding application. Test representative data on the devices your product supports. ## Accessibility responsibilities A canvas can have an accessible name, but that name does not expose every plotted value or relationship. Provide a nearby summary or data table when people need to understand exact values, trends, outliers, or selections. Tooltips, brushes, and direct mark selection are pointer-operated unless your application supplies an equivalent control. Do not place required information or the only path to an action inside a canvas interaction. ## Get started Follow [Installation](/docs/charts/installation), define labels and colors in [Chart Config](/docs/charts/chart-config), and choose a chart based on the question the data must answer. --- ## Installation > Install Honest UI charts and render a verified first chart. Source: https://www.honestui.com/docs/charts/installation Markdown: https://www.honestui.com/docs/charts/installation.md --- title: Installation metaTitle: Install Honest UI charts description: Install Honest UI charts and render a verified first chart. image: /og/og-image.png --- Honest UI charts are available from the `honestui/charts` package entry point. Unlike CLI-installed UI components, charts remain an `honestui` package dependency. ## Requirements - Node.js 20.18.1 or later. - React 19. - A container with an explicit height or aspect ratio. ## Install ### npm ```bash npm install honestui ``` ### yarn ```bash yarn add honestui ``` ### bun ```bash bun add honestui ``` ### pnpm ```bash pnpm add honestui ``` ## Import Import chart roots, shared types, and chart-specific data types from the same entry point. ```tsx import { BarChart, type ChartConfig } from "honestui/charts" import "honestui/charts.css" ``` Load `honestui/charts.css` once in your application root. It contains only the utilities used by the chart package, so chart layout, loading states, tooltips, and keyboard-operable legends do not depend on your Tailwind content paths. ## Render a chart ```tsx const data = [ { month: "Jan", completed: 18 }, { month: "Feb", completed: 24 }, ] const chartConfig = { completed: { label: "Completed tasks", colors: { light: ["#2563eb"], dark: ["#60a5fa"] }, }, } satisfies ChartConfig export function CompletedTasksChart() { return ( ) } ``` Confirm that the chart has a visible height and that each `dataKey` exists in both the data rows and `chartConfig`. Add a visible summary or table if readers need the plotted values without pointer interaction. ## Next steps Choose a chart based on the comparison you need to show, then use [Chart Config](/docs/charts/chart-config) to define shared labels, colors, and icons. --- ## Accordion > Show related sections that people can expand and collapse as needed. Source: https://www.honestui.com/docs/components/accordion Markdown: https://www.honestui.com/docs/components/accordion.md --- title: Accordion description: Show related sections that people can expand and collapse as needed. links: doc: https://base-ui.com/react/components/accordion#api-reference --- ```tsx import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, } from "@/components/honest-ui/ui/accordion" const items = [ { id: "1", title: "What is Base UI?", content: "Base UI is a library of high-quality unstyled React components for design systems and web apps.", }, { id: "2", title: "How do I get started?", content: "Head to the \"Quick start\" guide in the docs. If you've used unstyled libraries before, you'll feel at home.", }, { id: "3", title: "Can I use it for my project?", content: "Of course! Base UI is free and open source.", }, ] export function AccordionDemo() { return ( {items.map((item) => ( {item.title} {item.content} ))} ) } ``` ## Overview Use an accordion when the page has related sections that should stay close together, but the user does not need to see every section at the same time. Accordions work well for settings, FAQs, filters, details panels, and long forms with optional sections. Avoid them when all content must be compared side by side. ## Anatomy An accordion is made from an accordion root, one or more items, a trigger for each item, and content for each panel. The trigger should clearly describe what will open. The content should be short enough that opening one panel does not make the page hard to scan. ## Behavior Use a single accordion when only one panel should be open. Use a multiple accordion when several panels can stay open at once. Use controlled state when the open panel needs to sync with routing, saved preferences, or another part of the page. ## Accessibility Keep triggers as real buttons, use clear headings, and make sure focus remains visible. Keyboard users should be able to tab to the trigger and open or close it with the keyboard. ## Installation ### npm ```bash npx honestui@latest add accordion ``` ### yarn ```bash yarn dlx honestui@latest add accordion ``` ### bun ```bash bunx --bun honestui@latest add accordion ``` ### pnpm ```bash pnpm dlx honestui@latest add accordion ``` ### shadcn ```bash npx shadcn@latest add @honestui/accordion ``` Install the following dependencies: ```bash npm install @base-ui-components/react ``` Copy and paste the following code into your project. ### components/ui/accordion.tsx ```tsx "use client" import { Accordion as AccordionPrimitive } from "@base-ui-components/react/accordion" import { ChevronDown as ChevronDownIcon } from "honestui/icons" import { cn } from "@/lib/utils" type AccordionValue = NonNullable type AccordionChangeDetails = AccordionPrimitive.Root.ChangeEventDetails type AccordionNativeProps = AccordionPrimitive.Root.Props & { collapsible?: boolean type?: undefined } type AccordionSingleProps = Omit< AccordionPrimitive.Root.Props, "defaultValue" | "multiple" | "onValueChange" | "value" > & { type: "single" collapsible?: boolean defaultValue?: string multiple?: false onValueChange?: (value: string, eventDetails: AccordionChangeDetails) => void value?: string } type AccordionMultipleProps = Omit< AccordionPrimitive.Root.Props, "defaultValue" | "multiple" | "onValueChange" | "value" > & { type: "multiple" collapsible?: boolean defaultValue?: AccordionValue multiple?: true onValueChange?: AccordionPrimitive.Root.Props["onValueChange"] value?: AccordionValue } type AccordionProps = | AccordionNativeProps | AccordionSingleProps | AccordionMultipleProps function Accordion({ collapsible, defaultValue, multiple, onValueChange, type, value, ...props }: AccordionProps) { const isSingle = type === "single" const resolvedMultiple = type ? type === "multiple" : multiple const normalizedDefaultValue: AccordionValue | undefined = isSingle && typeof defaultValue === "string" ? [defaultValue] : Array.isArray(defaultValue) ? defaultValue : undefined const normalizedValue: AccordionValue | undefined = isSingle && typeof value === "string" ? [value] : Array.isArray(value) ? value : undefined return ( { if (isSingle) { if (!collapsible && nextValue.length === 0) { eventDetails.cancel() return } onValueChange?.(nextValue[0] ?? "", eventDetails) } else { onValueChange?.(nextValue, eventDetails) } }} value={normalizedValue} {...props} /> ) } function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) { return ( ) } function AccordionTrigger({ className, children, ...props }: AccordionPrimitive.Trigger.Props) { return ( svg]:rotate-180", className )} {...props} > {children} ) } function AccordionPanel({ className, children, ...props }: AccordionPrimitive.Panel.Props) { return (
{children}
) } export { Accordion, AccordionItem, AccordionTrigger, AccordionPanel, AccordionPanel as AccordionContent, } ``` Update the import paths to match your project setup. ## Usage ```tsx import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, } from "@/components/ui/accordion"; ``` ```tsx Is it accessible? Yes. It adheres to the WAI-ARIA design pattern. ``` ## Examples Examples cover the main accordion modes: one open panel, many open panels, and externally controlled state. ### Single Accordion Use this for compact pages where opening one section should close the previous section. ```tsx import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, } from "@/components/honest-ui/ui/accordion" export function AccordionSingleDemo() { return ( What is Base UI? Honest UI gives you thoughtful components with visible, editable code that stays in your project. How do I get started? Head to the “Get started” guide in the docs. If you’ve used component libraries before, you’ll feel at home. Can I use it for my project? Yes. Honest UI is free and open source. ) } ``` ### Multiple Accordion Use this when each section is independent and users may need to keep several answers open. ```tsx import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, } from "@/components/honest-ui/ui/accordion" export function AccordionMultipleDemo() { return ( What is Base UI? Honest UI gives you thoughtful components with visible, editable code that stays in your project. How do I get started? Head to the “Get started” guide in the docs. If you’ve used component libraries before, you’ll feel at home. Can I use it for my project? Yes. Honest UI is free and open source. ) } ``` ### Controlled Accordion Use this when the open item must be controlled by your application state. ```tsx "use client" import * as React from "react" import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, } from "@/components/honest-ui/ui/accordion" import { Button } from "@/components/honest-ui/ui/button" export function AccordionControlledDemo() { const [value, setValue] = React.useState([]) return (
What is Base UI? Honest UI gives you thoughtful components with visible, editable code that stays in your project. How do I get started? Head to the “Get started” guide in the docs. If you’ve used component libraries before, you’ll feel at home. Can I use it for my project? Yes. Honest UI is free and open source.

Open items: {value.length > 0 ? value.join(", ") : "None"}

) } ``` ## Decision guidance Choose Accordion when several sections are peers and people benefit from scanning their headings before opening details. Use Collapsible for one optional region, and use normal headings when all content should remain visible. Do not hide a required step or the only explanation of an error inside a closed item. ## API reference `Accordion`, `AccordionItem`, `AccordionTrigger`, and `AccordionPanel` forward their matching Base UI Accordion props. `AccordionContent` is an alias of `AccordionPanel`. Configure single or multiple expansion, controlled state, and disabled items on the Base UI parts. See the [Base UI Accordion API](https://base-ui.com/react/components/accordion#api-reference). --- ## Alert > Present important page-level information or require a decision before work continues. Source: https://www.honestui.com/docs/components/alert Markdown: https://www.honestui.com/docs/components/alert.md --- title: Alert description: Present important page-level information or require a decision before work continues. links: doc: https://base-ui.com/react/components/alert-dialog#api-reference --- ```tsx "use client" import * as React from "react" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field" import { Form } from "@/components/honest-ui/ui/form" export function AlertDemo() { const [email, setEmail] = React.useState("alex@example.com") const [sentTo, setSentTo] = React.useState(null) return (
{ event.preventDefault() setSentTo(email) }} >

Invite a teammate

They will join the Design workspace as a member.

Work email { setEmail(event.target.value) setSentTo(null) }} required /> {sentTo ? "Invite sent" : "Before you invite"} {sentTo ? `${sentTo} can now join from the email invitation.` : "Invitations expire after seven days. You can revoke one at any time."}
) } ``` ## Overview Use an alert to call attention to information that affects the current page or task. Alerts are best for inline feedback, warnings, success messages, errors, and important context. They should be visible near the content they explain. Use a toast instead when the message is temporary and does not need to stay on the page. Use Alert Dialog when the user must make a decision before the app can continue. Alert dialogs are for high-impact choices such as deleting data, leaving with unsaved changes, confirming a destructive action, or acknowledging a blocking error. ## Anatomy An alert usually has a container, optional icon, title, description, and optional actions. The title should be short. The description should explain what happened or what the user should do next. An alert dialog has a trigger, popup, title, description, and actions. The title should state the decision. The description should explain the consequence. The actions should make the safe choice and the risky choice easy to distinguish. ## Variants Choose the variant by meaning, not by color preference. Use info for neutral guidance, success for completed work, warning for possible risk, error for a failed action, and destructive when the user is dealing with a harmful or irreversible action. ## Behavior Keep alerts close to the content they explain. Keep alert dialogs short and focused. If a flow needs a form, browsing, or several steps, use Dialog or Sheet instead. ## Accessibility Do not rely on color alone. Pair state colors with clear text and, when useful, an icon. Keep action buttons keyboard reachable and avoid putting long instructions inside a small alert. Alert dialogs should have a clear title and description. Keep focus inside the popup while it is open. Make sure the cancel action is easy to reach and that destructive actions use explicit copy such as `Delete project`, not vague copy like `OK`. ## Installation ### npm ```bash npx honestui@latest add alert ``` ### yarn ```bash yarn dlx honestui@latest add alert ``` ### bun ```bash bunx --bun honestui@latest add alert ``` ### pnpm ```bash pnpm dlx honestui@latest add alert ``` ### shadcn ```bash npx shadcn@latest add @honestui/alert ``` Import the following variables into your CSS file ```css @theme inline { --color-destructive-foreground: var(--destructive-foreground); --color-info: var(--info); --color-info-foreground: var(--info-foreground); --color-success: var(--success); --color-success-foreground: var(--success-foreground); --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); } :root { --destructive-foreground: oklch(0.704 0.191 22.216); --info: oklch(0.623 0.214 259.815); --info-foreground: oklch(0.707 0.165 254.624); --success: oklch(0.696 0.17 162.48); --success-foreground: oklch(0.765 0.177 163.223); --warning: oklch(0.769 0.188 70.08); --warning-foreground: oklch(0.828 0.189 84.429); } .dark { --destructive-foreground: oklch(0.704 0.191 22.216); --info: oklch(0.623 0.214 259.815); --info-foreground: oklch(0.707 0.165 254.624); --success: oklch(0.696 0.17 162.48); --success-foreground: oklch(0.765 0.177 163.223); --warning: oklch(0.769 0.188 70.08); --warning-foreground: oklch(0.828 0.189 84.429); } ``` Install the following dependencies: ```bash npm install @base-ui-components/react ``` Copy and paste the following code into your project. ### components/ui/alert.tsx ```tsx "use client" import * as React from "react" import { AlertDialog as AlertDialogPrimitive } from "@base-ui-components/react/alert-dialog" import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const alertVariants = cva( "relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-xl border px-3.5 py-3 text-sm text-card-foreground has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-2 has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] [&>svg]:h-[1lh] [&>svg]:w-4", { variants: { variant: { default: "bg-transparent dark:bg-input/32 [&>svg]:text-muted-foreground", info: "border-info/32 bg-info/4 [&>svg]:text-info", success: "border-success/32 bg-success/4 [&>svg]:text-success", warning: "border-warning/32 bg-warning/4 [&>svg]:text-warning", error: "border-destructive/32 bg-destructive/4 [&>svg]:text-destructive", }, }, defaultVariants: { variant: "default", }, } ) function Alert({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps) { return (
) } function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertDescription({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertAction({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertDialog(props: AlertDialogPrimitive.Root.Props) { return } function AlertDialogTrigger(props: AlertDialogPrimitive.Trigger.Props) { return ( ) } function AlertDialogPortal(props: AlertDialogPrimitive.Portal.Props) { return } function AlertDialogBackdrop({ className, ...props }: AlertDialogPrimitive.Backdrop.Props) { return ( ) } function AlertDialogPopup({ className, ...props }: AlertDialogPrimitive.Popup.Props) { return (
) } function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertDialogBody({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) { return (
) } function AlertDialogTitle({ className, ...props }: AlertDialogPrimitive.Title.Props) { return ( ) } function AlertDialogDescription({ className, ...props }: AlertDialogPrimitive.Description.Props) { return ( ) } function AlertDialogClose(props: AlertDialogPrimitive.Close.Props) { return ( ) } export { Alert, AlertTitle, AlertDescription, AlertAction, AlertDialog, AlertDialogPortal, AlertDialogBackdrop, AlertDialogBackdrop as AlertDialogOverlay, AlertDialogTrigger, AlertDialogPopup, AlertDialogPopup as AlertDialogContent, AlertDialogHeader, AlertDialogBody, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogClose, } ``` Update the import paths to match your project setup. ## Usage ```tsx import { Alert, AlertDescription, AlertDialog, AlertDialogBody, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle, AlertDialogTrigger, AlertTitle, } from "@/components/ui/alert"; ``` ```tsx > Heads up! You can add components and dependencies to your app using the cli. ``` ```tsx Delete Account Are you absolutely sure? This action cannot be undone. This will permanently delete your account and remove your data from our servers. Cancel Delete Account ``` ## Examples Each example places the alert inside the task that produces it, including the action, result, and recovery path where they matter. ### With Icon Generate a new set of recovery codes and see how the alert explains the consequence before and after the action. ```tsx "use client" import * as React from "react" import { Info as InfoIcon } from "honestui/icons" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" export function AlertWithIcon() { const [generated, setGenerated] = React.useState(false) return (

Recovery codes

Use a recovery code if you lose access to your authenticator.

{generated ? "New codes are ready" : "Keep your codes private"} {generated ? "Your previous codes no longer work. Store the new set somewhere safe." : "Generating a new set will invalidate every code you saved before."}
) } ``` ### With Icon and Action Buttons Turn on two-step verification, defer it, or return to the setup from the same account-security workflow. ```tsx "use client" import * as React from "react" import { CircleCheck as CircleCheckIcon, Info as InfoIcon, TriangleAlert as TriangleAlertIcon, } from "honestui/icons" import { Alert, AlertAction, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" export function AlertWithIconAction() { const [status, setStatus] = React.useState<"review" | "later" | "secured">( "review" ) const StatusIcon = status === "secured" ? CircleCheckIcon : status === "later" ? TriangleAlertIcon : InfoIcon return (

Account security

Two-step verification

{status === "secured" ? "On" : "Off"}
{status === "secured" ? "Two-step verification is on" : status === "later" ? "Two-step verification is still off" : "Protect your account"} {status === "secured" ? "New devices now require an additional sign-in step." : status === "later" ? "You can return to this setup whenever you are ready." : "Require a second step when someone signs in on a new device."} {status !== "secured" && ( )} {status !== "later" && ( )}
) } ``` ### Info Alert Give neutral guidance at the point where it changes how someone completes a form. ```tsx "use client" import * as React from "react" import { Info as InfoIcon } from "honestui/icons" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field" import { Form } from "@/components/honest-ui/ui/form" export function AlertInfo() { const [ready, setReady] = React.useState(false) return (
{ event.preventDefault() setReady(true) }} >

Billing address

Used for invoices and tax calculations.

{ready ? "Address ready for review" : "Use the address on your payment method"} {ready ? "Check the address and total on the next step before you pay." : "A mismatch may cause your bank to decline the payment."} Postal code
) } ``` ### Success Alert Confirm a saved profile change while keeping the edited field and next state in view. ```tsx "use client" import * as React from "react" import { CircleCheck as CircleCheckIcon } from "honestui/icons" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field" import { Form } from "@/components/honest-ui/ui/form" export function AlertSuccess() { const [saved, setSaved] = React.useState(true) return (
{ event.preventDefault() setSaved(true) }} >

Profile

This name appears to everyone in your workspace.

Display name setSaved(false)} /> {saved && ( Profile saved Your updated name is now visible across the workspace. )}
) } ``` ### Warning Alert Warn about an expiring payment method and show what changes after it is replaced. ```tsx "use client" import * as React from "react" import { TriangleAlert as TriangleAlertIcon } from "honestui/icons" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" export function AlertWarning() { const [updated, setUpdated] = React.useState(false) return (

Payment method

Visa ending in 4242 · Expires this month

{updated ? "Payment method updated" : "Card expires soon"} {updated ? "Future invoices will use the replacement card." : "Replace this card before your next invoice to avoid an interrupted subscription."}
) } ``` ### Error Alert Preserve the failed value, explain the valid format, and let the user recover in place. ```tsx "use client" import * as React from "react" import { CircleAlert as CircleAlertIcon } from "honestui/icons" import { Alert, AlertDescription, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field" import { Form } from "@/components/honest-ui/ui/form" export function AlertError() { const [url, setUrl] = React.useState("example.com/webhook") const [connected, setConnected] = React.useState(false) const isValid = url.startsWith("https://") return (
{ event.preventDefault() setConnected(isValid) }} >

Webhook endpoint

Send workspace events to your server.

Endpoint URL { setUrl(event.target.value) setConnected(false) }} aria-describedby="webhook-status" /> {connected ? "Webhook connected" : "Connection failed"} {connected ? "The endpoint is ready to receive workspace events." : "Enter a secure URL that starts with https://, then try again."}
) } ``` ## Alert Dialog Alert Dialog is included in the same component file. Use it only when the user must respond before continuing. ### Basic Alert Dialog Show the destructive action in its settings context, require confirmation, then make the completed state visible. ```tsx "use client" import * as React from "react" import { Alert, AlertDescription, AlertDialog, AlertDialogBody, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle, AlertDialogTrigger, AlertTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" export function AlertDialogDemo() { const [deleted, setDeleted] = React.useState(false) const resultRef = React.useRef(null) React.useEffect(() => { if (deleted) resultRef.current?.focus() }, [deleted]) if (deleted) { return ( Workspace deleted The Design workspace and its sample data were removed. ) } return (

Delete workspace

Permanently remove the Design workspace and its data.

}> Delete Design workspace Delete Design workspace? This permanently deletes the workspace and its sample data. This action cannot be undone. }> Keep workspace setDeleted(true)} /> } > Delete workspace
) } ``` ### Close Confirmation Use this pattern when closing would discard work, interrupt a process, or hide important state. ```tsx "use client" import * as React from "react" import { AlertDialog, AlertDialogBody, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle, } from "@/components/honest-ui/ui/alert" import { Button } from "@/components/honest-ui/ui/button" import { Dialog, DialogBody, DialogClose, DialogDescription, DialogFooter, DialogHeader, DialogPopup, DialogTitle, DialogTrigger, } from "@/components/honest-ui/ui/dialog" import { Field } from "@/components/honest-ui/ui/field" import { Form } from "@/components/honest-ui/ui/form" import { Textarea } from "@/components/honest-ui/ui/textarea" export function DialogCloseConfirmationDemo() { const [dialogOpen, setDialogOpen] = React.useState(false) const [confirmOpen, setConfirmOpen] = React.useState(false) const [value, setValue] = React.useState("") return ( { if (!o && value) { setConfirmOpen(true) } else { setDialogOpen(o) } }} > }> Compose New message Type something and try closing.
{ event.preventDefault() // Close the dialog when submitting setDialogOpen(false) }} >