--- url: https://wallarm.github.io/design-system/get-started/introduction.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Introduction Wallarm Design System is the React component library behind Wallarm products. It ships accessible, ready-to-use components, the design tokens they are styled with, and tooling that helps people and AI assistants use both correctly. ## What it is built on - **React 19** and **TypeScript**: every component is typed, and refs are passed as plain props. - **Tailwind CSS v4** for styling; colors, spacing, radius and typography are [design tokens](https://wallarm.github.io/design-system/foundations/tokens.md) exposed as CSS variables. - **Ark UI** for accessible behavior: focus management, keyboard support and ARIA wiring. - **TanStack Table** and **TanStack Virtual** for data tables and long lists. - **DnD Kit** for drag and drop. ## Where to find it - **npm**: [`@wallarm-org/design-system`](https://www.npmjs.com/package/@wallarm-org/design-system) - **Source**: [github.com/wallarm/design-system](https://github.com/wallarm/design-system) - **Storybook**: [wallarm.github.io/design-system/storybook](https://wallarm.github.io/design-system/storybook/), the interactive playground with every story and its controls. ## Before you start The library has required peer dependencies: `react` and `react-dom` (^19.0.0), `tailwindcss` (^4.0.0), `tw-animate-css` (^1.0.0) and `@internationalized/date` (^3.12.0). [Installation](https://wallarm.github.io/design-system/get-started/installation.md) walks through them and the CSS setup. ## Next steps - [Installation](https://wallarm.github.io/design-system/get-started/installation.md): add the package, its peers and the theme. - [Theming](https://wallarm.github.io/design-system/get-started/theming.md): light and dark themes, frame style and token overrides. - [Routing](https://wallarm.github.io/design-system/get-started/routing.md): wire navigation components to your router. - [Components](https://wallarm.github.io/design-system/components/button.md): the component catalog. - [MCP server](https://wallarm.github.io/design-system/ai/mcp.md): give your coding assistant the component and token metadata. --- url: https://wallarm.github.io/design-system/get-started/installation.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Installation ## 1. Install the library ```sh [npm] npm install @wallarm-org/design-system ``` ```sh [yarn] yarn add @wallarm-org/design-system ``` ```sh [pnpm] pnpm add @wallarm-org/design-system ``` ## 2. Install the peer dependencies All of them are required: ```sh [npm] npm install react@^19.0.0 react-dom@^19.0.0 tailwindcss@^4.0.0 tw-animate-css@^1.0.0 @internationalized/date@^3.12.0 ``` ```sh [yarn] yarn add react@^19.0.0 react-dom@^19.0.0 tailwindcss@^4.0.0 tw-animate-css@^1.0.0 @internationalized/date@^3.12.0 ``` ```sh [pnpm] pnpm add react@^19.0.0 react-dom@^19.0.0 tailwindcss@^4.0.0 tw-animate-css@^1.0.0 @internationalized/date@^3.12.0 ``` - `react` and `react-dom`: the components are written for React 19. - `tailwindcss`: the styling system; your build compiles the component classes. - `tw-animate-css`: enter and exit animations. - `@internationalized/date`: date values for the calendar and date inputs. ## 3. Add the Tailwind PostCSS plugin Tailwind v4 compiles through its PostCSS plugin. Install it: ```sh [npm] npm install -D @tailwindcss/postcss ``` ```sh [yarn] yarn add -D @tailwindcss/postcss ``` ```sh [pnpm] pnpm add -D @tailwindcss/postcss ``` and register it in `postcss.config.mjs` at the project root: ```js title="postcss.config.mjs" export default { plugins: { '@tailwindcss/postcss': {}, }, }; ``` ## 4. Import the styles Create the CSS entry of your app: ```css title="App.css" @import 'tailwindcss'; @import 'tw-animate-css'; @import '@wallarm-org/design-system/theme'; ``` The theme declares the tokens, the Geist fonts and the `@source` paths that let Tailwind find the classes used inside the components, so no extra content configuration is needed. ## 5. Wrap the app in ThemeProvider ```tsx title="App.tsx" import { Button } from '@wallarm-org/design-system/Button'; import { ThemeProvider } from '@wallarm-org/design-system/ThemeProvider'; import './App.css'; export const App = () => { return ( ); }; ``` `ThemeProvider` writes the theme as `data-theme` on `` and remembers the user's choice in `localStorage`. All props are optional: | Prop | Default | Description | | ---------------------- | -------------------- | ----------------------------------------------------------------- | | `defaultTheme` | `'light'` | Theme until the user picks one: `'light'` or `'dark'`. | | `storageKey` | `'wasd-theme'` | `localStorage` key for the theme. | | `defaultFrameStyle` | `'neutral'` | Frame style until the user picks one: `'neutral'` or `'branded'`. | | `frameStyleStorageKey` | `'wasd-frame-style'` | `localStorage` key for the frame style. | The **frame style** is the AppShell look next to light and dark: the neutral gray surround or the warm branded one. Read and change both with `useTheme()`; see [Theming](https://wallarm.github.io/design-system/get-started/theming.md). :::warning Micro-frontends Keep `defaultTheme` and `defaultFrameStyle` identical in the host and every micro-frontend. Each `ThemeProvider` writes `` when it mounts, so a different default flips the whole console when that product opens. ::: ## Tree-shaking Import each component from its own entry point: ```tsx // Good: only Button is bundled import { Button } from '@wallarm-org/design-system/Button'; // Avoid: pulls in the whole library import { Button } from '@wallarm-org/design-system'; ``` Icons have their own entry, `@wallarm-org/design-system/icons`; see [Icons](https://wallarm.github.io/design-system/foundations/icons.md). ## Troubleshooting **Styles are not applied.** Check that `@wallarm-org/design-system/theme` is imported after `tailwindcss` and `tw-animate-css`, that the PostCSS plugin is registered, and that the app is wrapped in `ThemeProvider`. **TypeScript import errors.** Use TypeScript 5.0 or newer with a `moduleResolution` that reads package `exports` (`bundler` or `nodenext`), add `"skipLibCheck": true` to `tsconfig.json`, and restart the TypeScript server in your editor. **React version conflict.** Make sure the app uses React 19, then delete `node_modules` and the lock file and reinstall. **Fonts do not load.** The Geist fonts are bundled with `@wallarm-org/design-system/theme`. Check that the theme is imported and look for the font requests in the browser's Network tab. --- url: https://wallarm.github.io/design-system/get-started/theming.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Theming Theming is driven by two attributes on ``, both written by `ThemeProvider`: - `data-theme`: `light` or `dark`; - `data-frame-style`: `neutral` or `branded`, the AppShell surround inside the theme. Every component reads its colors from [design tokens](https://wallarm.github.io/design-system/foundations/tokens.md), and the theme CSS swaps the token values under these attributes. Components never need a theme prop. ## ThemeProvider and useTheme Wrap the app once (see [Installation](https://wallarm.github.io/design-system/get-started/installation.md) for the props), then read and change the theme anywhere below it with `useTheme()`: ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { useTheme } from '@wallarm-org/design-system/ThemeProvider'; export const ThemeToggle = () => { const { theme, setTheme } = useTheme(); const nextTheme = theme === 'dark' ? 'light' : 'dark'; const handleClick = () => setTheme(nextTheme); return ( ); }; ``` `setTheme` updates `data-theme` and stores the choice in `localStorage` under `storageKey`. The types are exported as `Theme` (`'light' | 'dark'`) and `FrameStyle` (`'neutral' | 'branded'`). ## Frame style The frame style is the AppShell look next to light and dark: `neutral` (default) is the gray surround, `branded` the warm one. It is set and read the same way: ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { useTheme } from '@wallarm-org/design-system/ThemeProvider'; export const FrameStyleToggle = () => { const { frameStyle, setFrameStyle } = useTheme(); const nextStyle = frameStyle === 'branded' ? 'neutral' : 'branded'; const handleClick = () => setFrameStyle(nextStyle); return ( ); }; ``` Because the value lives on ``, micro-frontends rendered in the same document follow it without any wiring. :::warning Micro-frontend defaults Keep `defaultTheme` and `defaultFrameStyle` identical in the host and every micro-frontend. Each `ThemeProvider` writes `` when it mounts, so a micro-frontend with a different default flips the whole console when it opens. ::: ## Overriding tokens Tokens are plain CSS variables, so you can override them in your own CSS after the theme import. Light values live on `:root` and dark values under `[data-theme='dark']`; override both when the value differs per theme: ```css title="App.css" @import 'tailwindcss'; @import 'tw-animate-css'; @import '@wallarm-org/design-system/theme'; :root { --color-text-brand: var(--color-w-orange-700); } [data-theme='dark'] { --color-text-brand: var(--color-w-orange-400); } ``` Override semantic tokens (`--color-text-*`, `--color-bg-*`, `--color-border-*`) rather than palette tokens: components use the semantic layer, and a palette change ripples into every semantic token that points at it. The full list is on the [Tokens](https://wallarm.github.io/design-system/foundations/tokens.md) page. --- url: https://wallarm.github.io/design-system/get-started/routing.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Routing The design system does not depend on a router. Navigation components either render your router's link element through `asChild`, or hand you a callback to navigate with. ## asChild With `asChild`, a component does not render its own element. It merges its classes, attributes, ref and event handlers into its only child, so your router's link becomes the real DOM node: you get client-side navigation, a real `href`, middle-click and "open in new tab", with the design-system look. These components support `asChild` for routing: | Component | Renders by default | | ----------------------------------- | ------------------ | | `Link` | `` | | `Button` | ` ); ``` ### Navigation rail, header logo, cards and tabs `NavRailItem` keeps rendering its icon and label inside the child, so the child link needs no content of its own: ```tsx import { Link as RouterLink } from '@tanstack/react-router'; import { Home } from '@wallarm-org/design-system/icons'; import { NavRailItem } from '@wallarm-org/design-system/NavRail'; import { TopHeaderLogo } from '@wallarm-org/design-system/TopHeader'; export const HomeRailItem = ({ active }: { active: boolean }) => ( ); export const Logo = () => ( Wallarm ); ``` A card that is a link, and tabs that are routes (the active tab comes from the URL): ```tsx import { Link as RouterLink, useRouterState } from '@tanstack/react-router'; import { Card, CardContent, CardHeader, CardTitle } from '@wallarm-org/design-system/Card'; import { Tabs, TabsList, TabsTrigger } from '@wallarm-org/design-system/Tabs'; export const NodeCard = () => ( node-1 Filtering node in eu-1 ); export const NodeTabs = () => { const pathname = useRouterState({ select: state => state.location.pathname }); const activeTab = pathname.endsWith('/metrics') ? 'metrics' : 'overview'; return ( Overview Metrics ); }; ``` ## Breadcrumbs `BreadcrumbsItem` renders an `` when it has an `href` and is not the current page, and a ` ); ``` renders: ```html
…
Error Invalid credentials
…
``` In Playwright: ```ts import { expect, test } from '@playwright/test'; test('login error can be dismissed', async ({ page }) => { await expect(page.getByTestId('login-error')).toBeVisible(); await expect(page.getByTestId('login-error--title')).toHaveText('Error'); await page.getByTestId('login-error--controls').getByRole('button').click(); await page.getByTestId('login-error--close').click(); }); ``` Testing Library's `screen.getByTestId('login-error--close')` works the same way. Without a `data-testid` on the root, no derived ids are rendered, so production HTML stays clean. Leaf components such as `Button` or `Badge` take `data-testid` like any other attribute. ## Exceptions | Component | Where the test id comes from | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | Toast | The toast's `id`: `useToast().create({ id: 'save-success', title: 'Saved' })` renders `data-testid="save-success"`, and its parts derive from it. | | Tour | `data-testid` on `Tour`. Tour has no DOM root of its own, so the id is applied to its popup parts through the cascade. | ## Your own compound components Use the same helpers to make your components cascade, from `@wallarm-org/design-system/utils/testId`: ```tsx import type { ReactNode } from 'react'; import { type TestableProps, TestIdProvider, useTestId } from '@wallarm-org/design-system/utils/testId'; interface PanelProps extends TestableProps { children: ReactNode; } export const Panel = ({ 'data-testid': testId, children }: PanelProps) => (
{children}
); export const PanelTitle = ({ children }: { children: ReactNode }) => { const testId = useTestId('title'); // 'settings--title' under return

{children}

; }; ``` `useTestId(slot)` returns `{base}--{slot}`, or `undefined` outside a provider or when the root has no test id. ## `data-testid` and `data-slot` Components also render `data-slot` attributes. They exist for CSS selectors and can change with the markup, so don't use them in tests. Both attributes coexist on the same elements. --- url: https://wallarm.github.io/design-system/guides/analytics.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Analytics The design system does not ship an analytics SDK, provider or analytics-specific props. Instead, every interactive component forwards the attributes and handlers you pass to the **real interactive DOM element**: the button, link or input the user actually clicks. Your analytics library finds them there, typically with a document-level click listener and `event.target.closest('[data-analytics-id]')`. The canonical attributes are `data-analytics-id` and `data-analytics-props`, but the rule covers any `data-*`, `aria-*`, `id`, `ref` and event handler. ## Attributes land on the click target ```tsx import { Button } from '@wallarm-org/design-system/Button'; export const DeleteHostButton = () => ( ); ``` `data-analytics-props` is forwarded byte-for-byte: the design system never parses, normalizes or reserializes it. Its format is up to you and your analytics library. Attributes survive rerenders, open and close transitions, variant changes and controlled or uncontrolled state changes. Your own event handlers run alongside the component's internal ones; they are never silently replaced. ## asChild With `asChild`, the attributes reach the element you render: ```tsx import { Button } from '@wallarm-org/design-system/Button'; export const DocsButton = () => ( ); ``` ## Components with several click targets When a component has more than one interactive part, each part is an exported sub-component, and you put the attributes on the part itself, not on a wrapper around the whole component: ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@wallarm-org/design-system/Dialog'; export const DeleteRuleDialog = () => ( Delete rule? ); ``` Don't wrap a component in `
` when the click target is inside it: the attribute ends up on an element nobody clicks. A few internal targets cannot be reached this way yet, such as parts of the table. Their component folder documents the gap and the callback to track instead (for example [`Table/ANALYTICS_GAPS.md`](https://github.com/wallarm/design-system/blob/main/packages/design-system/src/components/Table/ANALYTICS_GAPS.md)). Interactions without a DOM click, such as sorting or resizing, are reported through typed callbacks (`onSortingChange` on `Table`, `onResizeEnd` on `DrawerResizeHandle`, …) that you track from your own code. ## Clickable containers Some components delegate clicks from a container: a `Card` with `onClick` is clickable on its whole surface. Native interactive descendants (` ); }; ``` ## Usage ```tsx import { Button } from '@wallarm-org/design-system/Button'; ``` ## Examples ### Variants `variant` sets emphasis and `color` sets meaning, and only the pairings drawn here are designed: `primary` exists for `brand` and `destructive` only. `neutral-alt` has ghost and secondary variants, shown on an inverted surface so they remain readable in both themes. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { HStack, VStack } from '@wallarm-org/design-system/Stack'; export const Variants = () => ( ); ``` ### Sizes Three heights at identical emphasis; `large` is the default, and the smaller two are for dense contexts like table rows and toolbars where a full-height button would dominate. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { HStack } from '@wallarm-org/design-system/Stack'; export const Sizes = () => ( ); ``` ### Disabled Every sanctioned pairing with the action unavailable. `disabled` also takes the button out of the tab order, so say somewhere on screen what would re-enable it rather than leaving the reader to guess. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { HStack, VStack } from '@wallarm-org/design-system/Stack'; export const Disabled = () => ( ); ``` ### Loading `loading` covers the content with a spinner but keeps the label's footprint, so the button doesn't resize mid-request. It disables the button on its own — passing `disabled` as well is redundant. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { HStack, VStack } from '@wallarm-org/design-system/Stack'; export const Loading = () => ( ); ``` ### Icons An icon before the label, after it, or both. The button sizes and spaces icons itself, so pass the icon bare; and if one button in a row carries an icon, they all should. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronLeft, ChevronRight } from '@wallarm-org/design-system/icons'; import { HStack } from '@wallarm-org/design-system/Stack'; export const Icons = () => ( ); ``` ### Badge A `NumericBadge` after the label, for a count the action applies to. The button tightens its right padding whenever the last child isn't text, so a trailing badge or icon doesn't sit stranded. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { NumericBadge } from '@wallarm-org/design-system/NumericBadge'; export const Badge = () => ( ); ``` ### Icon only There is no `iconOnly` prop: a button whose only child is an icon squares itself off. Give it an `aria-label` naming the action and a `Tooltip`, since nothing on screen says what it does. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronRight } from '@wallarm-org/design-system/icons'; import { HStack } from '@wallarm-org/design-system/Stack'; export const IconOnly = () => ( ); ``` ### Link as button `asChild` puts the button's styling on your own ``, so the element stays a real link and middle-click and “open in new tab” keep working. Use it only when a navigation has to carry a button's weight; ordinary navigation is a `Link`. ```tsx import { Button } from '@wallarm-org/design-system/Button'; export const LinkAsButton = () => ( ); ``` ### Full width `fullWidth` fills the container, for narrow surfaces like a `Drawer` or a dialog footer rather than a wide desktop form. Two full-width buttons side by side split the row evenly instead of overflowing it. ```tsx import { Button } from '@wallarm-org/design-system/Button'; export const FullWidth = () => (
); ``` ## Props | Prop | Type | Default | Description | | ----------- | --------------------------------------------------------------------------------- | --------- | ----------- | | size | `{ small: string; medium: string; large: string; 'inline-edit': string; }` | `large` | | | loading | `{ true: string; }` | `false` | | | fullWidth | `{ true: string; false: string; }` | | | | asChild | `boolean \| undefined` | `false` | | | data-testid | `string \| undefined` | | | | as | `C \| undefined` | | | | color | `{ brand: string; neutral: string; 'neutral-alt': string; destructive: string; }` | `brand` | | | variant | `{ primary: string; outline: string; ghost: string; secondary: string; }` | `primary` | | --- url: https://wallarm.github.io/design-system/components/dropdown-menu.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # DropdownMenu A menu of actions hanging off a trigger — reach for `Select` when the reader is choosing a value for a form, since a menu runs commands rather than holding an answer. Leave the primary action visible as a `Button` and put only the secondary ones in here; past roughly ten items, group them or move them somewhere with room. [Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/DropdownMenu) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/actions-dropdownmenu--overview) ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem } from '@wallarm-org/design-system/DropdownMenu'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const Basic = () => ( My Account Profile ⌘ P Billing ⌘ B Settings ⌘ S Keyboard shortcuts super ⌘ K Team Invite users Email Message More... New Team ⌘ T GitHub Support API Log out ⌘ Q ); ``` ## Usage ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem } from '@wallarm-org/design-system/DropdownMenu'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; ``` ## Examples ### Context `DropdownMenuContextTrigger` opens the same menu on right-click, and `DropdownMenuTriggerItem` nests a submenu inside it. Always leave a left-click route to the same actions — a right-click-only affordance is undiscoverable. ```tsx import { DropdownMenu, DropdownMenuContent, DropdownMenuContextTrigger, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTriggerItem } from '@wallarm-org/design-system/DropdownMenu'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const Context = () => (
Right click here
My Account Profile ⌘ P Billing ⌘ B Settings ⌘ S Keyboard shortcuts super ⌘ K Team Invite users Email Message More... New Team ⌘ T GitHub Support API Log out ⌘ Q
); ``` ### With descriptions `DropdownMenuItemContent` pairs `DropdownMenuItemText` with `DropdownMenuItemDescription` for a second line. Descriptions make a menu tall quickly, which is when separators start doing real work. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDescription, DropdownMenuItemText, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; import { CirclePlus, Plus } from '@wallarm-org/design-system/icons'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const WithDescriptions = () => ( Bar-volume chart Description Canvas Description Attacks heat-map Description ⌘ Q Request custom widget ); ``` ### With icons `DropdownMenuItemIcon` sits before the label. Icon every item in a group or none of them — a half-iconned list reads as though some items are missing theirs. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; import { CirclePlus, Earth, LayoutTemplate, Maximize, Plus } from '@wallarm-org/design-system/icons'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const WithIcons = () => ( Bar-volume chart Canvas Attacks heat-map ⌘ Q Request custom widget ); ``` ### With footer `DropdownMenuFooter` bleeds to the panel edge under a divider and renders at secondary emphasis, so it suits a persistent link or count rather than an action competing with the items. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuFooter, DropdownMenuItem, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const WithFooter = () => ( Profile Billing Settings Notifications Integrations Security API Keys Webhooks Audit Log Team Members Permissions Usage ↑ ↓ to navigate ↵ to select ); ``` ### With description and icons Icons and descriptions together, which is the widest an item gets. Past this the menu is doing a panel's job — reach for a `Popover`. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDescription, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; import { CirclePlus, Earth, LayoutTemplate, Maximize, Plus } from '@wallarm-org/design-system/icons'; import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd'; export const WithDescriptionAndIcons = () => ( Bar-volume chart Description Canvas Description Attacks heat-map Description ⌘ Q Request custom widget ); ``` ### With checkbox items `DropdownMenuCheckboxItem` for options that aren't mutually exclusive. Selecting one leaves the menu open, so several can be toggled in a single visit. ```tsx import { useState } from 'react'; import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; export const WithCheckboxItems = () => { const [bold, setBold] = useState(true); const [italic, setItalic] = useState(false); const [underline, setUnderline] = useState(true); return ( Text style Bold Italic Underline Strikethrough ); }; ``` ### With radio group `DropdownMenuRadioGroup` for one-of-many. It also stays open on select, so the reader sees the indicator move before dismissing it themselves. ```tsx import { useState } from 'react'; import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; export const WithRadioGroup = () => { const [view, setView] = useState('list'); const handleViewChange = (details: { value: string }) => { setView(details.value); }; return ( View mode List Grid Compact ); }; ``` ### With mixed selection items Commands, checkboxes and a radio group in one menu. `DropdownMenuLabel` and `DropdownMenuSeparator` are what keep the three kinds from reading as one flat list. ```tsx import { useState } from 'react'; import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; export const WithMixedSelectionItems = () => { const [bold, setBold] = useState(true); const [italic, setItalic] = useState(false); const [view, setView] = useState('list'); const handleViewChange = (details: { value: string }) => { setView(details.value); }; return ( Text style Bold Italic View mode List Grid Reset to defaults ); }; ``` ## Props | Prop | Type | Default | Description | | ----------------- | ---------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | open | `boolean \| undefined` | | | | defaultOpen | `boolean \| undefined` | | | | onOpenChange | `((open: boolean) => void) \| undefined` | | | | modal | `boolean \| undefined` | | | | anchorPoint | `{ x: number; y: number; } \| undefined` | | Virtual anchor point for positioning without a trigger element | | positioning | `PositioningOptions \| undefined` | | Override default positioning config | | highlightedValue | `string \| null \| undefined` | | Programmatically control which item is highlighted | | onHighlightChange | `((details: HighlightChangeDetails) => void) \| undefined` | | Callback when the highlighted item changes (e.g. on mouse hover) | | closeOnSelect | `boolean \| undefined` | | Whether selecting an item closes the menu (default true) | | onRequestDismiss | `((event: LayerDismissEvent) => void) \| undefined` | | Called when another layer asks this menu to dismiss — e.g. a layer below it in the stack is removed. Call `event.preventDefault()` to keep the menu open. | | ids | `ElementIds \| undefined` | | Override the trigger element's id. Pass the same id to another compound component's `ids.trigger` (e.g. `Tooltip`, `Popover`) to compose their triggers on one element via nested `asChild` without an extra wrapper node — otherwise the outer trigger's id wins and the other component can't find its own anchor. | | data-testid | `string \| undefined` | | | ### DropdownMenuCheckboxItem | Prop | Type | Default | Description | | --------------- | ---------------------------------------------------------- | --------- | ------------------------------------------------ | | checked \* | `boolean` | | | | onCheckedChange | `((checked: boolean) => void) \| undefined` | | | | value | `string \| undefined` | | Optional — auto-generated via useId() if omitted | | disabled | `boolean \| undefined` | | | | closeOnSelect | `boolean \| undefined` | | | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | variant | `{ default: string; brand: string; destructive: string; }` | `default` | | | inset | `{ true: string; }` | | | | data-testid | `string \| undefined` | | | ### DropdownMenuContextTrigger | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------- | ------- | ----------- | | asChild | `boolean \| undefined` | | | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | type | `"button" \| "submit" \| "reset" \| undefined` | | | | disabled | `boolean \| undefined` | | | | name | `string \| undefined` | | | | value | `string \| number \| readonly string[] \| undefined` | | | | data-testid | `string \| undefined` | | | ### DropdownMenuItem | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------------- | --------- | ----------------------------------------------------------------- | | inset | `boolean \| undefined` | `false` | | | disabled | `boolean \| undefined` | | | | onSelect | `(() => void) \| undefined` | | | | value | `string \| undefined` | | Explicit value for programmatic highlighting via highlightedValue | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | variant | `{ default: string; brand: string; destructive: string; }` | `default` | | | data-testid | `string \| undefined` | | | ### DropdownMenuRadioGroup | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------ | ------- | ----------- | | value | `string \| undefined` | | | | onValueChange | `((details: { value: string; }) => void) \| undefined` | | | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | data-testid | `string \| undefined` | | | ### DropdownMenuRadioItem | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------------- | --------- | ------------------------------------------------- | | value \* | `string` | | Required — identifies this radio within the group | | disabled | `boolean \| undefined` | | | | closeOnSelect | `boolean \| undefined` | | | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | variant | `{ default: string; brand: string; destructive: string; }` | `default` | | | inset | `{ true: string; }` | | | | data-testid | `string \| undefined` | | | ### DropdownMenuTrigger | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | asChild | `boolean \| undefined` | | | | value | `string \| undefined` | | A real ` ); ``` ## Usage ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronDown } from '@wallarm-org/design-system/icons'; import { SplitButton } from '@wallarm-org/design-system/SplitButton'; ``` ## Examples ### Variants Every sanctioned pairing, and the reason the pair must match: outline buttons drop the gap and overlap their borders into a single hairline, which only looks right when both halves carry the same variant. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronDown } from '@wallarm-org/design-system/icons'; import { SplitButton } from '@wallarm-org/design-system/SplitButton'; import { HStack, VStack } from '@wallarm-org/design-system/Stack'; export const Variants = () => (
); ``` ### Sizes Both halves take the same `size`, since the group aligns them rather than sizing them. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronDown } from '@wallarm-org/design-system/icons'; import { SplitButton } from '@wallarm-org/design-system/SplitButton'; import { HStack } from '@wallarm-org/design-system/Stack'; export const Sizes = () => ( ); ``` ### Content Text, icon-and-text, and icon-only leading halves. The trailing half stays a bare chevron — giving it a label doubles the width and makes the menu look like a second action. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { ChevronDown, CircleDashed } from '@wallarm-org/design-system/icons'; import { NumericBadge } from '@wallarm-org/design-system/NumericBadge'; import { SplitButton } from '@wallarm-org/design-system/SplitButton'; import { HStack, VStack } from '@wallarm-org/design-system/Stack'; export const Content = () => ( ); ``` ### With dropdown menu The real shape: the leading half performs the default action, and only the chevron opens the menu. Repeat the default inside the menu only if its wording differs there. ```tsx import { Button } from '@wallarm-org/design-system/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu'; import { ChevronDown } from '@wallarm-org/design-system/icons'; import { SplitButton } from '@wallarm-org/design-system/SplitButton'; export const WithDropdownMenu = () => ( Save as draft Save and publish Save as template ); ``` ## Props | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------- | ------- | ----------- | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | title | `string \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | data-testid | `string \| undefined` | | | --- url: https://wallarm.github.io/design-system/components/toggle-button.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # ToggleButton A button that stays pressed — for something the reader flips in place and can see the result of, like pinning a panel or holding a filter on. Reach for `Switch` when it belongs in a settings form, and `SegmentedControl` when one of several options has to win. [Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/ToggleButton) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/actions-togglebutton--overview) ```tsx import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Basic = () => ( Toggle Me ); ``` ## Usage ```tsx import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; ``` ## Examples ### Variants and colors `outline` reads as a control that is always there; `ghost` disappears until needed, for toolbars. `brand` tints the pressed state, `neutral` keeps it grey for when several toggles sit together and colour would shout. ```tsx import { HStack, VStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const VariantsAndColors = () => ( Outline Ghost Outline Ghost ); ``` ### Sizes Three heights matching `Button`, so a toggle can sit in a row of them without breaking the line. ```tsx import { HStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Sizes = () => ( Small Medium Large ); ``` ### Disabled Both states while disabled. A disabled toggle still shows whether it is on, which is the point — say elsewhere why it cannot be changed. ```tsx import { HStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Disabled = () => ( Disabled Disabled Active Ghost Disabled ); ``` ### Loading For a toggle whose effect is a request. It keeps the label's footprint and disables itself, so the pressed state does not flicker while the answer is in flight. ```tsx import { HStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Loading = () => ( Loading Loading Active Ghost Loading ); ``` ### Icons An icon before or after the label. Pressed state is carried by the whole button, not the icon, so don't swap the icon to signal it. ```tsx import { ChevronLeft, ChevronRight } from '@wallarm-org/design-system/icons'; import { HStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Icons = () => ( Left icon Right icon Both icons ); ``` ### Icon only The toolbar case: an icon alone squares the button off. `aria-label` is doing all the naming here, so it is not optional. ```tsx import { ChevronRight } from '@wallarm-org/design-system/icons'; import { HStack } from '@wallarm-org/design-system/Stack'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const IconOnly = () => ( ); ``` ### Controlled Pass `active` and own the state when something else has to move with it — a panel opening, a filter applying. Once `active` is set the button stops tracking itself. ```tsx import { useState } from 'react'; import { ToggleButton } from '@wallarm-org/design-system/ToggleButton'; export const Controlled = () => { const [active, setActive] = useState(false); return ( Controlled ); }; ``` ## Props | Prop | Type | Default | Description | | -------------- | -------------------------------------------------------------------------------------------- | --------- | ----------- | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | `false` | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | color | `string \| undefined` | `brand` | | | onChange | `ChangeEventHandler \| undefined` | | | | type | `"button" \| "submit" \| "reset" \| undefined` | | | | disabled | `boolean \| undefined` | `false` | | | name | `string \| undefined` | | | | value | `string \| number \| readonly string[] \| undefined` | | | | asChild | `boolean \| undefined` | `false` | | | size | `{ small: string; medium: string; large: string; 'inline-edit': string; }` | `large` | | | data-testid | `string \| undefined` | | | | loading | `{ true: string; }` | `false` | | | as | `C \| undefined` | | | | fullWidth | `{ true: string; false: string; }` | | | | variant | `{ outline: string; ghost: string; }` | `outline` | | | active | `{ true: string; false: string; }` | | | | onToggle | `((active: boolean, event: MouseEvent) => void) \| undefined` | | | --- url: https://wallarm.github.io/design-system/components/checkbox.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Checkbox Collects any number of choices from a limited set, or turns a single option on or off — reach for `Radio` when only one choice is allowed, and `Switch` when the change takes effect immediately instead of on submit. Past roughly ten options, a `Select` reads better than a long column of boxes. [Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/Checkbox) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/inputs-checkbox--overview) ```tsx import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; export const Basic = () => ( Accept terms and conditions ); ``` ## Usage ```tsx import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; ``` ## Examples ### Checked The checked state. Pass `checked` to drive it from your own state, or `defaultChecked` to let the checkbox keep track of it. ```tsx import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; export const Checked = () => ( Accept terms and conditions ); ``` ### Indeterminate `checked='indeterminate'` is for a parent whose children are only partly selected. Set it deliberately — a click never produces it — and clear it once every child is checked or unchecked. ```tsx import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; export const Indeterminate = () => ( Accept terms and conditions ); ``` ### Disabled All three states while disabled, so you can see that the indicator stays readable when the option cannot be changed. ```tsx import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; import { VStack } from '@wallarm-org/design-system/Stack'; export const Disabled = () => ( Accept terms and conditions Accept terms and conditions Accept terms and conditions ); ``` ### With description `CheckboxDescription` adds a second line under the label, and switches the row to a grid so that text lines up with the label rather than the box. ```tsx import { Checkbox, CheckboxDescription, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; import { Info } from '@wallarm-org/design-system/icons'; import { Tooltip, TooltipContent, TooltipTrigger } from '@wallarm-org/design-system/Tooltip'; export const WithDescription = () => ( Accept terms and conditions Additional information By clicking this checkbox, you agree to the terms and conditions. ); ``` ### Group `CheckboxGroup` ties several checkboxes to one `name` and one array of values, and owns the spacing between them. Every box stays independent: ticking one must never move another, unless it is a parent selecting all of its children. ```tsx import { Checkbox, CheckboxGroup, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; export const Group = () => ( React Solid Vue Svelte ); ``` ### Card `variant='card'` gives every option its own bordered surface. Cards exist to carry a description — that is what the extra room is for, and a card holding a bare label wastes it. Plain rows read better for short lists of short labels. ```tsx import { Checkbox, CheckboxDescription, CheckboxGroup, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; import { Info } from '@wallarm-org/design-system/icons'; import { Tooltip, TooltipContent, TooltipTrigger } from '@wallarm-org/design-system/Tooltip'; export const Card = () => ( React By clicking this checkbox, you agree to the terms and conditions. Solid Additional information By clicking this checkbox, you agree to the terms and conditions. Vue By clicking this checkbox, you agree to the terms and conditions. Svelte By clicking this checkbox, you agree to the terms and conditions. Angular By clicking this checkbox, you agree to the terms and conditions. ); ``` ### Form field Wrapped in `Field`, so the label and description above the options come from `FieldLabel` and `FieldDescription`. Shown as plain rows and as cards. ```tsx import { Checkbox, CheckboxGroup, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; import { Field, FieldDescription, FieldLabel } from '@wallarm-org/design-system/Field'; import { Info } from '@wallarm-org/design-system/icons'; import { HStack } from '@wallarm-org/design-system/Stack'; import { Tooltip, TooltipContent, TooltipTrigger } from '@wallarm-org/design-system/Tooltip'; export const FormField = () => ( Label{' '} Additional information This is an input description. React Solid Vue Svelte Label Additional information This is an input description. React Solid Vue Svelte ); ``` ## Props | Prop | Type | Default | Description | | --------------- | ---------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | | title | `string \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | htmlFor | `string \| undefined` | | | | id | `string` | | The unique identifier of the machine. | | form | `string \| undefined` | | The id of the form that the checkbox belongs to. | | defaultChecked | `CheckedState \| undefined` | | The initial checked state of the checkbox when rendered. Use when you don't need to control the checked state of the checkbox. | | disabled | `boolean \| undefined` | | Whether the checkbox is disabled | | name | `string \| undefined` | | The name of the input field in a checkbox. Useful for form submission. | | value | `string \| undefined` | | The value of checkbox input. Useful for form submission. | | ids | `ElementIds \| undefined` | | The ids of the elements in the checkbox. Useful for composition. | | readOnly | `boolean \| undefined` | | Whether the checkbox is read-only | | required | `boolean \| undefined` | | Whether the checkbox is required | | onCheckedChange | `complex` | | The callback invoked when the checked state changes. | | invalid | `boolean \| undefined` | | Whether the checkbox is invalid | | checked | `CheckedState \| undefined` | | The controlled checked state of the checkbox | | asChild | `boolean \| undefined` | | Use the provided child element as the default rendered element, combining their props and behavior. | | data-testid | `string \| undefined` | | | ### CheckboxDescription | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------- | ------- | ----------- | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | ### CheckboxGroup | Prop | Type | Default | Description | | ----------------- | --------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------- | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string[] \| undefined` | | The initial value of `value` when uncontrolled | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | disabled | `boolean \| undefined` | | If `true`, the checkbox group is disabled | | name | `string \| undefined` | | The name of the input fields in the checkbox group (Useful for form submission). | | value | `string[] \| undefined` | | The controlled value of the checkbox group | | asChild | `boolean \| undefined` | | Use the provided child element as the default rendered element, combining their props and behavior. | | readOnly | `boolean \| undefined` | | If `true`, the checkbox group is read-only | | invalid | `boolean \| undefined` | | If `true`, the checkbox group is invalid | | onValueChange | `((value: string[]) => void) \| undefined` | | The callback to call when the value changes | | maxSelectedValues | `number \| undefined` | | The maximum number of selected values | | variant | `{ default: string; card: string; }` | `default` | | ### CheckboxLabel | Prop | Type | Default | Description | | -------------- | ---------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------- | | title | `string \| undefined` | | | | defaultChecked | `boolean \| undefined` | | | | defaultValue | `string \| number \| readonly string[] \| undefined` | | | | autoFocus | `boolean \| undefined` | | | | id | `string \| undefined` | | | | tabIndex | `number \| undefined` | | | | rel | `string \| undefined` | | | | onChange | `ChangeEventHandler \| undefined` | | | | asChild | `boolean \| undefined` | | Use the provided child element as the default rendered element, combining their props and behavior. | ## Explorer --- url: https://wallarm.github.io/design-system/components/field.md --- > For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt. # Field The scaffolding around a control — label, description, error and the required marker — so the control itself only has to be the control. Only `Input`, `Textarea` and `Slider` read this context automatically; wrap anything else and you get the layout, but the labelling still has to be wired by hand. [Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/Field) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/inputs-field--overview) ```tsx import { createListCollection } from '@ark-ui/react/collection'; import { Button } from '@wallarm-org/design-system/Button'; import { Checkbox, CheckboxIndicator, CheckboxLabel } from '@wallarm-org/design-system/Checkbox'; import { Field, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet } from '@wallarm-org/design-system/Field'; import { Input } from '@wallarm-org/design-system/Input'; import { NumberInput } from '@wallarm-org/design-system/NumberInput'; import { Radio, RadioGroup, RadioIndicator, RadioLabel } from '@wallarm-org/design-system/Radio'; import { Select, SelectButton, SelectContent, SelectOption, SelectOptionText, SelectPositioner } from '@wallarm-org/design-system/Select'; import { HStack } from '@wallarm-org/design-system/Stack'; import { Switch, SwitchControl, SwitchLabel } from '@wallarm-org/design-system/Switch'; import { Textarea } from '@wallarm-org/design-system/Textarea'; export const Basic = () => { const monthsCollection = createListCollection({ items: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'], }); const yearsCollection = createListCollection({ items: ['2025', '2026', '2027', '2028', '2029'], }); return (
Payment Method All transactions are secure and encrypted Name on Card Card Number Enter your 16-digit card number Month Year CVV Amount
Billing Address The billing address associated with your payment method Same as shipping address
Subscription Plan Yearly and lifetime plans offer significant savings. Monthly ($9.99/month) Yearly ($99.99/year) Lifetime ($299.99)
Notice when delivered
Comments