# Central Design System (CDS 4) — full documentation > Version: 4.0.0-alpha.13 > Everything at once: guides, tokens and themes, components with examples and the API contract, CDS 3 migration. > Generated automatically (`bun run generate:meta` → `bun run generate:llms`). Do not edit manually. --- ## Setup ```ts import { createApp } from 'vue'; import '@central-design-system/components/styles'; import { createCds, components, directives } from '@central-design-system/components'; import App from './App.vue'; const cds = createCds({ components, directives }); createApp(App).use(cds).mount('#app'); ``` Usage: `Click me`. This is full registration: the `components` namespace import and the `styles` aggregate keep the entire library in the bundle. It suits places where the set of components is not known upfront (admin panels, sandboxes, documentation). In product applications register components individually — `createCds({ components: { CdsButton } })` plus the base style layer `@central-design-system/components/styles/common.css`; see the "Tree-shaking" guide for details. ## Conventions - **Uniform props.** `size`, `color` / `bgColor`, `appearance`, `disabled`, `loading`, `width` / `height` behave the same across all components (shared composable factories). - **Tokens, not raw values.** Colors are set via the `color` prop, not arbitrary CSS. - **Atomic Design.** Complex UI is assembled from atoms (e.g. a form: `CdsField` + `CdsLabel` + `CdsDescription` + `CdsMessages` + `CdsInput`). - The full CDS 3 → CDS 4 migration guide lives in `MIGRATION.md`. --- # Setup and themes ## Installation ```bash npm install @central-design-system/components ``` ## Wiring it into the app ```ts import { createApp } from 'vue'; import '@central-design-system/components/styles'; import { createCds, components, directives } from '@central-design-system/components'; import App from './App.vue'; const cds = createCds({ components, directives }); createApp(App).use(cds).mount('#app'); ``` After that every component is available globally: `Click me`. This is the full registration — it pulls in the entire library. For production apps register components individually, see the Tree-shaking guide. ## Style entry points | Import | What it provides | | --- | --- | | `@central-design-system/components/styles` | Aggregate: CSS of every component (~556 KB). Quick start, tree-shaking disabled | | `@central-design-system/components/styles/common.css` | Base layer (~9 KB): layers, reset, fonts, typography, grid | | `@central-design-system/components/styles/core` | Only layers, fonts and reset — no typography | | `@central-design-system/components/styles/utilities` | Utility classes | | `@central-design-system/components/styles/tailwind` | Tailwind CSS integration layer | | `@central-design-system/components/styles/legacy` | Legacy utilities for migrating from CDS 3 | With per-component registration you only include the base layer `styles/common.css` — each component ships its own CSS alongside the component itself. Tailwind CSS v4 integration (installation, layers, utilities built on CDS tokens) is covered in the Tailwind CSS + CDS guide. ## Themes The theme is set at initialization via `createCds`: ```ts const cds = createCds({ components, directives, theme: { defaultTheme: 'b2bLight' } }); ``` Built-in themes: `cdsLight` (default), `cdsDark`, `b2bLight`, `b2bDark`, `promoLight`, `promoDark`. The values of every color token in each theme are listed in ../tokens/themes.md. Custom themes, runtime theme switching and disabling theming are covered in the Theming guide. ## Icons The Phosphor iconpack is active by default and needs no setup: its CSS ships with the package. Other packs are available too (`cds`, `lucide`, `materialSymbols`, `remix`, `tabler`): ```ts import { createCds, iconsets } from '@central-design-system/components'; createCds({ icons: { defaultSet: 'remix', sets: { remix: iconsets.remix.icons }, aliases: iconsets.remix.aliases } }); ``` The `@central-design-system/icons` package (CDS 3) is deprecated, see the migration guide. --- # CDS 4 conventions The golden rule: **the source of truth is the component's `api.md`** (`references/components//api.md`). Do not invent props, events or slots — if they are not in api.md, they do not exist on the component. ## Shared props The props below come from shared composable factories and behave identically in every component that has them: | Prop | Semantics | | --- | --- | | `size` | Size: `xs` / `sm` / `md` / `lg` / `xl` or a number | | `appearance` | Appearance (visual variant); the set of values is component-specific — check the type in api.md | | `color` / `bgColor` | Content / background color as a **theme token**, not a CSS value | | `disabled` | Disabled state | | `loading` | Loading state | | `width` / `height` | Dimensions (number → px, or a CSS value as a string) | ## Tokens, not raw values - Set colors via the `color` prop / theme tokens (`--cds-color-*`), never arbitrary CSS (`#fff`, `red`). Theme tokens are listed in ../tokens/themes.md. - Spacing, radii and other values in custom SCSS go through the global `--cds-*` variables, never hardcoded. ## Atomic Design Complex UI is composed from atoms. Example — a form: the ready-made `CdsTextInput` "molecule" is internally built as `CdsField` + `CdsLabel` + `CdsDescription` + `CdsMessages` + `CdsInput`, and the same atoms are available for building your own fields. See the Forms guide for details. ## Defaults Prop defaults can be set centrally: - globally — via the `defaults` option in `createCds({ defaults: { CdsButton: { size: 'lg' } } })`; - for a subtree — with the `CdsDefaultsProvider` component (api). ## Deprecated APIs Props/components marked `_(deprecated)_` in api.md still work but will be removed. In the dev console they emit a warning prefixed `[CDS UPGRADE]`. When migrating legacy code, see the migration guide. --- # Forms with CDS 4 ## Ready-made controls For typical forms use the ready-made "molecules" (each has its own `api.md` and `examples.md` in `references/components/`): | Control | Purpose | | --- | --- | | CdsTextInput | Text field with label / description / messages | | CdsSelect | Dropdown (single / multiple) | | CdsAutocomplete | Selection with search over the list | | CdsCombobox | Selection that also accepts free-form input | | CdsCheckbox | Checkbox | | CdsRadioGroup | Radio button group | | CdsToggle | Toggle | | CdsDatePicker / CdsTimePicker | Date / time | ## CdsForm: aggregation and validation `CdsForm` groups fields, aggregates their validation (`v-model` — form validity) and exposes `validate` / `reset` / `resetValidation` methods via slot props and the exposed API. Validation rules are set on the fields with the `rules` prop (an array of functions `value → true | 'error text'`). A verified example (from Storybook): ```html ``` ```ts const valid = ref(false); const name = ref(''); const email = ref(''); const rules = { name: [ (value: string) => !!value || 'Must not be empty', (value: string) => value.length <= 10 || 'No more than 10 characters' ], email: [ (value: string) => !!value || 'Must not be empty', (value: string) => /.+@.+\..+/.test(value) || 'Invalid format' ] }; ``` Useful modes (full list in api.md): - `first-fail` — validation stops at the first invalid field; - `disabled` / `readonly` on the form propagate to every nested field. CdsForm also works with external validators (vuelidate, vee-validate) — see examples.md. ## Building your own field from atoms When no ready-made molecule fits, assemble the field from atoms: | Atom | Role | | --- | --- | | CdsField | Field wrapper: wires up label/control/messages, states | | CdsLabel | Field label | | CdsDescription | Supporting description | | CdsMessages | Error messages / hints | | CdsInput | Bare input control | Before assembling, open the `api.md` of every atom — take the set of props and slots only from there. --- # CDS 3 → CDS 4 migration (digest) This is a short digest. **The full version with Before/After for every change is `MIGRATION.md` at the root of the `@central-design-system/components` npm package.** ## Severity legend | Marker | Meaning | | --- | --- | | ⚠️ **BREAKING** | Breaks existing code — action required | | 🔁 **RENAMED** | Rename — mechanical search & replace | | 🟠 **DEPRECATED** | Works in 4.x, will be removed in 5.x | | ✨ **NEW** | New capability, nothing breaks | ## Quick checklist - [ ] Replace the CSS import: `@central-design-system/components/dist/cds.css` → `@central-design-system/components/styles` (⚠️ breaking). - [ ] If you use `@central-design-system/icons` — the package is 🟠 deprecated; switch to iconpacks via `createCds({ icons })` (see setup.md). - [ ] Go through the component rename index below. - [ ] Run the build and check the dev console: `[CDS UPGRADE]` warnings point at deprecated props. ## Key breaking changes - ⚠️ **CSS import path** — `dist/cds.css` is no longer a public entry point; import `@central-design-system/components/styles` instead. - ⚠️ **Legacy reset is off by default** — the global reset from CDS 3 is now opt-in: `@use '@central-design-system/components/styles' with ($legacy-reset: true);`. - ⚠️ **CSS architecture on ITCSS + CSS Layers** — the cascade is driven by native `@layer`; global overrides of CDS styles without `!important` may now resolve differently. ## Component rename and removal index | CDS 3 | CDS 4 | | --- | --- | | `CdsDropdown` | 🔁 `CdsSelect` (the native ``: on mobile devices the system list is more familiar. Filtering, virtual scrolling and the menu slots do not work in this mode. **Example — `NativeSelect.vue`:** ```vue ``` ### Tuning the list The `list-props` prop passes any props through to the inner CdsList — in the example `bgColor` paints the background of the menu, and `slim` removes the inner paddings of the menu so that the list fills it entirely. `item-color` sets the color of the selected items (`color` is taken by default). In the same way `menu-props` configures the inner CdsMenu, and `menu-height` limits the height of the menu. **Example — `ListProps.vue`:** ```vue ``` ### Slots The select gives up every part of the menu and the field for replacement. The slots of the field itself are the same as in CdsTextInput. | Slot name | Description | | :----------------------------- | :----------------------------------------------------------- | | `item` | The whole list item; receives `item`, `index` and `props` | | `selection` | The selected value in the field | | `chip` | The chip of a selected value (with `chips`) | | `prepend-item` / `append-item` | Content before and after the list | | `no-data` | Menu content when the list is empty | | `subheader` / `divider` | Group subheader and divider | | `menu-header` / `menu-footer` | Menu header and footer; receive `search` and `filteredItems` | The `item` slot overrides the rendering of an item completely. Be sure to pass `props` into `CdsListItem` — the selection handler lives in them. In the example every country shows its flag and capital. **Example — `ItemSlot.vue`:** ```vue ``` The `selection` slot is your own display of what is selected in the field: the first two countries are shown as tags, the rest are folded into a counter. **Example — `SelectionSlot.vue`:** ```vue ``` The `prepend-item` and `append-item` slots add your own entries to the start and the end of the list. In the example the start holds "Select all countries" with a checkbox, and the end — "Load more" with a simulated fetch through `loading`. **Example — `PrependAppendSlot.vue`:** ```vue ``` The `menu-header` and `menu-footer` slots add content to the header and the footer of the menu — a search field and a confirmation button, for example. Both slots receive `search` (written into `v-model:search`, it filters the list) and `filteredItems`. **Example — `MenuHeaderAndFooterSlots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Show two or three options as radio buttons — every option is visible without a click. | A select hides a short list behind an extra click. | | The label names the field and stays visible after the choice. | Without a label the selected value does not explain what the field is. | | A select picks a value. Leave actions to buttons or to a menu. | Commands inside a select look like a field value: it is unclear what will happen after the choice. | ## Scenarios ### Submitting a form The select takes part in CdsForm validation on a par with text fields: `rules` will not let the form through without a chosen subject. Give optional fields a default value — that way the form is filled in faster. **Example — `FormSubmit.vue`:** ```vue ``` ### Dependent lists The list of cities depends on the chosen country: while there is no country the second select is turned off through `disabled`, and while the options are loading it shows `loading`. When the country changes the chosen city is reset — otherwise a non-existent pair would stay in the form. **Example — `DependentSelects.vue`:** ```vue ``` ### Picking assignees The combination of `multiple`, `chips` and `closable-chips` shows the chosen people as tags and removes them by the cross right in the field. The `item` slot adds an avatar and a role — that way it is easier to find the right person in a long list. **Example — `Assignees.vue`:** ```vue ``` ### Sorting the results A compact select controls the order of a list: `hide-messages` removes the bottom block, `aria-label` replaces the hidden label for screen readers. The choice is applied at once — an "Apply" button is not needed. **Example — `Sorting.vue`:** ```vue ``` ## API ### CdsSelect **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state of the field | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `appendInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner append slot, after the content of the field | | `autocomplete` | `string \| undefined` | — | no | Helps to influence browser suggestions. The `suppress` value changes the name attribute of the fields, and `off` relies on the browser to stop suggesting values on its own. Any other value is passed to the built-in autocomplete of the corresponding element. | | `autofocus` | `boolean \| undefined` | — | no | Enables autofocus | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `centerAffix` | `boolean \| undefined` | — | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `chips` | `boolean \| undefined` | — | no | Shows the selected values as removable chips (CdsTag). | | `clearable` | `boolean \| undefined` | — | no | Shows the clear button | | `clearIcon` | `IconValue \| undefined` | `'remove'` | no | Icon of the clear button | | `closableChips` | `boolean \| undefined` | — | no | Adds a remove button to the chips (relevant together with `chips`). | | `closeText` | `string \| undefined` | `'$cds.close'` | no | Text for screen readers describing the close action of the menu. | | `color` | `string \| undefined` | — | no | Component color | | `counter` | `string \| number \| boolean \| undefined` | — | no | Character counter. Accepts a boolean, a number or a string | | `counterValue` | `number \| ((value: any) => number) \| undefined` | — | no | Custom counter value. Either a number or a function computing it from the current value | | `customFilter` | `FilterFunction \| undefined` | — | no | Your own value filtering function. Receives the value, the search query and the item, returns a match or `-1` | | `customKeyFilter` | `FilterKeyFunctions \| undefined` | — | no | Separate filtering functions for specific item keys — an object of the form `{ key: function }` | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | — | no | Renders the menu content upfront, without waiting for the first opening. | | `ellipsis` | `boolean \| undefined` | — | no | In multiple mode keeps the selected values on a single line with an ellipsis | | `error` | `boolean \| undefined` | — | no | Error state | | `errorMessages` | `string \| readonly string[] \| null \| undefined` | `[]` | no | Puts the component into the error state and passes custom error messages. They are merged with any checks defined in the `rules` prop. This field does not trigger validation. | | `filterKeys` | `FilterKeys \| undefined` | — | no | Item keys the search runs over. By default filtering goes by the item title | | `filterMode` | `FilterMode \| undefined` | `'intersection'` | no | How the results of `customKeyFilter` and of the general filtering are combined: by intersection, by union or by replacement | | `focused` | `boolean \| undefined` | — | no | Controls the focus state of the component. When `true`, the component is considered focused and may apply the corresponding styles or behavior. | | `hideDetails` | `boolean \| "auto" \| undefined` | — | no | Hides the details block (messages and hints). With the 'auto' value the block is hidden when there are no messages | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `hideNoData` | `boolean \| undefined` | — | no | Hides the menu and the "no data" placeholder when the item list is empty. | | `hideSelected` | `boolean \| undefined` | — | no | Hides the already selected items from the menu list. | | `hint` | `string \| undefined` | — | no | Hint text shown under the input | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `isSelectAll` | `string \| boolean \| undefined` | `false` | no | Adds a "select all" entry as the first item of the list (for `multiple` only). `true` uses the default `$cds.selectAll` caption, a string sets your own caption. | | `itemChildren` | `SelectItemKey` | `false` | no | Object field that holds the child items, or a function that returns them | | `itemColor` | `string \| undefined` | — | no | Color of the selected items in the menu list. `color` is used by default. | | `itemProps` | `SelectItemKey` | `'props'` | no | Object field that holds the props of the item, or a function that returns them | | `items` | `any[] \| undefined` | `[]` | no | Array of items to display | | `itemTitle` | `SelectItemKey` | `'title'` | no | Object field used as the item title, or a function that returns it | | `itemType` | `SelectItemKey` | `'type'` | no | Object field that defines the item type (`item`, `divider`, `subheader`), or a function that returns it | | `itemValue` | `SelectItemKey` | `'value'` | no | Object field used as the item value, or a function that returns it | | `label` | `string \| undefined` | — | no | Label text of the component | | `listProps` | `CdsListProps \| undefined` | — | no | Props passed through to the inner CdsList component. | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `menu` | `boolean \| undefined` | — | no | Controls the open state of the dropdown menu (v-model:menu). | | `menuHeight` | `string \| number \| undefined` | `178` | no | Maximum height of the dropdown menu. | | `menuIcon` | `IconValue \| undefined` | `'chevron-down'` | no | Icon indicating that the menu can be expanded. | | `menuProps` | `CdsMenuProps \| undefined` | — | no | Props passed through to the inner CdsMenu component. | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelModifiers` | `Record \| undefined` | — | no | v-model modifiers passed by Vue to process the field value | | `modelValue` | `any` | `null` | no | Value of the component in v-model. If the component supports the multiple prop, an empty array is used by default. | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several values. The selected items are shown as chips or as a list. | | `name` | `string \| undefined` | — | no | Name of the input | | `nativeSelect` | `boolean \| undefined` | — | no | Renders a native HTML select instead of the custom dropdown menu (CdsMenu) | | `noAutoScroll` | `boolean \| undefined` | — | no | Turns off the automatic scrolling of the menu to the selected item on opening. | | `noDataText` | `string \| undefined` | `'$cds.noDataText'` | no | Text shown in the menu when the item list is empty. | | `noFilter` | `boolean \| undefined` | — | no | Turns off the built-in filtering — the list is shown as is, the search is handled outside | | `openOnClear` | `boolean \| undefined` | — | no | Opens the menu after the value is cleared. | | `openText` | `string \| undefined` | `'$cds.open'` | no | Text for screen readers describing the open action of the menu. | | `persistentClearable` | `boolean \| undefined` | — | no | Always show the clear button, not only on hover or focus | | `persistentCounter` | `boolean \| undefined` | — | no | Always show the counter, not only while the field is in use | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `persistentPlaceholder` | `boolean \| undefined` | — | no | Always show the placeholder instead of hiding it while the field is in use | | `placeholder` | `string \| undefined` | — | no | Placeholder text shown in an empty field | | `prefix` | `string \| undefined` | — | no | Text prefix shown before the field value | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `prependInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner prepend slot, before the content of the field | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `returnObject` | `boolean \| undefined` | — | no | Return an object in the model value instead of an array | | `reverse` | `boolean \| undefined` | — | no | Reverses the order of the elements inside the field | | `role` | `string \| undefined` | `'combobox'` | no | ARIA role for the native input element | | `rules` | `readonly ValidationRule[] \| undefined` | `[]` | no | Accepts an array of items of different types: functions, booleans and strings. Functions take the input value as an argument and must return either true / false, or a string with an error message. The input goes into the error state if a function returns false (or any value in the array is false) or is a string. | | `search` | `string \| undefined` | — | no | Current value of the search query used to filter the items (v-model:search). | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `suffix` | `string \| undefined` | — | no | Text suffix shown after the field value | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| { component: Component; } \| null \| undefined` | `{ component: CdsModalTransition }` | no | Transition animation | | `type` | `string \| undefined` | `'text'` | no | Type of the native input | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `valueComparator` | `ValueComparator \| undefined` | — | no | Function that compares item values to determine the selected state | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `update:focused` | `[focused: boolean]` | The focus state of the component changed (v-model:focused). | | `update:menu` | `[ue: boolean]` | The open state of the dropdown menu changed (v-model:menu). | | `update:modelValue` | `[value: any]` | The selected value changed (v-model). | | `update:search` | `[value: string]` | The search query changed (v-model:search). | | `update:selectedAll` | `[value: boolean]` | The "all selected" state changed (for `multiple` + `isSelectAll` only). | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `append-inner` | `CdsInputDefaultSlot` | Slot added at the end of the input | | `append-item` | `any` | Content after the item list in the menu. | | `chip` | `{ item: any; internalItem: ListItem; index: number; props: Record; }` | Custom rendering of the chip of a selected value (relevant together with `chips`). | | `clear` | `CdsInputDefaultSlot & { props: Record; }` | Slot for a custom clear icon (shown when the clearable prop is true). | | `description` | `{ description: string \| undefined; props: Record; }` | Default slot of the CdsDescription component | | `details` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `divider` | `{ props: Record; index: number; }` | Custom rendering of a divider in the menu list. | | `item` | `{ item: any; internalItem: ListItem; index: number; props: Record; }` | Custom rendering of an item of the menu list. | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | | `loader` | `LoaderSlotProps` | Slot for a custom loader (shown when the loading prop is true). | | `menu-footer` | `{ search: Ref; filteredItems: ListItem[]; }` | Content of the menu footer. Receives the current search query and the filtered items. | | `menu-header` | `{ search: Ref; filteredItems: ListItem[]; }` | Content of the menu header. Receives the current search query and the filtered items. | | `message` | `CdsMessageSlot` | Slot for customizing the content of a message | | `messages` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `no-data` | `any` | Content shown in the menu when the item list is empty. | | `prepend` | `CdsInputSlot` | Adds an element before the input | | `prepend-inner` | `CdsInputDefaultSlot` | Slot added at the start of the input | | `prepend-item` | `any` | Content before the item list in the menu. | | `selection` | `{ item: any; internalItem: ListItem; index: number; }` | Custom rendering of the selected value inside the field. | | `subheader` | `{ props: Record; index: number; }` | Custom rendering of a group subheader in the menu list. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `controlRef` | `HTMLElement \| undefined` | Ref to the control of the input | | `fieldIconColor` | `string \| undefined` | Icon color | | `filteredItems` | `ListItem[]` | Items filtered by the current search query. | | `isDirty` | `boolean` | Whether the input is dirty | | `isDisabled` | `boolean` | Whether the input is disabled | | `isFocused` | `boolean` | Whether the component is focused. | | `isPure` | `boolean` | Whether the input is pure | | `isReadonly` | `boolean` | Whether the input is read-only | | `isValid` | `boolean \| null` | Whether the input is valid | | `isValidating` | `boolean` | Whether the input is being validated | | `reset` | `() => Promise` | Resets the input to its initial state | | `resetValidation` | `() => Promise` | Resets the validation of the input | | `selectAll` | `() => void` | Toggle the selection of all available items (for `multiple` + `isSelectAll` only). | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsSelectionControl _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 32/32 · 51 unit · 4 e2e · 5 known bugs · lines 98.4% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ The base of the selection controls: a native `input` with state icons, a label and a description. The component holds the value, can work with its own `true`/`false` values and with multiple selection, and picks up the settings of CdsSelectionControlGroup. The checkboxes, radio buttons and toggles of the design system are built on it. **See also:** For regular selection take the ready-made controls — CdsCheckbox, CdsRadio, CdsToggle: they already have the icons, the sizes, the state colors and the block of messages. `CdsSelectionControl` is needed when the control you want is not in the library. ## Anatomy On the left is the control: the state icon from `true-icon` / `false-icon` and an invisible native `input` on top of it. On the right are the label (CdsLabel) and the description (CdsDescription); a click on the label toggles the control. The component has no sizes of its own: the area of the control is set by the `--cds-selection-control-width` and `--cds-selection-control-height` CSS variables, and the gap up to the label is the free space inside that area. In the examples below the distance is added with the `gap-x-2` class. ## Variations ### Type and icons The `type` prop sets the type of the native `input` — the behavior and the accessibility depend on it: a `checkbox` is turned on and off, a `radio` is only selected. The state icons come from `true-icon` and `false-icon`; without them the control has no visible part. **Example — `TypeAndIcons.vue`:** ```vue ``` ### Label and description The `label` prop names the option, `description` explains it. Name the option briefly in the label, and move the details — the price, the deadlines, the limitations — into the description. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Values By default the model holds `true` or `false`. The `true-value` and `false-value` props replace them with your own values — handy when what goes to the server is not a boolean. **Example — `Values.vue`:** ```vue ``` ### Multiple selection If the model is an array, the controls work in `multiple` mode: every control adds its `value` to it and removes it when unchecked. The mode is turned on automatically — the `multiple` prop is needed only to set it by hand. Comparing the values is the job of `value-comparator`, a deep comparison by default. **Example — `Multiple.vue`:** ```vue ``` ### States `disabled` blocks the control and dims its color, `readonly` forbids changing the value while keeping the look. `error` puts the `--error` modifier on the root — the error color is drawn for it by the styles of the particular control, the base component has none. **Example — `States.vue`:** ```vue ``` ### Colors `color` sets the color of the selected control, `base-color` the color of an unselected one. The values are the colors of the design system palette. **Example — `Colors.vue`:** ```vue ``` ### Layout Inside a flex container the control stretches together with its neighbors. The `inline` prop leaves it the width of its content — that way the controls can stand in a row without extra gaps. **Example — `Inline.vue`:** ```vue ``` ### Slots Slots replace the content coming from the props and the markup of the control itself. | Slot | Description | | ------------- | --------------------------------------------------------------------------------------------------------- | | `default` | Content inside the control area, before the `input`. Receives the classes and the background color styles | | `input` | The whole markup of the control. Receives `model`, the ready `inputNode` and the current `icon` | | `label` | Content of the label. Replaces `label` | | `description` | Content of the description. Replaces `description` | **Example — `Slots.vue`:** ```vue ``` ## Scenarios ### A selection tile The `input` slot replaces the icon with your own markup, and the native `input` from `inputNode` stays on top of it and catches the clicks and the focus. The size of the clickable area is set by the `--cds-selection-control-width` and `--cds-selection-control-height` variables, and the state arrives in the slot through `model`. **Example — `Tile.vue`:** ```vue ``` ### Consent before submitting The control does not show messages — that is the job of the CdsInput wrapper. Without it, render the error text next to the control and pass `error` to it: the modifier will come in handy for your styles. **Example — `Consent.vue`:** ```vue ``` ## API ### CdsSelectionControl **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `color` | `string \| undefined` | — | no | Component color | | `defaultsTarget` | `string \| undefined` | — | no | Name of the child component the group prop values are passed to as defaults | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | Puts the component into the visual error state | | `falseIcon` | `IconValue \| undefined` | — | no | Icon of the unselected state | | `falseValue` | `any` | — | no | Value for the false state. | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `inline` | `boolean \| undefined` | — | no | Renders the control as an inline element — the container does not stretch to the full width | | `label` | `string \| undefined` | — | no | Label text of the component | | `modelValue` | `any` | — | no | Value of the component (v-model). In a group it is the value of the selected control, with `multiple` — an array of the selected values | | `multiple` | `boolean \| null \| undefined` | `null` | no | Allows selecting several values — the model becomes an array. Turns on automatically when an array is passed to `modelValue` | | `name` | `string \| undefined` | — | no | The `name` attribute of the native input element. In a group one name joins all the nested controls | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `trueIcon` | `IconValue \| undefined` | — | no | Icon of the selected state | | `trueValue` | `any` | — | no | Value for the true state. | | `type` | `string \| undefined` | — | no | Type of the native input element — `radio` or `checkbox`, for example | | `value` | `any` | — | no | Value used when the component is selected inside a group. When it is not set, a unique identifier is used. | | `valueComparator` | `ValueComparator \| undefined` | `true` | no | Function comparing the model value with the `value` of the control. Deep comparison by default | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: any]` | Fires when the model of the component changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ backgroundColorClasses: Ref; backgroundColorStyles: Ref; }` | Default slot | | `description` | `{ description: string \| undefined; props: Record; }` | Default slot of the CdsDescription component | | `input` | `SelectionControlSlot` | Slot for the default input element. | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | **Exposed** | Name | Type | Description | | --- | --- | --- | | `input` | `HTMLInputElement \| undefined` | Ref to the native `input` element — a checkbox or a radio button. | | `isFocused` | `boolean` | Whether the control is focused. | --- # CdsSelectionControlGroup _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 22/22 · 36 unit · 4 known bugs · lines 97.1% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ A container for a set of selection controls: it holds the shared value, hands the nested CdsSelectionControl the type, the icons, the colors and the states, and ties them together with a single `name` attribute. The radio button group of the design system is built on it. **See also:** For a ready group with a title, a description and messages take CdsRadioGroup: it is assembled from this group and the CdsInput wrapper. `CdsSelectionControlGroup` is needed when you build your own set of controls. ## Variations ### Shared model and type The value of the selected control is held by the group: `v-model` is on it, every nested control only has its own `value`. The `type`, `true-icon` and `false-icon` props are handed by the group to all the controls, and the shared `name` attribute for the native `input` elements is created by the group itself — it can be overridden with the `name` prop. **Example — `Model.vue`:** ```vue ``` ### Multiple selection An array in the model turns on `multiple` mode: every control adds its `value` to it. The mode is turned on automatically — the `multiple` prop is needed only to set it by hand. **Example — `Multiple.vue`:** ```vue ``` ### Direction By default the controls line up in a row and split the width of the group evenly. `direction="vertical"` puts them in a column — handier for long captions and for sets with descriptions. **Example — `Direction.vue`:** ```vue ``` ### States `disabled` blocks the whole group, `readonly` forbids changing the selection without changing the look, `error` puts every control into the error state. A single option is blocked by the `disabled` prop of the control itself. **Example — `States.vue`:** ```vue ``` ### Colors and icons `color` sets the color of the selected control, `base-color` the color of the unselected ones, `true-icon` and `false-icon` the pair of state icons. The values apply to all the controls of the group at once. **Example — `ColorsAndIcons.vue`:** ```vue ``` ### Passing the settings through The group gives its settings to the component whose name is set in `defaults-target` — `CdsSelectionControl` by default. Put the name of a ready-made control there and the group starts controlling it: that is how CdsRadioGroup hands the settings to the radio buttons. **Example — `DefaultsTarget.vue`:** ```vue ``` ## Scenarios ### Filtering by categories An array model collects the checked categories, and the list is rebuilt on the fly through a computed. `inline` leaves the controls the width of their captions, so the filters go in a dense row. **Example — `Filters.vue`:** ```vue ``` ### Selection tiles The group does not dictate the markup to the controls: in the `input` slot every control draws its own tile, while the group still holds the selected value and ties the native `input` elements together with a single `name`. **Example — `Tiles.vue`:** ```vue ``` ## API ### CdsSelectionControlGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `color` | `string \| undefined` | — | no | Component color | | `defaultsTarget` | `string \| undefined` | — | no | Name of the child component the group prop values are passed to as defaults | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | Puts the component into the visual error state | | `falseIcon` | `IconValue \| undefined` | — | no | Icon of the unselected state | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `inline` | `boolean \| undefined` | — | no | Renders the control as an inline element — the container does not stretch to the full width | | `modelValue` | `any` | — | no | Value of the component (v-model). In a group it is the value of the selected control, with `multiple` — an array of the selected values | | `multiple` | `boolean \| null \| undefined` | `null` | no | Allows selecting several values — the model becomes an array. Turns on automatically when an array is passed to `modelValue` | | `name` | `string \| undefined` | — | no | The `name` attribute of the native input element. In a group one name joins all the nested controls | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `trueIcon` | `IconValue \| undefined` | — | no | Icon of the selected state | | `type` | `string \| undefined` | — | no | Type of the native input element — `radio` or `checkbox`, for example | | `valueComparator` | `ValueComparator \| undefined` | `true` | no | Function comparing the model value with the `value` of the control. Deep comparison by default | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: any]` | Fires when the selection inside the group changes. Passes the new value of the group | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | The controls of the group — checkboxes or radio buttons | --- # CdsSkeletonLoader _Category: Feedback · since 4.0.0_ _Tests: API 12/12 · 18 unit · 1 known bug · lines 94.1% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ A skeleton shows the shape of the future content while the data is loading: instead of an empty screen the user immediately sees where the heading, the text and the buttons will appear. The ready-made types (`type`) are assembled from "bones" — blanks for an avatar, a line of text, a button or a table. **See also:** A skeleton fits the first load of a block or a page. For waiting inside a single action — submitting a form, saving — take the `loading` prop of CdsButton or CdsProgressCircle. If there is no data at all, show CdsEmptyState. ## Anatomy A skeleton is a container with nested "bones": every bone repeats the shape of one element of the future content. The `list-item-avatar-two-line, actions` type unfolds into a circle for the avatar, two lines of text and two buttons. ## Variations ### Types The `type` prop takes a ready-made structure from the catalog: `article` — a heading and a paragraph, `card` — an image with a heading, `table` — a header, rows and a footer. **Example — `Presets.vue`:** ```vue ``` ### Your own structure The type can be described with a string: a comma-separated list puts bones one after another, and `@N` repeats a bone N times. An array of strings works the same way as a comma-separated list. **Example — `Structure.vue`:** ```vue ``` ### Catalog of types All the built-in types and their structures. Any of them can be inserted into your own string as a bone — `heading, table-row@3`. **Example — `AllTypes.vue`:** ```vue ``` ### Sizes The `width`, `height`, `min-width` and `max-width` props set the size of the container — the bones stretch along it. Give the skeleton the same size as the future content, so that the layout does not jump when the data arrives. **Example — `Sizes.vue`:** ```vue ``` ### Replacing the content Put the content into the default slot: while `loading` is true, the skeleton is visible in its place, and afterwards — the content itself, with no wrapper. The `loading-text` prop sets the `aria-label` — a screen reader will announce what exactly is loading. **Example — `Loading.vue`:** ```vue ``` ### Without animation The `boilerplate` prop turns the shimmer off. Such a skeleton is a blank for mockups and static prototypes; on a live screen it does not communicate waiting. **Example — `Boilerplate.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The skeleton repeats the structure of the future content: a heading, lines of text, buttons. | A gray rectangle instead of a structure does not tell what will appear in its place. | | As many bones as there will be items — the list does not jump after loading. | Eight skeleton rows for three records: the content arrives and the height collapses. | | The shimmer animation shows that the loading is happening right now. | A static boilerplate on a live screen reads as broken layout — it is for mockups only. | ## Scenarios ### List of participants While the list is loading, `type="list-item-avatar-two-line@3"` holds the space for three records: an avatar and two lines of text in each. The slot hands over the ready list as soon as the data arrives, so no `v-if` is needed in the template. **Example — `FeedList.vue`:** ```vue ``` ### Table of contracts A skeleton of `table-heading, table-row@3` repeats the header and the rows of the table, and `loading-text` explains the wait to the screen reader. The number of rows matches the page size of the data — after loading, the height of the block does not change. **Example — `DataTable.vue`:** ```vue ``` ### Page frame On the first load of a page the blocks load independently, so each one has its own skeleton: the list of sections is `list-item@4`, the content is `heading, paragraph, paragraph`. A block that is ready appears right away, without waiting for its neighbor. **Example — `PageLayout.vue`:** ```vue ``` ## API ### CdsSkeletonLoader **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `boilerplate` | `boolean \| undefined` | `false` | no | Boilerplate mode: turns the shimmer animation off (for prototyping). | | `height` | `string \| number \| undefined` | — | no | Component height | | `loading` | `boolean \| undefined` | `false` | no | Shows the skeleton instead of the slot content while loading. | | `loadingText` | `string \| undefined` | — | no | Text for the `aria-label` while loading. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `theme` | `string \| undefined` | — | no | Component theme | | `type` | `(string & {}) \| "text" \| "block" \| "article" \| "button" \| "table" \| "divider" \| "subtitle" \| "chip" \| "avatar" \| "actions" \| "heading" \| "sentences" \| "paragraph" \| "card" \| "card-avatar" \| "date-picker" \| "date-picker-options" \| "date-picker-days" \| "list-item" \| "list-item-avatar" \| "list-item-two-line" \| "list-item-avatar-two-line" \| "list-item-three-line" \| "list-item-avatar-three-line" \| "table-heading" \| "table-thead" \| "table-tbody" \| "table-row-divider" \| "table-row" \| "table-tfoot" \| readonly ((string & {}) \| "text" \| "block" \| "article" \| "button" \| "table" \| "divider" \| "subtitle" \| "chip" \| "avatar" \| "actions" \| "heading" \| "sentences" \| "paragraph" \| "card" \| "card-avatar" \| "date-picker" \| "date-picker-options" \| "date-picker-days" \| "list-item" \| "list-item-avatar" \| "list-item-two-line" \| "list-item-avatar-two-line" \| "list-item-three-line" \| "list-item-avatar-three-line" \| "table-heading" \| "table-thead" \| "table-tbody" \| "table-row-divider" \| "table-row" \| "table-tfoot")[] \| undefined` | `'block'` | no | Skeleton type: a predefined preset or an arbitrary structure string (or an array of strings). | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content rendered instead of the skeleton once the loading is done. | --- # CdsSlideGroup _Category: Atoms · since 4.0.0_ _Tests: none yet — behavior is not covered by automated tests_ A slide group lays a set of elements out in a single scrollable line: when the elements do not fit, the strip is paged with arrows. It can also drive a selection through `v-model` — CdsTabs and CdsTagGroup are built on the slide group. **See also:** For a bar of sections take the ready CdsTabs, for picking tags take CdsTagGroup, and to page through slides one by one take CdsSlideView. ## Anatomy Arrow buttons sit at the edges of the container, and the strip of elements scrolls between them. The arrows appear only when the strip does not fit into the container, and they page it by the width of the visible area. ## Variations ### Scrolling and arrows By default the arrows appear on a desktop when the elements do not fit into the container; on mobile the strip is scrolled with a finger without arrows. The `show-arrows` prop changes this behavior: `true` shows the arrows on overflow and on mobile, `desktop` and `mobile` always show them on the matching devices, `always` always shows them, `never` never does. **Example — `Arrows.vue`:** ```vue ``` ### Selecting elements Wrap the elements into `CdsSlideGroupItem` and the group starts driving the selection: `v-model` holds the value of the selected element from its `value` prop. `CdsSlideGroupItem` itself renders nothing — its slot receives `isSelected` and `toggle`, and how to show the selected state is up to you. The `mandatory` prop forbids clearing the last selection. **Example — `Selection.vue`:** ```vue ``` The `multiple` prop allows selecting several elements — `v-model` becomes an array, and `max` limits the number of selected ones. **Example — `Multiple.vue`:** ```vue ``` ### The active element in the center When the selection changes, the strip scrolls to the active element itself — that is the job of `scroll-to-active`, which is on by default. The `center-active` prop additionally keeps the active element in the center of the container. **Example — `CenterActive.vue`:** ```vue ``` ### Vertical group The `direction="vertical"` prop turns the strip into a column — limit its height with `max-height` on the group itself. **Example — `Vertical.vue`:** ```vue ``` ### Slots | Slot | Description | | --------- | -------------------------------------------------------------- | | `default` | The elements of the strip, usually `CdsSlideGroupItem` | | `prev` | Your own content for the "back" button instead of the arrow | | `next` | Your own content for the "forward" button instead of the arrow | All the slots receive the `prev`, `next`, `select` and `isSelected` methods. The click on the area of an arrow is handled by the group itself, so it is enough to put the visuals only into `prev` / `next`. The icons of the default arrows are changed without slots — with the `prev-icon` and `next-icon` props. **Example — `CustomArrows.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The arrows hint that the strip scrolls and that there are more elements than visible. | Without arrows a cut-off element is the only hint of scrolling, and it is easy to miss. | | Elements of the same kind and size page predictably and read as a single row. | A mix of components of different sizes makes the strip ragged — it no longer reads as one list. | ## Scenarios ### Booking an appointment Two slide groups with a selection: the strip of days with `center-active` keeps the selected date in the center, and the strip of times is more compact — with `size="sm"` buttons. Both lists use `mandatory`: a booking always has a selected date and time. **Example — `Booking.vue`:** ```vue ``` ### A strip of documents The slide group works without a selection too — as a regular scrollable strip. The cards go straight into the `default` slot without `CdsSlideGroupItem`, and the arrows page the strip by the width of the visible area. **Example — `CardsRow.vue`:** ```vue ``` ### A formatting bar A toolbar inside a narrow container: icon buttons with `aria-label`, `multiple` allows turning several formats on at once, and the `show-arrows="always"` arrows page through the tools that did not fit. **Example — `Toolbar.vue`:** ```vue ``` ## API ### CdsSlideGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `centerActive` | `boolean \| undefined` | — | no | Forces the active component to be aligned to the center. | | `contentClass` | `any` | — | no | Adds classes to the slide group container | | `contentStyle` | `any` | — | no | Adds inline styles to the slide group container | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `mandatory` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `mobile` | `boolean \| null \| undefined` | `null` | no | Determines the display mode of the component: `true` renders it in mobile mode, `false` in desktop mode, `null` makes the mode depend on the current breakpoint. | | `mobileBreakpoint` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | — | no | Sets the breakpoint at which the component switches to mobile mode. Accepts a number (for example, 600) or the name of a predefined breakpoint (`xs`, `sm`, `md`, `lg`, `xl`). | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `nextIcon` | `IconValue \| undefined` | `'chevron-right'` | no | Icon for the “next” button. | | `prevIcon` | `IconValue \| undefined` | `'chevron-left'` | no | Icon for the “previous” button. | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `scrollToActive` | `boolean \| undefined` | `true` | no | When `true`, the container scrolls the active component into view whenever it changes. | | `selectedClass` | `string \| undefined` | `'cds-slide-group-item--active'` | no | CSS class applied in the selected state | | `showArrows` | `string \| boolean \| undefined` | — | no | Changes how the arrows are shown. By default the arrows appear on desktop devices when the container overflows and stay hidden on mobile devices. `true` also shows them on mobile on overflow, `desktop` always shows them on desktop, `mobile` always on mobile, `always` on both, and `never` disables the arrows. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `SlideGroupSlot` | Slot for the CdsSlideGroupItem components | | `next` | `SlideGroupSlot` | Slot for the "next" button. | | `prev` | `SlideGroupSlot` | Slot for the "previous" button. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `focus` | `(location?: "next" \| "prev" \| "first" \| "last" \| undefined) => void` | Focuses the component | | `hasNext` | `boolean` | Returns true if there are elements after the current index. | | `hasPrev` | `boolean` | Returns true if there are elements before the current index. | | `scrollOffset` | `number` | Returns the scroll offset of the element | | `scrollTo` | `(location: "next" \| "prev") => void` | Scrolls to the element by its index | | `selected` | `readonly string[]` | Returns the index of the selected element | ### CdsSlideGroupItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `value` | `any` | — | no | Value of the component within the group | **Events** | Name | Type | Description | | --- | --- | --- | | `group:selected` | `[value: { value: boolean; }]` | Fires when an element is selected inside the group. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ isSelected: boolean; select: (value: boolean) => void; toggle: () => void; selectedClass: false \| (string \| undefined)[]; }` | Slot for the content | --- # CdsSlideView _Category: Atoms · since 4.0.0_ _Tests: none yet — behavior is not covered by automated tests_ A slide view shows one slide out of a set and switches them with a shift animation: arrows, swipes and `v-model` page forward and backward. It is the base for carousels and step-by-step interfaces — CdsCarousel is built on the slide view. **See also:** For a carousel of images with dot delimiters and autoplay take the ready CdsCarousel, for sections with a navigation bar take CdsTabs, and for a strip where several elements are visible at once take CdsSlideGroup. ## Anatomy The container shows one active `CdsSlideViewItem` slide, and the arrows at the edges page to the neighboring ones — they are turned on by the `show-arrows` prop. `v-model` holds the index of the active slide — or the value from the `value` prop of the slide, if it is set. ## Variations ### Arrows By default there are no arrows — the slides are paged with a swipe on touch devices or programmatically through `v-model`. The `show-arrows` prop turns the arrows on: `true` shows them at all times, `"hover"` only on hover over the slide. Keyboard navigation comes together with the arrows. The swipe is turned off with `:touch="false"`, and the icons of the arrows are changed with the `prev-icon` and `next-icon` props. **Example — `ArrowsHover.vue`:** ```vue ``` ### Vertical arrows The `vertical-arrows` prop gathers the arrows turned on by `show-arrows` into a column at the edge of the slide: `true` or `'left'` puts them on the left, `'right'` on the right. **Example — `VerticalArrows.vue`:** ```vue ``` ### Continuous paging The `continuous` prop closes the slides into a ring: the first one follows the last. Without it the matching arrow is hidden on the edge slides. **Example — `Continuous.vue`:** ```vue ``` ### Direction The `direction="vertical"` prop moves the slides vertically — the navigation keys change together with the animation: ↑ / ↓ work instead of ← / →. **Example — `Vertical.vue`:** ```vue ``` ### Transitions The `crossfade` prop replaces the shift with a soft dissolve — a good fit when the slides are not lined up in a sequence. On a single `CdsSlideViewItem` the animation is configured with the `transition` and `reverse-transition` props: the name of your own transition animation or `false` to turn it off. The content of a slide is rendered on the first show; the `eager` prop renders it right away — useful for SEO. **Example — `Crossfade.vue`:** ```vue ``` ### Slots | Slot | Description | | -------------- | ----------------------------------------------------------------------------- | | `default` | The `CdsSlideViewItem` slides | | `prev`, `next` | Your own paging buttons; they receive `props` with `onClick` and `aria-label` | | `additional` | Content after the slides: indicators, a counter, captions | The `additional` slot receives a `group` with the selection methods — but an outer `v-model` is usually enough, as in the demo with the dot indicators. **Example — `CustomControls.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Dots or a counter show how many slides there are and which one is open now. | Without a position indicator it is unclear how much content is hidden and where you are. | | Slides of the same height: the container is stable and the content below does not jump. | Slides of different heights jerk the page on every switch. | ## Scenarios ### A step-by-step form The steps of a questionnaire are switched with buttons through `v-model`: the arrows stay off and the swipes are muted with `:touch="false"` — the only way to move is "Back" and "Next". The height of the container animates to the content of the active step automatically. **Example — `Wizard.vue`:** ```vue ``` ### Customer testimonials The quotes are not lined up in a sequence, so `crossfade` replaces the shift. The arrows appear on hover (`show-arrows="hover"`), the position is shown by a counter in the `additional` slot, and `continuous` pages the testimonials in a loop. **Example — `Testimonials.vue`:** ```vue ``` ### An events feed A compact widget with vertical paging: `direction="vertical"` moves the events from the bottom up, and `vertical-arrows="right"` gathers the arrows into a column at the right edge. **Example — `EventsFeed.vue`:** ```vue ``` ## API ### CdsSlideView **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `continuous` | `boolean \| undefined` | — | no | Loops the navigation: from the last slide you move to the first one and back | | `crossfade` | `boolean \| undefined` | — | no | Slides change with a smooth crossfade instead of a shift | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `mandatory` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `nextIcon` | `IconValue \| undefined` | `'chevron-right'` | no | Icon of the button that moves to the next slide | | `prevIcon` | `IconValue \| undefined` | `'chevron-left'` | no | Icon of the button that moves to the previous slide | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `reverse` | `boolean \| undefined` | — | no | Inverts the direction of the transition animation between slides | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `showArrows` | `string \| boolean \| undefined` | — | no | Shows the navigation arrows. `'hover'` — only while the pointer is over the component | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `touch` | `boolean \| TouchHandlers \| undefined` | — | no | Controls swipe navigation: `false` turns the gestures off, an object sets your own touch handlers | | `transitionDuration` | `number \| undefined` | — | no | Duration of the transition animation between slides, in milliseconds | | `verticalArrows` | `boolean \| "left" \| "right" \| undefined` | — | no | Places the navigation arrows vertically: `'left'` or `'right'` — the side, `true` — the default side | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[]` | Fires when the active slide changes. Passes the value of the new active slide | **Slots** | Name | Type | Description | | --- | --- | --- | | `additional` | `{ group: GroupProvide; }` | Extra content above the slides — indicator dots or your own navigation, for example | | `default` | `{ group: GroupProvide; }` | Slides. The slot props carry the group state for controlling the active slide | | `next` | `{ props: ControlProps; }` | Button that moves to the next slide. The slot props are ready to bind to your own button | | `prev` | `{ props: ControlProps; }` | Button that moves to the previous slide. The slot props are ready to bind to your own button | **Exposed** | Name | Type | Description | | --- | --- | --- | | `group` | `GroupProvide` | State of the slide group: the list of elements, the active slide and the switching methods. | ### CdsSlideViewItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | — | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `reverseTransition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the reverse direction. A transition component name, or `false` to turn the animation off | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `transition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the forward direction. A transition component name, or `false` to turn the animation off | | `value` | `any` | — | no | Value of the component within the group | **Events** | Name | Type | Description | | --- | --- | --- | | `group:selected` | `[value: { value: boolean; }]` | Fires when a slide is selected inside the group. `value` tells whether the slide became active | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the slide | **Exposed** | Name | Type | Description | | --- | --- | --- | | `groupItem` | `GroupItemProvide` | State of the slide inside the group: whether it is selected, its value and the toggle method. | --- # CdsStages _Category: Feedback · since 4.0.0 · status: deprecated_ _Tests: API 13/13 · 17 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 9 axe recommendations (v4.0.0-alpha.11)_ A stage bar shows the course of a business process: which stages are behind, which one is running now and where the process stopped because of an error. The component only displays the status — the stages are not clickable, so the bar fits cards, headers and lists where the state of the process has to be read at a glance. **See also:** The component is deprecated: do not write new code with it. It keeps working across the whole 4.x line and prints a `[CDS UPGRADE]` warning in the dev console; it will be removed in 5.0. To show the course of a process without step navigation use CdsSteps — without the `interactive` prop the steps are not clickable, and the header without `items` works as a status tracker (see the "Request status" scenario). Mind that the look differs: `CdsStages` is an arrow bar, `CdsSteps` is a row of indicators with a progress line. To switch between equally weighted sections — CdsTabs. ## Anatomy The bar is a row of stages: each one has a title, and the arrow separators between neighboring stages set the direction of the process. The color of a stage encodes its state: neutral — the stage is ahead, accented — it is the current one, green — passed, red — an error. ## Variations ### Stages Pass an array of objects into `items`: the title and the value of a stage are read by the `item-title` and `item-value` keys (`title` and `value` by default). As long as `current` is not set, all the stages stay neutral — the process has not started yet. **Example — `Default.vue`:** ```vue ``` ### The current stage `current` takes the value of the active stage: it is highlighted with the accent color, and the stages to the left of it are marked as passed. **Example — `Current.vue`:** ```vue ``` ### An error An error is set in the data of a stage — `props: { error: true }` on an `items` element. The stage turns red once the process has reached it: when it is the current one or is already passed. **Example — `Error.vue`:** ```vue ``` ### Finishing the process The `finished` prop marks all the stages as passed at once — the value of `current` does not matter then. **Example — `Finished.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A stage title is one or two words: the bar is read at a glance. | Sentence-long titles stretch the stages and repeat the same words. | | Three to six stages: each one is a meaningful milestone of the process. | Splitting into tiny steps turns the bar into an unreadable comb. | | The error belongs to the stage where the process stopped: usually the current one. | Errors on passed stages alarm for nothing: the process moved on, they no longer matter. | ## Scenarios ### Order progress The value of `current` comes from the data and changes as the order is processed. Once the last stage is passed, turn `finished` on — the whole bar becomes green. **Example — `OrderTracking.vue`:** ```vue ``` ### Rejected during review The status of the listing is stored as a single string, and `items`, `current` and `finished` are computed from it. On rejection the "Проверка" stage gets `props.error` and turns red — the user immediately sees where the process stopped. **Example — `Moderation.vue`:** ```vue ``` ### Statuses in a list The bar is compact and does not intercept clicks, so it is easy to repeat in every row of a list or a table: the width comes from a utility class, and the state of the row from its own `current`, `finished` and error. **Example — `StatusList.vue`:** ```vue ``` ## API ### CdsStages **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `current` | `string \| number \| null \| undefined` | `null` | no | Current stage | | `finished` | `boolean \| undefined` | — | no | All stages are finished | | `itemChildren` | `SelectItemKey` | `'children'` | no | Object field that holds the child items, or a function that returns them | | `itemProps` | `SelectItemKey` | `'props'` | no | Object field that holds the props of the item, or a function that returns them | | `items` | `any[] \| undefined` | `[]` | no | Array of items to display | | `itemTitle` | `SelectItemKey` | `'title'` | no | Object field used as the item title, or a function that returns it | | `itemType` | `SelectItemKey` | `'type'` | no | Object field that defines the item type (`item`, `divider`, `subheader`), or a function that returns it | | `itemValue` | `SelectItemKey` | `'value'` | no | Object field used as the item value, or a function that returns it | | `returnObject` | `boolean \| undefined` | — | no | Return an object in the model value instead of an array | | `theme` | `string \| undefined` | — | no | Component theme | | `valueComparator` | `ValueComparator \| undefined` | — | no | Function that compares item values to determine the selected state | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isCurrent` | `(idx: number) => boolean` | Checks whether the stage with the given index is the current one. | | `isFinished` | `boolean` | Whether all the stages are passed. | --- # CdsStatus _Category: Feedback · since 4.0.0_ _Tests: API 8/8 · 20 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A status is a non-interactive indicator of the state of an object: the request is paid, the document is under review, the payment is overdue. The `status` prop sets the semantics — the color and the icon — while `variant` sets the display mode: a prominent filled badge or compact text with a colored icon. **See also:** For labels with arbitrary palette colors — categories, filters — take CdsTag; for counters and marker dots in the corner of an element — CdsBadge. ## Variations ### Statuses The `status` prop sets one of the five semantic statuses. Assign the values to the states of the object: `info` — neutral, `progress` — the process is running, `warning` — needs attention, `success` — success, `danger` — a problem. **Example — `Statuses.vue`:** ```vue ``` ### Display mode The `variant` prop controls how prominent the status is. `fill` (the default) is a badge with a colored background; it catches the eye in lists and tables. `text` has no background, a colored status icon and neutral text: the semantics are kept, but the status does not compete with the surrounding content. A similar "colored icon + text" pair can be assembled by hand — from CdsIcon with the `color` prop and text next to it. That way you are free to pick the icon and the color; `variant="text"`, on the other hand, guarantees that the icon and the color always match the semantics of the status. **Example — `Variants.vue`:** ```vue ``` ### Indicator The `indicator` prop puts a dot in the status color before the text. The status reads more compactly and fits dense lists well. With `variant="text"` the dot replaces the icon. **Example — `Indicator.vue`:** ```vue ``` ### Pulse The `pulse` prop makes the dot pulse and works only together with `indicator`. Enable it where a process is running right now: a check, an upload, a sync. Finished and static states do not need it — endless motion distracts (WCAG 2.2.2). Under `prefers-reduced-motion` the pulse is turned off. **Example — `Pulse.vue`:** ```vue ``` ### Status change When the status changes, the color of the fill, the text and the dot transitions smoothly, without a jump. **Example — `StatusChange.vue`:** ```vue ``` ### Text The text comes from the `text` prop. When you need markup — emphasis, non-breaking spaces — use the `default` slot: it replaces the text from the prop. **Example — `WithSlot.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The color of the status matches its meaning: success is green, a problem is red. | The color contradicts the meaning — the user reads the signal before the text and draws the wrong conclusion. | | The status text is one or two words, so the state is read instantly. | A long phrase does not fit and gets truncated with an ellipsis. Move the details into the text next to it. | | One display mode per list: the statuses are easy to compare across rows. | Mixing fill and text in neighboring rows looks like equal states have different importance. | ## Scenarios ### Statuses of records in a list In lists and tables a `fill` badge shows the state of a record at first glance. Keep the vocabulary of statuses short and consistent across the whole section — then the column can be scanned by color, without reading it. **Example — `RecordsList.vue`:** ```vue ``` ### Tracking a process The status reflects the course of an asynchronous process: after being sent for review the object moves to `progress`, and once it is done — to `success`. The user sees the current state without reloading the page. **Example — `ProcessTracking.vue`:** ```vue ``` ### A status in a details block In a dense info block — an invoice card, a panel of details — the `fill` background pulls attention away. The `text` variant sits in line with the rest of the data: the colored icon keeps the semantics, and the text stays neutral. **Example — `DetailsCard.vue`:** ```vue ``` ## API ### CdsStatus **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `indicator` | `boolean \| undefined` | — | no | A dot in the status color before the text. With `variant="text"` it replaces the icon. | | `pulse` | `boolean \| undefined` | — | no | Pulse of the dot. Works only together with `indicator`. Enable it only where a process is running right now: endless motion distracts and, per WCAG 2.2.2, should not accompany static states. Not animated under `prefers-reduced-motion`. | | `status` | `"progress" \| "danger" \| "success" \| "warning" \| "info" \| undefined` | `'info'` | no | Semantic status — drives the color and the default icon. | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `theme` | `string \| undefined` | — | no | Component theme | | `variant` | `"fill" \| "text" \| undefined` | `'fill'` | no | Display mode: `fill` — a filled badge without an icon; `text` — a transparent background with a colored status icon. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Slot for the status text. | --- # CdsSteps _Category: Navigation · since 4.0.0_ _Tests: none yet — behavior is not covered by automated tests_ The stepper walks the user through a multi-step process: it shows which steps are done, which one is active and how many are left. It can switch the content of the steps and renders the "Back" / "Next" buttons out of the box, while a header without content works as a status tracker. **See also:** The stepper shows the progress of a business process without step navigation on its own: without the `interactive` prop the steps are not clickable, and the header without `items` works as a status tracker — see the ["Request status"](#request-status) scenario. The CdsStages component, which used to solve the same task, is deprecated. For sections of equal weight that are switched in any order, use CdsTabs. ## Anatomy The stepper consists of a header with the steps, a content area and the navigation buttons — the last two appear when the steps are set through `items`. Every step is a state indicator with a progress line up to the next step, a title and a description. ## Variations ### Steps from an array Pass an array of objects into `items` — the title, the description and the value of a step are read by the `item-title`, `item-text` and `item-value` keys (by default `title`, `text`, and the value is the ordinal number of the step starting from one). The content of a step comes from the `item.{value}` slots or from the shared `item` slot, and the "Back" / "Next" buttons are rendered automatically: their texts are changed by the `prev-text` / `next-text` props, and `hide-actions` hides the buttons. **Example — `Default.vue`:** ```vue ``` ### States Steps can also be declared by hand — with `CdsStepsItem` components in the default slot: only the header is rendered, the content and the navigation stay up to you. A step has three states: `error` — finished with an error, `warning` — needs attention, `disabled` — unavailable. **Example — `States.vue`:** ```vue ``` ### Interactive steps The `interactive` prop allows jumping to any step by click or from the keyboard — the progress animates in a cascade and `disabled` steps are skipped. The `readonly` prop turns the transitions off while keeping the appearance. **Example — `Interactive.vue`:** ```vue ``` ### Vertical layout The `vertical` prop turns the header into a column — a good fit for status trackers and narrow panels. **Example — `Vertical.vue`:** ```vue ``` ### Slots Slots give control over every area of the stepper: | Slot | Description | | ------------------------------------ | ------------------------------------------------------------------ | | `default` | Your own `CdsStepsItem` when `items` is not set | | `title`, `text` | Title and description of every step | | `header-item`, `header-item.{value}` | Full replacement of the step content in the header | | `item`, `item.{value}` | Step content in the content area | | `actions` | Your own navigation buttons (receives the `prev` / `next` methods) | | `prev`, `next` | Replacement of a single button inside the default navigation block | The `title` and `text` slots receive the state of the step (`selected`, `complete`, `error`, `first`, `last`…) — handy for adding tags and hints. **Example — `Slots.vue`:** ```vue ``` ### Model The active step is controlled through `v-model`. For steps from `items` the default value is the ordinal number starting from one; for steps declared by hand it is the index starting from zero. Your own value is set by the `item-value` key or by the `value` prop of `CdsStepsItem`. The `prev` / `next` methods are available through the component ref. **Example — `Model.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The step title is a short name of the stage; the details go into the text description. | Sentence-long titles inflate the header and are hard to scan. | | Three to five steps: the process stays graspable and every step is a meaningful stage. | Seven steps or more scare the user with their volume — merge the adjacent stages. | | The description adds to the title: what the step needs or what will happen. | A description that repeats the title adds nothing — drop it. | ## Scenarios ### Checkout wizard A classic wizard: every step gets its own `item.{value}` slot with a form. The built-in buttons page through the steps, and the fields are bound to shared state through `v-model`, so the data survives the transitions. **Example — `Checkout.vue`:** ```vue ``` ### Confirmation before moving on The `actions` slot replaces the built-in buttons and receives the `prev` and `next` methods — you define the conditions of the transition yourself. Here the "Next" button stays disabled until the user accepts the terms of service. **Example — `Confirmation.vue`:** ```vue ``` ### Request status A header without `items` works as a process tracker: only the steps, no content and no buttons. The completed stages are marked with indicators, and the descriptions carry the dates and the deadlines. The `vertical` prop lays the history out in a column. **Example — `StatusTracker.vue`:** ```vue ``` ## API ### CdsSteps **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `hideActions` | `boolean \| undefined` | — | no | Hides the step navigation buttons | | `interactive` | `boolean \| undefined` | — | no | Allows jumping to a step by click | | `itemProps` | `SelectItemKey` | `'props'` | no | Object field that holds the props of the item, or a function that returns them | | `items` | `any[] \| undefined` | `[]` | no | Array of items to display | | `itemText` | `SelectItemKey` | `'text'` | no | Key of the step description in an items element object | | `itemTitle` | `SelectItemKey` | `'title'` | no | Object field used as the item title, or a function that returns it | | `itemValue` | `SelectItemKey` | `'value'` | no | Object field used as the item value, or a function that returns it | | `mandatory` | `boolean \| "force" \| undefined` | `'force'` | no | Requires at least one item to stay selected | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `nextText` | `string \| undefined` | `'$cds.steps.next'` | no | Text of the next step button | | `prevText` | `string \| undefined` | `'$cds.steps.prev'` | no | Text of the previous step button | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `required` | `boolean \| "force" \| undefined` | `'force'` | no | Requires at least one item to stay selected | | `selectedClass` | `string \| undefined` | `'cds-steps-item--current'` | no | CSS class applied in the selected state | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `vertical` | `boolean \| undefined` | — | no | Vertical layout | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: unknown]` | Fired when the v-model value changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `CdsStepsSlot` | Custom navigation buttons | | `default` | `CdsStepsSlot` | Header content: custom CdsStepsItem (used when items is not set) | | `header-item` | `CdsStepsItemSlot` | Custom rendering of every step content in the header | | `item` | `CdsStepsInternalItem` | Step content in the content area | | `next` | `CdsStepsActionsSlot` | Custom next step button | | `prev` | `CdsStepsActionsSlot` | Custom previous step button | | `text` | `CdsStepsItemSlot` | Custom description of every step | | `title` | `CdsStepsItemSlot` | Custom title of every step | **Exposed** | Name | Type | Description | | --- | --- | --- | | `next` | `() => void` | Moves to the next step. | | `prev` | `() => void` | Moves to the previous step. | ### CdsStepsActions **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| "next" \| "prev" \| undefined` | `false` | no | Disables the navigation buttons: both or a specific one | | `nextText` | `string \| undefined` | `'$cds.steps.next'` | no | Text of the next step button | | `prevText` | `string \| undefined` | `'$cds.steps.prev'` | no | Text of the previous step button | **Events** | Name | Type | Description | | --- | --- | --- | | `click:next` | `[]` | Click on the next step button | | `click:prev` | `[]` | Click on the previous step button | **Slots** | Name | Type | Description | | --- | --- | --- | | `next` | `CdsStepsActionsSlot` | Custom next step button | | `prev` | `CdsStepsActionsSlot` | Custom previous step button | ### CdsStepsItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | The step finished with an error | | `interactive` | `boolean \| undefined` | — | no | Allows jumping to a step by click | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `text` | `string \| undefined` | — | no | Step description | | `title` | `string \| undefined` | — | no | Step title | | `value` | `any` | — | no | Value of the component within the group | | `warning` | `boolean \| undefined` | — | no | The step needs attention | **Events** | Name | Type | Description | | --- | --- | --- | | `group:selected` | `[value: { value: boolean; }]` | Fired when the selected state of the step inside the group changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsStepsItemSlot` | Extra step content after the title and the description | | `text` | `CdsStepsItemSlot` | Custom step description | | `title` | `CdsStepsItemSlot` | Custom step title | ### CdsStepsView **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `crossfade` | `boolean \| undefined` | — | no | Slides change with a smooth crossfade instead of a shift | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `reverse` | `boolean \| undefined` | — | no | Inverts the direction of the transition animation between slides | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `transitionDuration` | `number \| undefined` | — | no | Duration of the transition animation between slides, in milliseconds | | `verticalArrows` | `boolean \| "left" \| "right" \| undefined` | — | no | Places the navigation arrows vertically: `'left'` or `'right'` — the side, `true` — the default side | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: any]` | Fired when the v-model value changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `additional` | `{ group: GroupProvide; }` | Extra content above the slides — indicator dots or your own navigation, for example | | `default` | `{ group: GroupProvide; }` | Slides. The slot props carry the group state for controlling the active slide | | `next` | `{ props: ControlProps; }` | Button that moves to the next slide. The slot props are ready to bind to your own button | | `prev` | `{ props: ControlProps; }` | Button that moves to the previous slide. The slot props are ready to bind to your own button | ### CdsStepsViewItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | — | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `reverseTransition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the reverse direction. A transition component name, or `false` to turn the animation off | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `transition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the forward direction. A transition component name, or `false` to turn the animation off | | `value` | `any` | — | no | Value of the component within the group | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the slide | --- # CdsSurface _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 12/12 · 12 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A surface is a container with a background from the tokens, sizes, positioning and a theme of its own. Take it when a block needs a design system background rather than a ready-made component: the backdrop of a panel, a plate, the base of your own component. **See also:** For a card with a title and actions take CdsCard, for the sections of a page take CdsLayout. `CdsSurface` is the lowest layer, without content or paddings of its own. ## Variations ### Color The `color` prop sets the background from the theme tokens and picks a contrasting text color. Besides `surface-*`, any color of the palette and any CSS color will do. Which colors exactly hide behind the tokens is decided by the theme: the `theme` prop switches it for the surface and for everything inside it. **Example — `Colors.vue`:** ```vue ``` ### Sizes The `width`, `height`, `min-width`, `max-width`, `min-height` and `max-height` props accept a number (pixels) or a string with any CSS unit. **Example — `Dimensions.vue`:** ```vue ``` ### Positioning The `position` prop sets the CSS position, `location` pins the surface to an edge of the container — `top end`, `bottom start`, `center`. Together they build a plate on top of another block. **Example — `Position.vue`:** ```vue ``` ## Scenarios ### A summary panel The surface gives the background and the sizes, while the paddings and the layout inside are up to you. The `tag` prop changes the tag of the wrapper — here it is `section`, so the block stays meaningful in the structure of the page. **Example — `SummaryPanel.vue`:** ```vue ``` ## API ### CdsSurface **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Background color of the surface | | `height` | `string \| number \| undefined` | — | no | Component height | | `location` | `Anchor \| null \| undefined` | — | no | Position of the element relative to its container, for example "top left", "center", "bottom right". | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `position` | `"absolute" \| "static" \| "fixed" \| "relative" \| "sticky" \| undefined` | — | no | CSS positioning of the component — the value of the `position` property | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | The main content of the surface. | --- # CdsTable _Category: Content · since 4.0.0_ _Tests: API 0/72 · 13 unit · lines 15.2% (v4.0.0-alpha.13) · a11y: 50 axe recommendations (v4.0.0-alpha.11)_ A table shows large sets of records in columns and takes the data work off your hands: sorting, filters, pagination, row selection and expansion, a pinned header and pinned columns. Columns are described by the `columns` prop, the records by the `data` prop. **See also:** For a plain list of similar items without columns, use CdsList; for a hierarchy without tabular data, use CdsTree. ## Anatomy Around the table there are the `header`, `toolbar` and `footer` slots and built-in pagination (the `pagination` prop). The table itself consists of a column header and rows with cells. ## Variations ### Showing data A minimal table: an array of column descriptions in `columns`, the records in `data`. The row key comes from the record's `key` field or from the `row-key` prop. **Example — `Default.vue`:** ```vue ``` The column's `align` property aligns the content — numeric values are conventionally aligned to the right. **Example — `Basic.vue`:** ```vue ``` ### Sizes The `size` prop controls the density: `md` is the default, `sm` and `xs` are for data-dense screens. **Example — `Size.vue`:** ```vue ``` ### Rows The `row-class-name` property computes a row class from the record: the built-in `cds-table--striped` class alternates the background, `cds-table__row--warning` and `cds-table__row--error` add a status highlight. The `hovered` prop highlights the row under the cursor. **Example — `Stripe.vue`:** ```vue ``` **Example — `StateRow.vue`:** ```vue ``` ### Cell content The column's `ellipsis` property truncates long text to a single line with an ellipsis — in cells and in headers alike. **Example — `Ellipsis.vue`:** ```vue ``` ### Responsiveness The column's `responsive` property lists the breakpoints at which the column is visible — secondary columns get hidden on narrow screens. **Example — `Responsive.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Numbers are aligned right — the digits line up and the amounts are easy to compare. | Numbers aligned left blend into the text, and you have to read closely to compare values. | | Truncate long text with the column's ellipsis — rows keep the same height and the full text stays available in a tooltip. | Raw long text stretches the row and the table loses its rhythm. | | Highlight only the rows that need attention with a status. | When nearly every row is highlighted, the signal stops working. | ## Documentation sections - Structure and headers — header grouping, merged cells, the slots around the table, column widths and declarative column descriptions. - Pinning and scrolling — pinning the header and columns while scrolling, horizontal scroll buttons. - Filters and sorting — column filters, multiple sorting, resetting and a custom filter panel. - Row selection — checkboxes, operations on the selected set, custom selection menu items. - Expansion and trees — expandable rows, nested tables and tree data. - Editing — editable cells, rows and the whole table. - Drag and drop — dragging rows and columns. - Scenarios — server-side data and ready-made recipes for product tables. ## Grouping headers A nested `children` array on a column joins several columns under a shared header — the header becomes multi-level. **Example — `GroupingTableHead.vue`:** ```vue ``` ## Merging cells The column's `customCell` function returns `colSpan`/`rowSpan` for a specific cell, while `colSpan` on the column itself merges header cells. A cell with `colSpan: 0` is not rendered. **Example — `ColspanAndRowspan.vue`:** ```vue ``` ## Header, toolbar and footer The `header`, `toolbar` and `footer` slots add your own areas around the table, and the `pagination` prop adds built-in pagination with a record counter and a page size selector. **Example — `HeaderFooter.vue`:** ```vue ``` ## Resizing columns The column's `resizable` property enables dragging the header border. The new width is reported by the `resize-column` event — store it in the column description. **Example — `ResizableColumn.vue`:** ```vue ``` ## Declarative column descriptions Instead of the `columns` array, columns can be described in the template with the `CdsTableColumn` and `CdsTableColumnGroup` components — handy when headers and cells need their own markup. **Example — `CustomizeStyles.vue`:** ```vue ``` ## Fixed header The `scroll.y` property limits the height of the table body — the column header stays in place while you scroll vertically. **Example — `FixedHeader.vue`:** ```vue ``` ## Fixed columns The column's `fixed: 'left' | 'right'` property pins it during horizontal scrolling. Set `scroll.x` wider than the container so that scrolling appears. **Example — `FixedColumns.vue`:** ```vue ``` ## Fixed columns and header Together, `scroll.x` and `scroll.y` pin both the columns and the header — the center of the table scrolls in both directions. **Example — `FixedColumnsAndHeader.vue`:** ```vue ``` ## Scroll buttons A table with horizontal scrolling can get scroll buttons: take the DOM node of the table body (`.cds-table__body`) through the component `ref` and change its `scrollLeft` on click. **Example — `ScrollButtons.vue`:** ```vue ``` ## Filters and sorting The column filter menu is set by `filters` and `onFilter`, the sorting by the `sorter` function. `sortDirections` lists the directions, `defaultSortOrder` sets the initial order, and `filterMultiple: false` switches the filter to single choice. Every change is reported by the `change` event. **Example — `FilterAndSorter.vue`:** ```vue ``` ## Multiple sorting A `sorter` object with a `multiple` field allows sorting by several columns at once — the number sets the column's priority in the chain. **Example — `MultipleSorter.vue`:** ```vue ``` ## Resetting filters and sorting The `filteredValue` and `sortOrder` column props make the state controlled: keep it outside, update it in the `change` handler — and reset it with buttons in a single assignment. **Example — `ResetFiltersAndSorters.vue`:** ```vue ``` ## Custom filter panel The column's `customFilterDropdown: true` flag enables the `customFilterDropdown` and `customFilterIcon` slots — the filter panel and its icon are drawn by your markup, a search field for example. **Example — `CustomizeFilterPanel.vue`:** ```vue ``` ## Selection and operations The `row-selection` object turns on row selection: `selectedRowKeys` holds the selected keys, `onChange` reports the changes. Actions on the selected set fit nicely in the `toolbar` slot. **Example — `SelectionAndOperation.vue`:** ```vue ``` ## Custom selection menu items The `selections` property fills the menu in the selection column header: the ready-made `SELECTION_ALL`, `SELECTION_INVERT` and `SELECTION_NONE` constants plus your own items with arbitrary logic. **Example — `CustomSelection.vue`:** ```vue ``` ## Expandable rows The `expandedRowRender` slot renders the content of an expanded row — the column with the chevron appears automatically. **Example — `ExpandableRow.vue`:** ```vue ``` ## Nested tables Anything can live inside `expandedRowRender` — including another `CdsTable` with its own columns and data. **Example — `NestedTable.vue`:** ```vue ``` ## Tree data Records with a `children` field expand as a tree. Together with `row-selection`, the `checkStrictly: false` option turns on cascading selection: checking a parent selects its children. **Example — `TreeData.vue`:** ```vue ``` ## Expanding every node The `expanded-row-keys` prop makes expansion controlled: collect the keys of every parent record — and an "Expand all" button unfolds the whole tree. **Example — `TreeDataExpandableAll.vue`:** ```vue ``` ## Editable cells The `bodyCell` slot replaces the content of a cell: on click the value turns into an input, on confirmation it turns back into text. **Example — `EditableCell.vue`:** ```vue ``` ## Editable rows The whole row switches into edit mode: inputs in every cell, the "Save" and "Cancel" buttons in the actions column. **Example — `EditableRows.vue`:** ```vue ``` ## Editable table Edit mode is turned on for the entire table at once — convenient for filling in reference data in bulk. **Example — `EditableTable.vue`:** ```vue ``` ## Dragging rows The `row-draggable` prop shows a grip icon to the left of the row. The move is reported by the `row-reorder` event — change the order in `data` yourself. A row can only be dropped between neighboring rows. **Example — `DraggableRows.vue`:** ```vue ``` ## Dragging nested rows In a tree, a row is only reordered among the siblings of its own parent: it cannot be dropped onto another level — the cursor shows "not allowed" and no event arrives. **Example — `DraggableNestedRows.vue`:** ```vue ``` ## Dragging columns The `column-draggable` prop adds a grip icon to the header. The `column-reorder` event reports the new order — update the `columns` array. **Example — `DraggableColumns.vue`:** ```vue ``` ## Dragging columns with groups A leaf column is reordered inside its own group, while a group header is dragged as a whole among neighboring groups. **Example — `DraggableColumnGroups.vue`:** ```vue ``` ## Data from the server Pagination, sorting and filters are handled on the backend: the `change` event gives you the current state of the table, the handler requests a page of data, and the `loading` prop shows the request in progress. **Example — `Ajax.vue`:** ```vue ``` ## Product moderation A header with tabs, a toolbar with search and filters, an empty state with an action and external pagination in the footer — a typical table for a moderation section. **Example — `ReceiptModeration.vue`:** ```vue ``` ## Items and prices Built-in pagination with a counter and a page size selector, a skeleton while loading and composite cells with an extra line of text. **Example — `ReceiptPositions.vue`:** ```vue ``` ## Item list A nested table inside an expanded row and a toolbar with fields and a dropdown calendar — a recipe for documents with line items. **Example — `ReceiptPositionsList.vue`:** ```vue ``` ## API ### CdsTable **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bordered` | `boolean \| undefined` | `false` | no | Show every table border | | `borderless` | `boolean \| undefined` | `false` | no | Remove every table border | | `canExpandable` | `boolean \| undefined` | `false` | no | Rows can be expanded | | `childrenColumnName` | `string \| undefined` | `'children'` | no | Name of the property holding the child records | | `columnDraggable` | `NTable.NDraggable.TColumnDraggable \| undefined` | — | no | Column drag and drop. `true` or a configuration object `{ icon, disabled, allowDrop }`. Reordering only happens among siblings inside the same group; the consumer changes the order in the `@column-reorder` handler. | | `columns` | `NTable.NColumn.TColumns \| undefined` | — | no | Table columns | | `components` | `NTable.NCustomize.TableComponents \| undefined` | — | no | Override the default table components | | `customHeaderRow` | `NTable.NCustomize.TGetComponentProps[]> \| undefined` | — | no | Sets the properties for every header row | | `customRow` | `NTable.NCustomize.TGetComponentProps \| undefined` | — | no | Sets the properties for every row | | `data` | `any[] \| undefined` | — | no | Array of records to show in the table | | `defaultExpandAllRows` | `boolean \| undefined` | `false` | no | All rows are expanded by default | | `defaultExpandedRowKeys` | `NTable.TKey[] \| undefined` | `undefined as ITableProps['defaultExpandedRowKeys']` | no | Keys of the rows expanded by default | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `expandColumnWidth` | `number \| undefined` | — | no | Width of the expand column | | `expandedRowClassName` | `NTable.NRow.TClassName \| undefined` | — | no | Classes for rows in the expanded state | | `expandedRowKeys` | `NTable.TKey[] \| undefined` | `undefined as ITableProps['expandedRowKeys']` | no | Keys of the currently expanded rows (supports v-model) | | `expandedRowRender` | `NTable.NExpand.TExpandedRowRender \| undefined` | — | no | Render function for every expanded row | | `expandFixed` | `NTable.TFixed \| undefined` | — | no | Pin the expand column (left \| right \| boolean) | | `expandIcon` | `NTable.NExpand.TRenderExpandIcon \| undefined` | — | no | Custom expand icon | | `expandIconColumnIndex` | `number \| undefined` | — | no | Index of the column that holds the expand icon | | `expandRowByClick` | `boolean \| undefined` | `false` | no | Expand the row by clicking anywhere in it | | `footer` | `NTable.NRender.TPanelRender \| undefined` | — | no | Render function for the table footer | | `getPopupContainer` | `NTable.NCustomize.TGetPopupContainer \| undefined` | — | no | Container that dropdowns are rendered into | | `header` | `NTable.NRender.TPanelRender \| undefined` | — | no | Render function for the table title | | `hovered` | `boolean \| undefined` | `false` | no | Highlight the row on hover | | `id` | `string \| undefined` | — | no | Table identifier | | `indentSize` | `number \| undefined` | `20` | no | Indent size in pixels for each nesting level | | `loading` | `boolean \| undefined` | `false` | no | Table loading state | | `locale` | `NTable.ILocale \| undefined` | — | no | Table localization (overrides the strings of the global locale) | | `pagination` | `false \| NTable.NPagination.IProps \| undefined` | — | no | Table pagination configuration | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `rowClassName` | `string \| NTable.NRow.TClassName \| undefined` | — | no | Row classes | | `rowDraggable` | `NTable.NDraggable.TRowDraggable \| undefined` | — | no | Row drag and drop. `true` or a configuration object `{ icon, disabled, allowDrop }`. Reordering only happens between siblings of the same parent; the consumer changes the order in the `@row-reorder` handler. | | `rowExpandable` | `((record: any) => boolean) \| undefined` | — | no | Whether the row can be expanded | | `rowKey` | `string \| NTable.NRow.TGetRowKey \| undefined` | `'key'` | no | Unique row key — a string or a function returning a string | | `rowSelection` | `NTable.NRow.IRowSelection \| undefined` | — | no | Row selection configuration | | `scroll` | `(NTable.TScroll & { scrollToFirstRowOnChange?: boolean \| undefined; }) \| undefined` | — | no | Whether the table can be scrolled | | `showExpandColumn` | `boolean \| undefined` | — | no | Show the expand column | | `showHeader` | `boolean \| undefined` | — | no | Whether to show the table header | | `showSorterTooltip` | `NTable.NSorter.TTooltip \| undefined` | `true` | no | Whether to show sorting tooltips in the header. You can pass an object with CdsTooltip properties. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `sortDirection` | `string[] \| undefined` | — | no | Sorting of the table data. 'ascend' \| 'descend' | | `sticky` | `boolean \| NTable.NSticky.ISticky \| undefined` | — | no | Sticky behavior for the header and the scrollbar | | `tableLayout` | `NTable.TLayout \| undefined` | — | no | Fixed or auto layout | | `theme` | `string \| undefined` | — | no | Component theme | | `toolbar` | `NTable.NRender.TPanelRender \| undefined` | — | no | Render function for the table toolbar | | `transformCellText` | `NTable.NCell.TTransformCellText \| undefined` | — | no | Transform the text inside a cell | **Events** | Name | Type | Description | | --- | --- | --- | | `change` | `[pagination: NTable.NPagination.IProps, filters: Record, sorter: NTable.ISorterResult \| NTable.ISorterResult[], extra: NTable.ICurrentData]` | Fired when the pagination, the filters or the sorting change. | | `columnReorder` | `[info: NTable.NDraggable.IColumnReorderInfo]` | Fired when a column is dragged. The consumer changes the order of the columns. | | `expand` | `[expanded: boolean, record: any]` | Fired when a row is expanded or collapsed. | | `expandedRowsChange` | `[expandedKeys: NTable.TKey[]]` | Fired when the set of expanded rows changes. | | `resizeColumn` | `[width: number, column: NTable.NColumn.IColumn]` | Fired when a column is resized. | | `rowReorder` | `[info: NTable.NDraggable.IRowReorderInfo]` | Fired when a row is dragged. The consumer changes the order of the data. | | `update:expandedRowKeys` | `[expandedKeys: NTable.TKey[]]` | Fired when the expanded rows are updated (v-model). | **Slots** | Name | Type | Description | | --- | --- | --- | | `bodyCell` | `{ text: any; value: any; record: any; index: number; column: NTable.NColumn.IColumn; }` | Custom render of a table body cell. | | `customFilterDropdown` | `NTable.NColumn.IFilterDropdownProps` | Custom filter dropdown of a column (used together with the column `customFilterDropdown`). | | `customFilterIcon` | `{ filtered: boolean; column: NTable.NColumn.IColumn; }` | Custom column filter icon. | | `default` | `any` | Declarative column description with CdsTableColumn / CdsTableColumnGroup. | | `emptyText` | `any` | Content shown when there is no data. | | `expandedRowRender` | `{ record: any; index: number; indent: number; expanded: boolean; }` | Render of the expanded row content. | | `expandIcon` | `NTable.NExpand.IRenderExpandIconProps` | Custom row expand icon. | | `footer` | `readonly any[]` | Table footer (the panel below the table). | | `header` | `readonly any[]` | Table title (the panel above the table). | | `headerCell` | `{ title: NTable.NColumn.TTitle; column: NTable.NColumn.IColumn; }` | Custom render of a table header cell. | | `summary` | `{ pageData: readonly any[]; }` | Summary row of the table. | | `toolbar` | `readonly any[]` | Table toolbar (the panel above the table). | **Exposed** | Name | Type | Description | | --- | --- | --- | | `table` | `any` | Reference to the internal table instance — gives access to its methods and state. | ### CdsTableColumn **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ value: any; text: any; record: any; index?: number \| undefined; renderIndex?: number \| undefined; column: NTable.NColumn.IColumn; }` | Custom render of a column cell. | | `filterIcon` | `{ filtered: boolean; column: NTable.NColumn.IColumn; }` | Custom column filter icon. | | `title` | `NTable.NColumn.ITitleProps` | Column title. | ### CdsTableColumnGroup **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Columns of the group (CdsTableColumn). | | `title` | `NTable.NColumn.ITitleProps` | Title of the column group. | --- # CdsTabs _Category: Navigation · since 4.0.0_ _Tests: API 0/107 · 5 unit · lines 68.3% (v4.0.0-alpha.13) · a11y: 8 axe recommendations (v4.0.0-alpha.11)_ Tabs split the screen into sections of equal weight and switch between them in place, without going to another page. The bar is built from `CdsTab` components or from an `items` array, and the content of the sections is switched by `CdsTabsView` and `CdsTabsViewItem`. **See also:** For a sequential process with steps and progress, use CdsSteps; to pick a single value in a form, use CdsButtonToggle. ## Anatomy Tabs consist of a bar and a content area: with tabs from `items` the content area is rendered automatically, with manual markup `CdsTabsView` is composed next to the bar. The bar is a container with tab buttons; the selected tab is highlighted by a moving slider. ## Variations ### Tabs and content Sections are declared with `CdsTab` components in the default slot, and the content with `CdsTabsViewItem` components inside `CdsTabsView`. The `value` props bind a tab to its content, and a shared `v-model` keeps the bar and the content area in sync. **Example — `Default.vue`:** ```vue ``` ### Tabs from an array Pass an array of strings or `{ text, value }` objects into `items` — the tabs and the content area are rendered automatically. The content of a section comes from the `item.{value}` slots, the label of a tab from the `tab.{value}` slots. **Example — `Items.vue`:** ```vue ``` ### Alignment The `align` prop pushes the tabs to the start of the bar (the default), to the center or to the end. **Example — `Align.vue`:** ```vue ``` ### Layout The `grow` prop stretches the tabs across the whole width of the bar — every tab takes an equal share of the free space. **Example — `Grow.vue`:** ```vue ``` The `fixed-tabs` prop also equalizes the width of the tabs, but caps it at 300px and centers the group. **Example — `FixedTabs.vue`:** ```vue ``` The `direction="vertical"` prop turns the bar into a column — handy for settings and sections with a long list. The content area is placed next to it with a regular flex row. **Example — `Vertical.vue`:** ```vue ``` ### Icons A tab accepts the same content props as a button: `prepend-icon` and `append-icon` add an icon next to the text, `icon` leaves only the icon. For an icon tab do not forget `aria-label` — without text it stays the only name of the section. **Example — `Icons.vue`:** ```vue ``` The `stacked` prop puts the icon above the text — the tab becomes taller and more noticeable. Such a layout works well with `align="center"` in mobile scenarios. **Example — `Stacked.vue`:** ```vue ``` ### States The `disabled` prop turns a tab off, `loading` shows a loading indicator instead of the content. **Example — `States.vue`:** ```vue ``` ### Colors Tabs accept the color aliases of the palette (`neutral`, `red`, `green`, `cyan`, `purple`…) or any CSS color. The `color` prop paints the text of the tabs, `active-color` the slider of the selected tab, `bg-color` the background of the whole bar, and `base-color` the background of the unselected tabs. **Example — `Colors.vue`:** ```vue ``` ### Scrolling When the tabs do not fit into the bar, it scrolls. The `show-arrows` prop adds scroll arrows, `center-active` keeps the selected tab in the center of the bar. **Example — `CenterActive.vue`:** ```vue ``` ### Slider The `slider-transition` prop picks the animation of the slider under the selected tab: `shift` (the default) moves it to the new tab, `grow` grows it in place, `fade` fades it in. The duration is set through `slider-transition-duration`, and `hide-slider` removes the slider entirely. **Example — `Slider.vue`:** ```vue ``` ### Slots Slots replace the automatic rendering from `items` when you need your own markup: | Slot | Description | | ---------------------- | ----------------------------------------------------------- | | `default` | Your own `CdsTab` when `items` is not set | | `tab`, `tab.{value}` | Tab for an `items` element: shared and for a specific value | | `item`, `item.{value}` | Section content: shared and for a specific value | | `view` | Extra content inside `CdsTabsView` | | `prev`, `next` | Your own scroll arrows | The `tab` and `item` slots receive the array element and replace the whole component — return `CdsTab` and `CdsTabsViewItem` with your own `value` from them. The `tab.{value}` and `item.{value}` slots replace the content only. **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A tab name is a short noun: the section is easy to scan. | Sentence-long names stretch the bar and read slower. | | Two to six tabs: every section is visible at once and the choice is obvious. | A dozen tabs cannot be scanned — merge adjacent sections or move the rare ones into a menu. | | Tabs are sections of equal weight that are switched in any order. | For a sequential process take CdsSteps: tabs show neither order nor progress. | ## Scenarios ### Card sections Classic tabs: a product card with sections and a shared `v-model`. The review counter is a `CdsBadge` with the `inline` prop right inside the tab slot. **Example — `ProductCard.vue`:** ```vue ``` ### List filter Tabs work without a content area too: `v-model` holds the selected status and the list is filtered by it through a `computed`. There is a single content area — only the selection changes. **Example — `ListFilter.vue`:** ```vue ``` ### Lazy loading of sections A heavy section loads on the first open: a `watch` on `v-model` fires the request, `CdsSkeletonLoader` stands in for the content while it loads, and the already loaded sections open instantly. **Example — `LazyLoad.vue`:** ```vue ``` ### Sections in a "More" menu When there are more sections than fit into the bar, the rare ones hide into a CdsMenu whose activator is a regular "More" tab in the same bar. A click on "More" immediately shows the first section from the menu, the selected item takes the place of the first visible tab (the displaced one moves into the menu), and if the menu is closed without a choice, the bar and the content return to the current section. **Example — `MoreMenu.vue`:** ```vue ``` ## API ### CdsTabs **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `align` | `"title" \| "start" \| "end" \| "center" \| undefined` | `'start'` | no | Alignment of the tabs inside the bar | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `centerActive` | `boolean \| undefined` | — | no | Forces the active component to be aligned to the center. | | `color` | `string \| undefined` | — | no | Component color | | `contentClass` | `any` | — | no | Adds classes to the slide group container | | `contentStyle` | `any` | — | no | Adds inline styles to the slide group container | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `fixedTabs` | `boolean \| undefined` | — | no | Makes all tabs the same width regardless of the length of their labels | | `grow` | `boolean \| undefined` | — | no | Stretches the tabs across the whole available width of the container | | `height` | `string \| number \| undefined` | — | no | Height of the tab bar. A number is in pixels, a string takes any CSS unit | | `hideSlider` | `boolean \| undefined` | — | no | Hides the underline indicator of the active tab | | `inset` | `boolean \| undefined` | — | no | Styling with a background: the active tab is highlighted with a filled pill instead of an underline | | `insetPadding` | `string \| number \| undefined` | — | no | Padding of the background in `inset` mode. A number is in pixels, a string takes any CSS unit | | `insetRadius` | `string \| number \| undefined` | — | no | Corner radius of the background in `inset` mode. A number is in pixels, a string takes any CSS unit | | `items` | `readonly TabItem[] \| undefined` | `[]` | no | List of tabs. A string or a number is a label, an object is a tab with arbitrary `CdsTab` props | | `mandatory` | `boolean \| "force" \| undefined` | `'force'` | no | Requires at least one item to stay selected | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `mobile` | `boolean \| null \| undefined` | `null` | no | Determines the display mode of the component: `true` renders it in mobile mode, `false` in desktop mode, `null` makes the mode depend on the current breakpoint. | | `mobileBreakpoint` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | — | no | Sets the breakpoint at which the component switches to mobile mode. Accepts a number (for example, 600) or the name of a predefined breakpoint (`xs`, `sm`, `md`, `lg`, `xl`). | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `nextIcon` | `IconValue \| undefined` | `'chevron-right'` | no | Icon for the “next” button. | | `prevIcon` | `IconValue \| undefined` | `'chevron-left'` | no | Icon for the “previous” button. | | `required` | `boolean \| "force" \| undefined` | `'force'` | no | Requires at least one item to stay selected | | `scrollToActive` | `boolean \| undefined` | `true` | no | When `true`, the container scrolls the active component into view whenever it changes. | | `selectedClass` | `string \| undefined` | `'cds-tabs--selected'` | no | CSS class applied in the selected state | | `showArrows` | `string \| boolean \| undefined` | — | no | Changes how the arrows are shown. By default the arrows appear on desktop devices when the container overflows and stay hidden on mobile devices. `true` also shows them on mobile on overflow, `desktop` always shows them on desktop, `mobile` always on mobile, `always` on both, and `never` disables the arrows. | | `sliderTransition` | `"shift" \| "grow" \| "fade" \| undefined` | — | no | Animation of the underline indicator of the active tab | | `sliderTransitionDuration` | `string \| number \| undefined` | — | no | Duration of the indicator animation in milliseconds. `0` disables the flight; by default it follows the motion scale | | `spaced` | `"both" \| "start" \| "end" \| undefined` | — | no | Pushes the prepend and append slots apart to the edges of the button. | | `stacked` | `boolean \| undefined` | — | no | Lays out the icon and the label of the tab vertically — the icon above the text | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: unknown]` | Fires when the tab is switched. Passes the value of the new active tab | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Tabs and content when they are declared by hand instead of the `items` prop | | `item` | `CdsTabsSlot` | Template for the tab content. The slot props carry the element from `items` | | `next` | `any` | Button that scrolls the tab bar forward | | `prev` | `any` | Button that scrolls the tab bar backward | | `tab` | `CdsTabsSlot` | Template for the tab label. The slot props carry the element from `items` | | `view` | `any` | The whole tab content area — replaces the automatic `CdsTabsView` | ### CdsTab **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appearance` _(deprecated)_ | `"inverse" \| "primary" \| "secondary" \| "tertiary" \| "transparent" \| undefined` | — | no | Visual appearance of the component. Deprecated: use `variant` and `color` | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `block` | `boolean \| undefined` | — | no | Stretches the button to the full width of its container | | `color` | `(string & {}) \| "neutral" \| "brand" \| "accent" \| "danger" \| "inverse" \| undefined` | `'brand'` | no | Component color: a role, a palette alias, a theme token or a CSS color | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `fixed` | `boolean \| undefined` | — | no | Fixes the width of the tab so it does not stretch to the length of its label | | `height` | `string \| number \| undefined` | — | no | Component height | | `hideSlider` | `boolean \| undefined` | — | no | Hides the underline indicator of the active tab | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `icon` | `boolean \| IconValue \| undefined` | — | no | Icon to display; the component renders as an icon-only button | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `selectedClass` | `string \| undefined` | `'cds-tab--selected'` | no | CSS class applied in the selected state | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `sliderTransition` | `"shift" \| "grow" \| "fade" \| undefined` | — | no | Animation of the underline indicator of the active tab | | `sliderTransitionDuration` | `string \| number \| undefined` | — | no | Duration of the indicator animation in milliseconds. `0` disables the flight; by default it follows the motion scale | | `spaced` | `"both" \| "start" \| "end" \| undefined` | — | no | Pushes the prepend and append slots apart to the edges of the button. | | `stacked` | `boolean \| undefined` | — | no | Stacks the icon above the text instead of placing them side by side | | `tag` | `string \| JSXComponent \| undefined` | `'button'` | no | Custom HTML tag or component to render | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `theme` | `string \| undefined` | — | no | Component theme | | `to` | `LinkTo \| undefined` | — | no | Target route or route location object for RouterLink. When set, the component behaves as a RouterLink | | `value` | `any` | — | no | Value of the component within the group | | `variant` | `"solid" \| "soft" \| "outline" \| "surface" \| "ghost" \| undefined` | `'solid'` | no | Component variant: `solid`, `soft`, `outline`, `surface`, `ghost` | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `any` | Content after the text | | `default` | `any` | Content inside the button | | `loader` | `any` | Loading indicator | | `prepend` | `any` | Content before the text | ### CdsTabsView **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `crossfade` | `boolean \| undefined` | — | no | Slides change with a smooth crossfade instead of a shift | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `reverse` | `boolean \| undefined` | — | no | Inverts the direction of the transition animation between slides | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `transitionDuration` | `number \| undefined` | — | no | Duration of the transition animation between slides, in milliseconds | | `verticalArrows` | `boolean \| "left" \| "right" \| undefined` | — | no | Places the navigation arrows vertically: `'left'` or `'right'` — the side, `true` — the default side | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: any]` | Fires when the shown content changes. Passes the value of the new active tab | **Slots** | Name | Type | Description | | --- | --- | --- | | `additional` | `{ group: GroupProvide; }` | Extra content above the slides — indicator dots or your own navigation, for example | | `default` | `{ group: GroupProvide; }` | Slides. The slot props carry the group state for controlling the active slide | | `next` | `{ props: ControlProps; }` | Button that moves to the next slide. The slot props are ready to bind to your own button | | `prev` | `{ props: ControlProps; }` | Button that moves to the previous slide. The slot props are ready to bind to your own button | ### CdsTabsViewItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | — | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `reverseTransition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the reverse direction. A transition component name, or `false` to turn the animation off | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `transition` | `string \| boolean \| undefined` | — | no | Transition used when the slide appears in the forward direction. A transition component name, or `false` to turn the animation off | | `value` | `any` | — | no | Value of the component within the group | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the slide | --- # CdsTag _Category: Content · since 4.0.0_ _Tests: API 41/41 · 67 unit · 5 known bugs · lines 96.5% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ A tag is a compact label next to an object: the status of a request, a product category, a selected filter. It takes a color from the palette, carries an icon or an avatar, can be closed with a cross and can work as a link. **See also:** To build a toggle or a filter with selection out of tags, take CdsTagGroup. For a counter or a dot indicator on top of another element use CdsBadge, and trigger actions with CdsButton — a tag only labels. ## Anatomy A tag consists of a container and content areas: `prepend` and `append` carry an icon or an avatar, the text lives in the center, and the close button appears with `closable`. ## Variations ### Colors The `color` prop paints the tag in one of the 11 palette aliases; without it the tag stays neutral gray. The text color can be overridden with `text-color` when needed. The `disabled` prop swaps the tag colors for the service colors of the disabled state and removes the reaction to clicks. **Example — `Colors.vue`:** ```vue ``` ### Sizes The `size` prop offers five sizes from `xs` to `xl`. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### Shape The `pill` prop rounds the corners completely — this shape emphasizes that the label stands on its own and looks good in a tag cloud. **Example — `Pill.vue`:** ```vue ``` ### Icons and avatars The `prepend-icon` and `append-icon` props add an icon before and after the text, `prepend-avatar` and `append-avatar` add a round avatar. The size of the icon and the avatar follows the size of the tag. **Example — `Icons.vue`:** ```vue ``` ### Slots Slots replace the content coming from props when you need full control over the markup. | Slot | Description | | --------- | ----------------------------------------------------------------------------------- | | `default` | Content of the tag. Replaces the text from `text` | | `prepend` | Content before the text. Replaces `prepend-icon` / `prepend-avatar` | | `append` | Content after the text. Replaces `append-icon` / `append-avatar` | | `close` | Content of the close button. Replaces the icon from `close-icon` | | `filter` | Content of the selection indicator in a group. Replaces the icon from `filter-icon` | **Example — `Slots.vue`:** ```vue ``` ### Link tag Pass `href` (or `to` with a `RouteLocationRaw` object from vue-router) and the tag renders as an `a` tag: it gets a cursor, keyboard focus and navigation on Enter, keeping the look of a tag. **Example — `AsLink.vue`:** ```vue ``` ### Closing The `closable` prop (or its alias `removable`) adds a close button. A click on it hides the tag and emits the `click:close` event, and the visibility can be controlled from the outside through `v-model`. The `close-icon` prop changes the icon of the button, `close-label` changes the accessible label. **Example — `Closable.vue`:** ```vue ``` ### Selection in a group Inside CdsTagGroup a tag becomes a toggle: `value` sets its value in the group, the selected state is marked with the `cds-tag--selected` class, and the `group:selected` event reports the change of selection. With `filter` the selected tag gets an indicator — `filter-icon` changes the icon, the `filter` slot changes the whole markup. The `default` slot exposes `isSelected`, `toggle` and `select` — a handy base for your own tag markup. The color of the selected tag comes from `active-color`: without it the group itself paints the selection with the brand color, and `color` stays the color of the unselected tag. **Example — `InGroup.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A label is one or two words: it reads at a glance and does not break the line. | A long phrase turns the label into a sentence and gets cut off on narrow screens. | | Tie a color to a meaning: one status — one color across the whole interface. | Random colors make people guess whether the coloring means anything at all. | | A tag labels an object, while the action stays with the button. | A tag named after an action looks clickable but does nothing. | ## Scenarios ### Selected filters Applied search filters read well as a row of closable tags: each tag removes its own filter on `click:close`, and the neighboring `tertiary` button resets everything at once. **Example — `SelectedFilters.vue`:** ```vue ``` ### Record statuses In lists and tables a colored tag shows the state of a record instantly. Assign colors to statuses once: `green` — success, `lemon` — pending, `red` — rejection, `neutral` — draft. The compact `size="sm"` does not compete with the text of the row. **Example — `Statuses.vue`:** ```vue ``` ### Adding labels An input field together with tags makes a label editor: Enter adds a new label, the cross (`closable` + `click:close`) removes an extra one. Duplicates are cut off before they get into the list. **Example — `TagInput.vue`:** ```vue ``` ## API ### CdsTag **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeClass` | `string \| undefined` | — | no | CSS class applied to the active (selected) link tag. | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendAvatar` | `string \| undefined` | — | no | Avatar displayed after (to the right of) the tag content. | | `appendIcon` | `IconValue \| undefined` | — | no | Icon displayed after (to the right of) the tag content. | | `closable` | `boolean \| undefined` | — | no | Adds a close button that hides the tag. | | `closeIcon` | `IconValue \| undefined` | `'remove'` | no | Icon of the close button. | | `closeLabel` | `string \| undefined` | `'$cds.close'` | no | Accessible label (aria-label) for the close button. | | `color` | `string \| undefined` | — | no | Component color | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `draggable` | `boolean \| undefined` | — | no | Makes the tag draggable (native drag-and-drop). | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `filter` | `boolean \| undefined` | — | no | Shows the selection indicator icon when the tag is used inside a group (CdsTagGroup). | | `filterIcon` | `IconValue \| undefined` | `'check'` | no | Icon of the selection indicator (relevant together with `filter`). | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `label` | `boolean \| undefined` | — | no | Applies the “label” style with a smaller corner radius. | | `link` | `boolean \| undefined` | — | no | Gives the tag the styles and the behavior of a link. | | `modelValue` | `boolean \| undefined` | `true` | no | Visibility of the tag (v-model). When `false` the tag is not rendered. | | `pill` | `boolean \| undefined` | — | no | Makes the corners of the tag fully rounded. | | `prependAvatar` | `string \| undefined` | — | no | Avatar displayed before (to the left of) the tag content. | | `prependIcon` | `IconValue \| undefined` | — | no | Icon displayed before (to the left of) the tag content. | | `removable` | `boolean \| undefined` | — | no | Adds a remove button (alias for `closable`). | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `tag` | `string \| JSXComponent \| undefined` | `'span'` | no | Custom HTML tag or component to render | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `to` | `LinkTo \| undefined` | — | no | Target route or route location object for RouterLink. When set, the component behaves as a RouterLink | | `value` | `any` | — | no | Value of the component within the group | **Events** | Name | Type | Description | | --- | --- | --- | | `click` | `[e: MouseEvent \| KeyboardEvent]` | Click on the tag (with a mouse or from the keyboard). | | `click:close` | `[e: MouseEvent]` | Click on the close button of the tag. | | `group:selected` | `[value: { value: boolean; }]` | Change of the tag selection state inside a group. | | `update:modelValue` | `[value: boolean]` | Change of the tag visibility (v-model). | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `any` | Content after the main content (in place of the append icon/avatar). | | `close` | `any` | Custom content of the close button. | | `default` | `{ isSelected: boolean \| undefined; selectedClass: boolean \| (string \| undefined)[] \| undefined; select: ((value: boolean) => void) \| undefined; toggle: (() => void) \| undefined; value: unknown; disabled: boolean; }` | Default content of the tag. The slot props expose the group state (selection, toggling). | | `filter` | `any` | Custom content of the selection indicator (relevant together with `filter`). | | `label` | `any` | Content of the tag label. | | `prepend` | `any` | Content before the main content (in place of the prepend icon/avatar). | --- # CdsTagGroup _Category: Content · since 4.0.0 · status: new_ _Tests: API 30/30 · 39 unit · lines 100% (v4.0.0-alpha.13) · a11y: 13 axe recommendations (v4.0.0-alpha.11)_ A tag group turns a set of CdsTag into a toggle: the selected tag is highlighted, the value is available through `v-model`, and the tags that do not fit move into a horizontal scroll. Fits catalog filters, category pickers and quick period switches. **See also:** If the choice should look like buttons, take CdsButtonToggle. For a choice out of a long list use CdsSelect, and for separate independent tags without selection just use CdsTag. ## Variations ### Selection Give every tag a `value` — exactly this value lands in `v-model`. Without `value` the index of the tag in the group becomes its value. A repeated click on the selected tag clears the selection. **Example — `Default.vue`:** ```vue ``` ### Multiple selection The `multiple` prop allows selecting several tags — `v-model` becomes an array of values. **Example — `Multiple.vue`:** ```vue ``` The `max` prop limits the number of selected tags: once the limit is reached, clicks on the remaining tags do not add to the selection. **Example — `Max.vue`:** ```vue ``` ### Mandatory selection The `mandatory` prop does not let you clear the last selection: a tag can only be switched. With the `'force'` value the first available tag is selected automatically, even when `v-model` is empty. **Example — `Mandatory.vue`:** ```vue ``` ### Selection indicator The `filter` prop adds a check icon to the selected tags — the selection reads not only from the fill. The `filter-icon` prop of the tag changes the icon, and the `filter` slot replaces it with your own markup. **Example — `Filter.vue`:** ```vue ``` ### Color and disabling The group passes the `color`, `active-color`, `disabled` and `filter` props to its tags as defaults — there is no need to repeat them on every tag. `color` paints the unselected tags, `active-color` paints the selected one; without it the selected tag stays in the brand color so that the selection reads with any palette. `disabled` blocks the whole group: the selection is visible but cannot be switched. A prop set directly on a tag wins over the value of the group. **Example — `TagDefaults.vue`:** ```vue ``` ### Layout By default the tags stand in a single row, and the extra ones move into a horizontal scroll with arrows: the group is built on CdsSlideGroup and accepts its props — `show-arrows`, `direction`, `center-active`. The `column` prop wraps the tags into rows instead of scrolling — that way all the options are visible at once. **Example — `Column.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | One group — one attribute: the values exclude each other and read as a row of equals. | Different attributes in one group: you cannot pick a category and a price at the same time. | | In a narrow block use column: all the options are visible at once. | A horizontal scroll in a narrow column hides half of the options behind an arrow. | | A tag group holds a few popular values — they are visible without expanding anything. | Dozens of values turn into a tag cloud: picking from such a list is more convenient in CdsSelect. | ## Scenarios ### Catalog filter A row of categories above the results is the most common job for a tag group. `column` shows all the categories at once, `mandatory` prevents ending up without a filter, and `v-model` gives you a ready key for the product request. **Example — `CatalogFilter.vue`:** ```vue ``` ### Picking several topics When the values do not exclude each other, turn on `multiple`. `max` keeps the selection within reasonable bounds, `filter` marks the selected topics with a check, and the hint under the group explains the limit. **Example — `Interests.vue`:** ```vue ``` ### Switching the period The group exposes the `next`, `prev` and `select` methods and the `selected` list — get them through a `ref` on the component. This is how tags get the back / forward arrows that walk through the periods in order. **Example — `PeriodStepper.vue`:** ```vue ``` ## API ### CdsTagGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `centerActive` | `boolean \| undefined` | — | no | Forces the active component to be aligned to the center. | | `color` | `string \| undefined` | — | no | Component color | | `column` | `boolean \| undefined` | — | no | Lays the tags out in several rows with wrapping instead of a horizontal scroll. | | `contentClass` | `any` | — | no | Adds classes to the slide group container | | `contentStyle` | `any` | — | no | Adds inline styles to the slide group container | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `filter` | `boolean \| undefined` | — | no | Shows a check icon on the selected tags (passed down to `CdsTag`). | | `mandatory` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `max` | `number \| undefined` | — | no | Maximum number of items that can be selected | | `mobile` | `boolean \| null \| undefined` | `null` | no | Determines the display mode of the component: `true` renders it in mobile mode, `false` in desktop mode, `null` makes the mode depend on the current breakpoint. | | `mobileBreakpoint` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | — | no | Sets the breakpoint at which the component switches to mobile mode. Accepts a number (for example, 600) or the name of a predefined breakpoint (`xs`, `sm`, `md`, `lg`, `xl`). | | `modelValue` | `any` | — | no | Value of the selected items of the group | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several items at once | | `nextIcon` | `IconValue \| undefined` | `'chevron-right'` | no | Icon for the “next” button. | | `prevIcon` | `IconValue \| undefined` | `'chevron-left'` | no | Icon for the “previous” button. | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `scrollToActive` | `boolean \| undefined` | `false` | no | When `true`, the container scrolls the active component into view whenever it changes. | | `selectedClass` | `string \| undefined` | `'cds-tag--selected'` | no | CSS class applied in the selected state | | `showArrows` | `string \| boolean \| undefined` | — | no | Changes how the arrows are shown. By default the arrows appear on desktop devices when the container overflows and stay hidden on mobile devices. `true` also shows them on mobile on overflow, `desktop` always shows them on desktop, `mobile` always on mobile, `always` on both, and `never` disables the arrows. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: unknown]` | Fires when the selected value changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsTagGroupSlotProps` | Tags of the group. The slot props expose the group state (selection, navigation). | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isSelected` | `(id: string) => boolean` | Check whether a tag with the given id is selected | | `next` | `() => void` | Select the next tag | | `prev` | `() => void` | Select the previous tag | | `select` | `(id: string, value: boolean) => void` | Select a tag by id | | `selected` | `readonly string[]` | Ids of the selected tags | --- # CdsTextArea _Category: Controls · since 4.0.0_ _Tests: API 85/85 · 95 unit · 2 e2e · 9 known bugs · lines 97.9% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ A text area is a field for multiline text: a comment, a description, a support request. Around the native `textarea` the component gathers everything a form needs: a label, a description, hints, error messages, clearing and a character counter, and with `auto-grow` it grows together with the text. **See also:** For a short single-line value use CdsTextInput, to pick from a ready list of options — CdsSelect. ## Anatomy On top are the label and the description, in the center is the multiline field with the clear button, under the field are the messages line and the character counter. The structure matches CdsTextInput: the same `prepend` / `append` zones outside and inside the border are available — as `*-icon` props and as slots of the same name. ## Variations ### Label and description The `label` prop names the field, `description` adds a supporting text under the label. The slots of the same name accept arbitrary markup. **Example — `Default.vue`:** ```vue ``` ### Number of rows The `rows` prop sets the height of the area in rows — 5 by default. Choose the height to match the expected length of the answer: two or three rows are enough for a comment. **Example — `Rows.vue`:** ```vue ``` ### Automatic height The `auto-grow` prop increases the height of the area as you type — the text does not have to be scrolled. `max-rows` limits the growth by a number of rows, `max-height` — by a height in pixels; beyond that a scrollbar appears. **Example — `AutoGrow.vue`:** ```vue ``` ### Resizing By default the user can stretch the area by its bottom right corner. The `no-resize` prop turns that off; with `auto-grow` manual resizing is disabled automatically. **Example — `NoResize.vue`:** ```vue ``` ### Clearing The `clearable` prop shows the clear icon on hover or focus, `persistent-clearable` keeps it visible at all times. **Example — `Clearable.vue`:** ```vue ``` ### Counter The `counter` prop shows a character counter: `true` — without a limit, a number — with a limit. `counter-value` accepts your own counting formula, `persistent-counter` keeps the counter visible outside of focus. To make the limit impossible to exceed, add the `maxlength` attribute. **Example — `Counter.vue`:** ```vue ``` ### States `disabled` blocks the input and lowers the contrast, `readonly` forbids changes but keeps focus and copying, `loading` shows a loading indicator — as a bar or as a circle (`loading="circle"`). **Example — `States.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The height of the area hints at the expected length: two or three rows are enough for a comment. | An area too tall for a short answer looks like a demand to write an essay. | | A counter with a limit shows the restriction upfront, and maxlength keeps it from being exceeded. | An error after the input forces the user to cut down text that is already written. | | For a short single-line value use a text field. | A text area for the subject of a request takes up space and hints at a long answer. | ## Scenarios ### Sending a request The form is made of `CdsForm`, a short subject in a text field and the message in a text area. The `rules` prop checks that the message is detailed enough, and `counter` together with `maxlength` show the limit upfront. The button gets `loading` for the duration of the request. **Example — `FeedbackForm.vue`:** ```vue ``` ### A comment in a discussion A compact comment field: `rows="1"` and `auto-grow` with `max-rows` — the area starts with a single row and grows together with the text, `hide-details` removes the bottom block. The send button is a `CdsFunctionalButton` in the `append-inner` slot; Enter sends the comment, Shift+Enter inserts a line break. **Example — `CommentReply.vue`:** ```vue ``` ### An error from the server The server response goes into `error-messages` as is — validation through `rules` is not needed for that. Reset the error when the value changes, so that the field does not complain about a text that is already fixed. **Example — `ServerError.vue`:** ```vue ``` ## API ### CdsTextArea **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state of the field | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `appendInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner append slot, after the content of the field | | `autocomplete` | `string \| undefined` | — | no | Helps to influence browser suggestions. The `suppress` value changes the name attribute of the fields, and `off` relies on the browser to stop suggesting values on its own. Any other value is passed to the built-in autocomplete of the corresponding element. | | `autofocus` | `boolean \| undefined` | — | no | Enables autofocus | | `autoGrow` | `boolean \| undefined` | — | no | Automatic growth of the text area height as you type | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `centerAffix` | `boolean \| undefined` | — | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `clearable` | `boolean \| undefined` | — | no | Shows the clear button | | `clearIcon` | `IconValue \| undefined` | `'remove'` | no | Icon of the clear button | | `color` | `string \| undefined` | — | no | Component color | | `counter` | `string \| number \| boolean \| undefined` | — | no | Character counter. Accepts a boolean, a number or a string | | `counterValue` | `number \| ((value: any) => number) \| undefined` | — | no | Custom counter value. Either a number or a function computing it from the current value | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `dirty` | `boolean \| undefined` | — | no | Marks that the value of the field was changed by the user | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | Error state | | `errorMessages` | `string \| readonly string[] \| null \| undefined` | `[]` | no | Puts the component into the error state and passes custom error messages. They are merged with any checks defined in the `rules` prop. This field does not trigger validation. | | `focused` | `boolean \| undefined` | — | no | Controls the focus state of the component. When `true`, the component is considered focused and may apply the corresponding styles or behavior. | | `hideDetails` | `boolean \| "auto" \| undefined` | — | no | Hides the details block (messages and hints). With the 'auto' value the block is hidden when there are no messages | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `hint` | `string \| undefined` | — | no | Hint text shown under the input | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `label` | `string \| undefined` | — | no | Label text of the component | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum height of the text area | | `maxRows` | `string \| number \| undefined` | — | no | Maximum number of rows while the height grows automatically | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelModifiers` | `Record \| undefined` | — | no | The v-model modifiers passed by Vue to process the field value | | `modelValue` | `any` | — | no | Value of the component in v-model. If the component supports the multiple prop, an empty array is used by default. | | `name` | `string \| undefined` | — | no | Name of the input | | `noResize` | `boolean \| undefined` | — | no | Turn off the ability to resize the text area | | `persistentClearable` | `boolean \| undefined` | — | no | Always show the clear button, not only on hover or focus | | `persistentCounter` | `boolean \| undefined` | — | no | Always show the counter, not only while the field is in use | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `persistentPlaceholder` | `boolean \| undefined` | — | no | Always show the placeholder instead of hiding it while the field is in use | | `placeholder` | `string \| undefined` | — | no | Placeholder text shown in an empty field | | `prefix` | `string \| undefined` | — | no | Text prefix shown before the field value | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `prependInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner prepend slot, before the content of the field | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `reverse` | `boolean \| undefined` | — | no | Reverses the order of the elements inside the field | | `rows` | `string \| number \| undefined` | `5` | no | Number of rows of the text area | | `rules` | `readonly ValidationRule[] \| undefined` | `[]` | no | Accepts an array of items of different types: functions, booleans and strings. Functions take the input value as an argument and must return either true / false, or a string with an error message. The input goes into the error state if a function returns false (or any value in the array is false) or is a string. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `suffix` | `string \| undefined` | — | no | Text suffix shown after the field value | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click:control` | `[e: MouseEvent]` | Fires on a click in the main area of the control | | `mousedown:control` | `[e: MouseEvent]` | Fires on a mouse button press in the main area of the control | | `update:focused` | `[focused: boolean]` | Fires when the element gains or loses focus | | `update:modelValue` | `[value: string]` | Fires when the model of the component changes | | `update:rows` | `[rows: number]` | Fires when the computed number of rows changes while the height grows automatically | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `append-inner` | `CdsInputDefaultSlot` | Slot added at the end of the input | | `clear` | `CdsInputDefaultSlot & { props: Record; }` | Slot for a custom clear icon (shown when the clearable prop is true). | | `counter` | `CdsCounterSlot` | Slot for a custom counter | | `description` | `{ description: string \| undefined; props: Record; }` | Default slot of the CdsDescription component | | `details` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | | `loader` | `LoaderSlotProps` | Slot for a custom loader (shown when the loading prop is true). | | `message` | `CdsMessageSlot` | Slot for customizing the content of a message | | `messages` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `prepend` | `CdsInputSlot` | Adds an element before the input | | `prepend-inner` | `CdsInputDefaultSlot` | Slot added at the start of the input | **Exposed** | Name | Type | Description | | --- | --- | --- | | `controlRef` | `HTMLElement \| undefined` | Ref to the control of the input | | `fieldIconColor` | `string \| undefined` | Icon color | | `isDirty` | `boolean` | Whether the input is dirty | | `isDisabled` | `boolean` | Whether the input is disabled | | `isPure` | `boolean` | Whether the input is pure | | `isReadonly` | `boolean` | Whether the input is read-only | | `isValid` | `boolean \| null` | Whether the input is valid | | `isValidating` | `boolean` | Whether the input is being validated | | `reset` | `() => Promise` | Resets the input to its initial state | | `resetValidation` | `() => Promise` | Resets the validation of the input | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsTextInput _Category: Controls · since 4.0.0_ _Tests: API 87/87 · 86 unit · 3 e2e · 6 known bugs · lines 97.2% (v4.0.0-alpha.13) · a11y: 12 axe recommendations (v4.0.0-alpha.11)_ A text field is the basic way to get data from the user: a name, an email, an amount, a search query. Around the native `input` the component gathers everything a form needs: a label, a description, hints, error messages, icons, clearing and a character counter. **See also:** For multiline text use CdsTextArea, to pick from a ready list of options use CdsSelect. ## Anatomy The first diagram shows the frame of the component: the label, the description, the field and the bottom block with messages and the counter. The second one shows how the field itself is built: the `prepend` and `append` zones outside the border, `prepend-inner` and `append-inner` inside it, and the clear button. Every zone is available both as a `*-icon` prop and as a slot of the same name. ## Variations ### Label and description The `label` prop names the field, `description` adds a supporting text under the label. The slots of the same name accept arbitrary markup. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Messages and hints There is a single text line under the field, and props split it by state: `messages` is visible at rest, `hint` — on focus, `error-messages` — on an error and on top of the rest. The `messages` and `details` slots override the content. **Example — `HintAndMessages.vue`:** ```vue ``` ### Hiding the details The `hide-details` prop removes the bottom block entirely — fields can then sit right next to each other. The `auto` value hides the block only while there is nothing to show: as soon as an error or a hint appears, the block is rendered and pushes the content below. **Example — `HideDetails.vue`:** ```vue ``` ### Icons The `prepend-icon` and `append-icon` props put an icon outside the field, `prepend-inner-icon` and `append-inner-icon` — inside it. **Example — `Icons.vue`:** ```vue ``` ### Prefix and suffix The `prefix` and `suffix` props add an immutable text at the edges of the entered value — a currency, a country code, a domain. **Example — `PrefixAndSuffix.vue`:** ```vue ``` ### Clearing The `clearable` prop shows the clear icon on hover or focus, `persistent-clearable` keeps it visible at all times. **Example — `Clearable.vue`:** ```vue ``` ### States `disabled` blocks the input and lowers the contrast, `readonly` forbids changes but keeps focus and copying, `loading` shows a loading indicator — as a bar or as a circle (`loading="circle"`). **Example — `States.vue`:** ```vue ``` ### Validation The `rules` prop accepts an array of validator functions: each one returns either `true` or a string with an error message. `validate-on` sets the moment they run — `blur`, `input` or `submit` (only on a `validate()` call). **Example — `Validation.vue`:** ```vue ``` Validators are plain functions: declare them once and reuse them across the fields of a form. Here the title is checked for being required and for its length (together with `maxlength` and the counter), and the email — for its format. **Example — `ValidationForm.vue`:** ```vue ``` ### Errors from outside The `error-messages` prop shows ready messages — the ones coming from the server, for example — independently of `rules`. `error` turns on the visual error state without any text, `max-errors` limits the number of messages. **Example — `ErrorState.vue`:** ```vue ``` ### Counter The `counter` prop shows a character counter: `true` — without a limit, a number — with a limit. `counter-value` accepts your own counting formula, `persistent-counter` keeps the counter visible outside of focus. **Example — `Counter.vue`:** ```vue ``` ### Colors The `color` prop sets the main color, `active-color` — the color on focus, `icon-color` — the color of the icons, `bg-color` — the background of the field. **Example — `Colors.vue`:** ```vue ``` ### Slots When props are not enough, the content of any block is replaced by a slot. `prepend` / `append` put elements outside the field, `prepend-inner` / `append-inner` — inside it; unlike the `*-icon` props, slots accept any components — buttons, links, badges. | Slot name | Description | | :-------------- | :--------------------------------------------------- | | `label` | Label content (replaces `label`) | | `description` | Description content (replaces `description`) | | `prepend` | Element before the input | | `append` | Element after the input | | `prepend-inner` | Element at the start of the field, inside the border | | `append-inner` | Element at the end of the field, inside the border | | `clear` | Your own clear icon (with `clearable`) | | `loader` | Your own loading indicator (with `loading`) | | `counter` | Counter content | | `details` | The whole bottom block — messages and counter | | `messages` | Content of the messages block | **Example — `CustomSlots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The label is always visible and names the field, the placeholder shows a sample value. | A placeholder used instead of a label disappears on input — the user forgets what they are filling in. | | The error message says exactly what to fix. | “Invalid value” does not help: it is unclear what is wrong and what to do. | | The placeholder is a short sample value in the right format. | Instructions in the placeholder duplicate the label and vanish on input. | ## Scenarios ### Searching through a list A search field is made of the `prepend-inner-icon="search"` icon and `clearable` — the user resets the query in one click and sees the full list again. A label is not needed here: the role of the field is obvious from the icon and the placeholder. **Example — `SearchFilter.vue`:** ```vue ``` ### Password with a preview The `append-inner` slot accepts interactive elements — a button that toggles `type` between `password` and `text`, for example. The hint in `hint` states the password requirements before the user makes a mistake. **Example — `PasswordToggle.vue`:** ```vue ``` ### An error from the server The server response goes into `error-messages` as is — validation through `rules` is not needed for that. Reset the error when the value changes, so that the field does not complain about an input that is already fixed. **Example — `ServerError.vue`:** ```vue ``` ### Events Every icon zone emits its own click event: `click:prepend`, `click:append`, `click:prepend-inner`, `click:append-inner` and `click:clear` (the last one fires after the value has already been reset). Here the icon on the left cycles through the options, the lock inside the field toggles, and the submit button clears the message. When you need a complex element instead of an icon — a button, a badge — use the slots of the same name, like in the password example above. **Example — `Events.vue`:** ```vue ``` ## API ### CdsTextInput **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state of the field | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `appendInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner append slot, after the content of the field | | `autocomplete` | `string \| undefined` | — | no | Helps to influence browser suggestions. The `suppress` value changes the name attribute of the fields, and `off` relies on the browser to stop suggesting values on its own. Any other value is passed to the built-in autocomplete of the corresponding element. | | `autofocus` | `boolean \| undefined` | — | no | Enables autofocus | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `centerAffix` | `boolean \| undefined` | — | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `clearable` | `boolean \| undefined` | — | no | Shows the clear button | | `clearIcon` | `IconValue \| undefined` | `'remove'` | no | Icon of the clear button | | `color` | `string \| undefined` | — | no | Component color | | `counter` | `string \| number \| boolean \| undefined` | — | no | Character counter. Accepts a boolean, a number or a string | | `counterValue` | `number \| ((value: any) => number) \| undefined` | — | no | Custom counter value. Either a number or a function computing it from the current value | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `dirty` | `boolean \| undefined` | — | no | Marks that the value of the field was changed by the user | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | Error state | | `errorMessages` | `string \| readonly string[] \| null \| undefined` | `[]` | no | Puts the component into the error state and passes custom error messages. They are merged with any checks defined in the `rules` prop. This field does not trigger validation. | | `focused` | `boolean \| undefined` | — | no | Controls the focus state of the component. When `true`, the component is considered focused and may apply the corresponding styles or behavior. | | `hideDetails` | `boolean \| "auto" \| undefined` | — | no | Hides the details block (messages and hints). With the 'auto' value the block is hidden when there are no messages | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `hint` | `string \| undefined` | — | no | Hint text shown under the input | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `label` | `string \| undefined` | — | no | Label text of the component | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelModifiers` | `Record \| undefined` | — | no | v-model modifiers passed by Vue to process the field value | | `modelValue` | `any` | — | no | Value of the component in v-model. If the component supports the multiple prop, an empty array is used by default. | | `name` | `string \| undefined` | — | no | Name of the input | | `persistentClearable` | `boolean \| undefined` | — | no | Always show the clear button, not only on hover or focus | | `persistentCounter` | `boolean \| undefined` | — | no | Always show the counter, not only while the field is in use | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `persistentPlaceholder` | `boolean \| undefined` | — | no | Always show the placeholder instead of hiding it while the field is in use | | `placeholder` | `string \| undefined` | — | no | Placeholder text shown in an empty field | | `prefix` | `string \| undefined` | — | no | Text prefix shown before the field value | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `prependInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner prepend slot, before the content of the field | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `reverse` | `boolean \| undefined` | — | no | Reverses the order of the elements inside the field | | `role` | `string \| undefined` | — | no | ARIA role for the native input element | | `rules` | `readonly ValidationRule[] \| undefined` | `[]` | no | Accepts an array of items of different types: functions, booleans and strings. Functions take the input value as an argument and must return either true / false, or a string with an error message. The input goes into the error state if a function returns false (or any value in the array is false) or is a string. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `suffix` | `string \| undefined` | — | no | Text suffix shown after the field value | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `type` | `string \| undefined` | `'text'` | no | Type of the native input | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click:append` | `[e: MouseEvent]` | Click on the outer append icon (`append-icon` prop) | | `click:appendInner` | `[e: MouseEvent]` | Click on the inner append icon (`append-inner-icon` prop) | | `click:clear` | `[e: MouseEvent]` | Click on the clear icon (`clearable`); fires after the value has been reset | | `click:control` | `[e: MouseEvent]` | Fires on a click in the main area of the control | | `click:prepend` | `[e: MouseEvent]` | Click on the outer prepend icon (`prepend-icon` prop) | | `click:prependInner` | `[e: MouseEvent]` | Click on the inner prepend icon (`prepend-inner-icon` prop) | | `mousedown:control` | `[e: MouseEvent]` | Fires on a mouse button press in the main area of the control | | `update:focused` | `[focused: boolean]` | Fires when the element gains or loses focus | | `update:modelValue` | `[value: string]` | Fires when the model of the component changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `append-inner` | `CdsInputDefaultSlot` | Slot added at the end of the input | | `clear` | `CdsInputDefaultSlot & { props: Record; }` | Slot for a custom clear icon (shown when the clearable prop is true). | | `counter` | `CdsCounterSlot` | Slot for a custom counter | | `default` | `{ id: Readonly>; }` | Default slot | | `description` | `{ description: string \| undefined; props: Record; }` | Default slot of the CdsDescription component | | `details` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | | `loader` | `LoaderSlotProps` | Slot for a custom loader (shown when the loading prop is true). | | `message` | `CdsMessageSlot` | Slot for customizing the content of a message | | `messages` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `prepend` | `CdsInputSlot` | Adds an element before the input | | `prepend-inner` | `CdsInputDefaultSlot` | Slot added at the start of the input | **Exposed** | Name | Type | Description | | --- | --- | --- | | `controlRef` | `HTMLElement \| undefined` | Ref to the control of the input | | `fieldIconColor` | `string \| undefined` | Icon color | | `isDirty` | `boolean` | Whether the input is dirty | | `isDisabled` | `boolean` | Whether the input is disabled | | `isPure` | `boolean` | Whether the input is pure | | `isReadonly` | `boolean` | Whether the input is read-only | | `isValid` | `boolean \| null` | Whether the input is valid | | `isValidating` | `boolean` | Whether the input is being validated | | `reset` | `() => Promise` | Resets the input to its initial state | | `resetValidation` | `() => Promise` | Resets the validation of the input | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsTimePicker _Category: Controls · since 4.0.0_ _Tests: API 21/21 · 39 unit · 2 e2e · 7 known bugs · lines 97.2% (v4.0.0-alpha.13) · a11y: 17 axe recommendations (v4.0.0-alpha.11)_ Time selection: hours, minutes and — if you want — seconds. The value can be typed on the keyboard or stepped through with the arrows, and `v-model` receives a string in the given format (`HH:mm` by default), which is convenient to store and to send to the server. **See also:** To pick a date use CdsDatePicker, and if you need a field with a date and a time at once — the ready CdsDateInput with the `with-time` prop: it puts this clock under the calendar and brings everything together into one string itself. ## Anatomy Every block of the time is a field with arrows: the value can be typed on the keyboard or stepped through one unit at a time. The seconds, the AM/PM switch and the "Now" button are added by the `with-seconds`, `format12h` and `now-btn` props. ## Variations ### Value and format The time arrives in `v-model` as a string in the `mask` format — `HH:mm` by default. As the second argument of the `update:model-value` event the component gives out the parsed date as an object: the year, the month, the day, the hours, the minutes, the seconds. While no value is chosen, the fields are empty and show the `00` hint. **Example — `Default.vue`:** ```vue ``` The mask may include the date as well: then the component changes the time only and carries the date over from the current value — that is how one string is shared between a calendar and a clock. The `with-time` prop of CdsDateInput is built on the same idea. If the model is empty, the date for the new string is taken from `default-date` (the `YYYY/MM/DD` format), otherwise it is today. **Example — `Mask.vue`:** ```vue ``` ### Seconds `with-seconds` adds a third block. The mask is extended automatically: the component appends `:ss` to `HH:mm` by itself. **Example — `WithSeconds.vue`:** ```vue ``` ### The 12-hour format `format12h` shows the hours from 1 to 12 and the AM/PM switch. This does not affect the value in the model — the format is set by the mask, so for a string with AM/PM use `hh:mm A`. **Example — `Format12h.vue`:** ```vue ``` ### The "Now" button `now-btn` adds a button under the clock that sets the current time — the user does not have to step through the values with the arrows. **Example — `NowBtn.vue`:** ```vue ``` ### Available time `allowed-hours`, `allowed-minutes` and `allowed-seconds` accept arrays of the allowed values: the arrows step through those only, and a value outside the list is pulled by the component to the nearest allowed one. **Example — `LimitedTime.vue`:** ```vue ``` When the restriction depends on the already chosen time, pass the `allowed-time` function instead of the arrays. It is called separately for the hours, the minutes and the seconds: the parts that are not being checked arrive as `null`. **Example — `AllowedTime.vue`:** ```vue ``` ### Localization `locale` accepts a locale name (`ru` | `en`) or your own object of translations; without the prop the locale of the application is taken. The caption of the "Now" button and the default format depend on the locale: in `en` the time is 12-hour, so the hours are shown from 1 to 12 even without `format12h` — only the AM/PM switch is added by it. **Example — `Localization.vue`:** ```vue ``` ### States `disabled` turns the clock off and dims it, `readonly` keeps the usual look but forbids changing the value — both with the arrows and from the keyboard. **Example — `DisabledAndReadonly.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The minute step is set through allowed-minutes — the needed value is reached in a couple of clicks. | Free minutes give 60 options where meetings are scheduled by quarters of an hour. | | Show the seconds only where they matter: in logs, timings, trading rules. | An extra field in a meeting booking makes the user fill in what nobody needs. | | In a Russian interface the 24-hour format is more familiar — it is the default one. | AM/PM asks the user to convert the time in their head and adds an extra switch. | ## Scenarios ### Booking a meeting Meetings are scheduled within working hours and by quarters of an hour — `allowed-hours` and `allowed-minutes` leave only such values. The user cannot pick a time that would have to be rejected later. **Example — `MeetingTime.vue`:** ```vue ``` ### A field with a time Most often the clock lives not on the page but in a menu next to a text field. There is no ready field for the time alone in the system — assemble the control out of CdsTextInput, a CdsMenu with `activator="parent"` and the clock: all the props and slots of the field and the menu stay available to you. For the manual input add a mask: we recommend the lightweight (2.5 KB) [Maska](https://github.com/beholdr/maska) library. If you need the date together with the time, the field already exists — CdsDateInput with `with-time`. **Example — `TimeField.vue`:** ```vue ``` ### A "from — to" interval Two clocks can share one rule: the `allowed-time` of the end looks at the start and does not let an earlier time be picked. When the start is moved past the end, the demo moves the end too — the rule and the code work in pairs. **Example — `WorkingHours.vue`:** ```vue ``` ### Date and time The calendar does not pick the time and the clock does not pick the date — put them next to each other with a shared model and the same `DD.MM.YYYY HH:mm` mask: every component changes its own part of the string. In a field this pair is already assembled — turn on `with-time` on CdsDateInput. **Example — `DateAndTime.vue`:** ```vue ``` ## API ### CdsTimePicker **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `allowedHours` | `number[] \| undefined` | — | no | Configures which hours are available for selection. | | `allowedMinutes` | `number[] \| undefined` | — | no | Configures which minutes are available for selection. | | `allowedSeconds` | `number[] \| undefined` | — | no | Configures which seconds are available for selection. | | `allowedTime` | `((hr: number \| null, min: number \| null, sec: number \| null) => boolean) \| undefined` | — | no | Configures which time is available for selection. | | `defaultDate` | `string \| undefined` | — | no | Date used by default when the model is empty (in the YYYY/MM/DD format). | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `format12h` | `boolean \| undefined` | — | no | Shows the time in the 12-hour AM/PM format. | | `locale` | `string \| TDateLocale \| undefined` | — | no | Locale for the dates. A locale name ('ru' \| 'en') or a `TDateLocale` object. The current locale from `useLocale` is taken by default, otherwise `ru`. | | `mask` | `string \| undefined` | `'HH:mm'` | no | Date/time format | | `modelValue` | `string \| TDatetimeValueRange \| (string \| TDatetimeValueRange)[] \| null \| undefined` | `null` | no | Value of the model | | `nowBtn` | `boolean \| undefined` | — | no | Shows the "Now" button. | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `theme` | `string \| undefined` | — | no | Component theme | | `withSeconds` | `boolean \| undefined` | — | no | Adds seconds to the time selection. | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: string \| undefined, date: IRawDate]` | The value changed (v-model). Passes the formatted value and the date object. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `setAm` | `() => void` | Switches the 12-hour format to the first half of the day (AM). | | `setHour` | `(hour: number) => void` | Sets the hours. | | `setMinute` | `(minute: number) => void` | Sets the minutes. | | `setNow` | `() => void` | Sets the current system time. | | `setPm` | `() => void` | Switches the 12-hour format to the second half of the day (PM). | | `setSecond` | `(second: number) => void` | Sets the seconds. | --- # CdsToast _Category: Feedback · since 4.0.0 · status: new_ _Tests: API 69/69 · 68 unit · 6 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 9 axe recommendations (v4.0.0-alpha.11)_ A toast is a pop-up notification about the result of an action: the changes are saved, the file is uploaded, the request failed. It appears above the page, does not interrupt the work and closes itself once `timeout` runs out. **See also:** For a stream of events where notifications arrive one after another use CdsToastQueue. A message that has to stay on the page belongs in CdsNotification, and a question that requires a decision from the user — in the CdsModal dialog. ## Anatomy A toast consists of a container and three zones: prepend with the status icon, an avatar or a loading indicator; the content with a heading and text; and the actions zone. The `timer` prop adds a bar of the remaining time. ## Variations ### Controlling the visibility Show the toast through `v-model` or the `activator` slot — in the second case the component manages its own state. The toast closes automatically after `timeout` (5000 ms by default); hovering the cursor or focusing inside the toast pauses the countdown, and on touch screens the toast can be swiped away. **Example — `Visibility.vue`:** ```vue ``` ### Status The `status` prop picks the color and the icon by the meaning of the message: `info`, `success`, `warning`, `danger`, `progress`. The icon can be replaced by the `icon` prop or hidden with the value `false`. **Example — `Statuses.vue`:** ```vue ``` ### Timer The `timeout` prop sets the delay before auto-closing in milliseconds, and `-1` turns it off. The bar of the remaining time is enabled by the `timer` prop (`true`/`top` — on top, `bottom` — at the bottom), `reverse-timer` flips its direction and `timer-color` changes its color. **Example — `Timer.vue`:** ```vue ``` ### Position The `location` prop puts the toast into one of the six positions: the side (`top`, `bottom`) plus the alignment (`left`, `center`, `right`). The toast is rendered above the page content by CdsOverlay. **Example — `Location.vue`:** ```vue ``` ### Content and actions The heading and the text come from the `title` and `text` props, the avatar before the content from `prepend-avatar`, and `loading` replaces the icon with a loading indicator. The `actions` slot adds buttons: inside it they get `variant="solid"`, `color="inverse"` and `size="sm"` by default. The vertical layout (`vertical`) moves the actions below the content. **Example — `ContentAndActions.vue`:** ```vue ``` ### Slots Slots replace the content coming from props when you need your own markup. | Slot | Description | | ----------- | -------------------------------------------------------------------------------- | | `activator` | The element that opens the toast | | `header` | A header across the full width of the toast | | `prepend` | Content before the text. Replaces the icon, the avatar and the loading indicator | | `title` | Heading. Replaces the text from `title` | | `text` | Text. Replaces the text from `text` | | `default` | Main content after the text | | `actions` | Actions of the toast | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The toast text is a short summary of the action, readable in a second. | Details and instructions cannot be read before the toast closes itself. | | A toast reports an action that already happened and offers to undo it. | A toast does not wait for an answer — ask questions that need a decision in a modal. | | An error stays on the screen (timeout: -1) until the user reacts. | An error with a timer disappears before the user can deal with it. | ## Scenarios ### Undoing an action The toast confirms the deletion and gives time to change one's mind: the "Отменить" button in the `actions` slot brings the document back, and the `timer` bar shows how much time is left to decide. **Example — `UndoAction.vue`:** ```vue ``` ### A background task A single toast accompanies the task from the start to the result. While the processing runs, `loading` shows the indicator and `timeout: -1` keeps the notification from disappearing; once it is done the same toast switches to `status="success"` and closes itself. **Example — `BackgroundTask.vue`:** ```vue ``` ### An error with a retry Do not hide an error automatically: `timeout: -1` keeps the toast until the user reacts, and the "Повторить" button in `actions` runs the request again. **Example — `ErrorRetry.vue`:** ```vue ``` ## API ### CdsToast **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `absolute` | `boolean \| undefined` | — | no | Positions the element absolutely instead of fixed. This is useful for overlays that must stay inside a certain area, for example inside a container with `position: relative`. | | `activator` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| undefined` | — | no | The element that activates the component | | `activatorProps` | `Record \| undefined` | `{}` | no | Props for the activator element | | `attach` | `string \| boolean \| Element \| undefined` | — | no | Sets the DOM element the overlay content is moved to. It accepts a direct element reference, a querySelector string, or true to disable moving. By default the body element is used. Changing this prop is usually not recommended except for edge cases: the default positioning algorithm handles most scenarios better than it can without moving, and unexpected behavior may appear if the menu ends up being a child of its activator. | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `false` | no | Closes the overlay content when the browser Back button is pressed or $router.back() is called, cancelling the original navigation. `persistent` overlays cancel the navigation and animate as if they were clicked outside instead of closing. | | `closeOnContentClick` | `boolean \| undefined` | — | no | Hide the component on a click on the content | | `collapsed` | `{ width: number; height: number; } \| undefined` | — | no | Collapsed state of a toast in the queue: the size the toast collapses to. Managed by the CdsToastQueue component. | | `contained` | `boolean \| undefined` | — | no | Limits the size of the component and of its grid to the offset parent. Implies the `absolute` and `attach` props. (Note: the parent element must have `position: relative`.) | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `contentClass` | `any` | — | no | Applies a custom class to the content element. This is handy because the content is moved to the beginning of the cds-app component (unless `attach` is set) and cannot be selected with classes passed to the component directly. | | `contentProps` | `any` | — | no | Applies custom props to the moved content | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | — | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `height` | `string \| number \| undefined` | — | no | Component height | | `icon` | `false \| IconValue \| undefined` | `null` | no | Icon before the content. Taken from `status` by default; `false` hides the icon. | | `loading` | `boolean \| undefined` | — | no | Shows a loading indicator instead of the icon. | | `location` | `Anchor \| null \| undefined` | `'top center'` | no | Position of the element relative to its container, for example "top left", "center", "bottom right". | | `locationStrategy` | `"static" \| "connected" \| LocationStrategyFunction \| undefined` | `'static'` | no | Sets the way the overlay content is positioned. By default static is used, which centers the content in its container. Use connected to attach the content to the activator element. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `boolean \| undefined` | — | no | The v-model value of the component. If the component supports the **multiple** prop, an empty array is used by default. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the scrim element. Applies only when `scrim=true`. | | `openDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component opens. Works only together with open-on-hover. | | `openOnClick` | `boolean \| undefined` | — | no | Show the component on a click on the activator | | `openOnFocus` | `boolean \| undefined` | — | no | Show the component when the activator gets focus | | `openOnHover` | `boolean \| undefined` | — | no | Show the component on hover over the activator | | `origin` | `Anchor \| "auto" \| "overlap" \| undefined` | `'auto'` | no | Sets the anchor point of the overlay content that is aligned with the `location` anchor of the target. With "auto" the opposite side of the `location` point is used. With "overlap" the same anchor point is used, so the overlay overlaps the target. It also sets the CSS `transform-origin` property for the enter/leave transitions. | | `position` | `"absolute" \| "static" \| "fixed" \| "relative" \| "sticky" \| undefined` | — | no | CSS positioning of the component — the value of the `position` property | | `prependAvatar` | `string \| undefined` | — | no | Source of the avatar image before the content. Takes priority over the icon. | | `queueGap` | `number \| undefined` | — | no | Gap between the toasts in the queue, in pixels. Managed by the CdsToastQueue component. | | `queueIndex` | `number \| undefined` | — | no | Index of the toast in the queue. Managed by the CdsToastQueue component. | | `reverseTimer` | `boolean \| undefined` | — | no | Reverses the timer bar: it fills up instead of draining. | | `status` | `"progress" \| "danger" \| "success" \| "warning" \| "info" \| undefined` | `'info'` | no | Semantic status — drives the color and the default icon. | | `target` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| "cursor" \| [x: number, y: number] \| undefined` | — | no | When `locationStrategy` is set to "connected", specify the element or the array of x, y coordinates the overlay is positioned against. By default the activator element is used. | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `timeout` | `string \| number \| undefined` | `5000` | no | Delay in milliseconds before the toast hides automatically. The value `-1` turns auto-closing off. | | `timer` | `boolean \| "top" \| "bottom" \| undefined` | `false` | no | Shows the timer bar until auto-closing: `true`/`top` — on top, `bottom` — at the bottom. | | `timerColor` | `string \| undefined` | — | no | Color of the timer bar. | | `title` | `string \| undefined` | — | no | Heading of the toast. | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'cds-toast-transition'` | no | Transition animation | | `vertical` | `boolean \| undefined` | — | no | Vertical layout: the actions move below the content. | | `width` | `string \| number \| undefined` | — | no | Component width | | `zIndex` | `string \| number \| undefined` | `2000` | no | The z-index value of the component. | **Events** | Name | Type | Description | | --- | --- | --- | | `afterEnter` | `[]` | The enter animation finished. | | `afterLeave` | `[]` | The leave animation finished. | | `update:modelValue` | `[value: boolean]` | The visibility of the toast changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `{ isActive: Ref; }` | Slot for the actions of the toast. | | `activator` | `{ isActive: boolean; props: Record; }` | Slot for the element that acts as the activator of the toast. | | `default` | `any` | Main content of the toast. | | `header` | `any` | Slot for the full-width header of the toast. | | `prepend` | `any` | Slot before the content (icon, avatar or loading indicator). | | `text` | `any` | Text slot. | | `title` | `any` | Heading slot. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `activatorEl` | `HTMLElement \| undefined` | The DOM element of the activator. | | `activatorRef` | `TemplateRef` | Template ref for assigning the activator manually. | | `animateClick` | `() => void` | Runs the bounce animation of the content — the same as on a click outside a `persistent` overlay. | | `contentEl` | `HTMLElement \| undefined` | The DOM element of the overlay content. | | `globalTop` | `boolean` | Whether the overlay is the top one in the global stack of open overlays. | | `rootEl` | `HTMLElement \| undefined` | The root DOM element of the overlay. | | `scrimEl` | `HTMLElement \| undefined` | The DOM element of the scrim that dims the page. | | `targetEl` | `HTMLElement \| undefined` | The DOM element of the positioning target. | | `targetRef` | `TemplateRef` | Template ref for assigning the positioning target manually. | | `updateLocation` | `((e: Event) => void) \| undefined` | Recalculates the position of the content relative to the target. | --- # CdsToastQueue _Category: Feedback · since 4.0.0 · status: new_ _Tests: API 58/58 · 34 unit · 2 e2e · 2 known bugs · lines 99.2% (v4.0.0-alpha.13) · a11y: 6 axe recommendations (v4.0.0-alpha.11)_ A queue of pop-up notifications built on CdsToast. Put the messages into the `v-model` array — the queue will show them one by one or as a stack, respect the limit of simultaneously visible toasts and close the ones that are done. **See also:** For a single notification — a save confirmation, for example — CdsToast is enough. ## Variations ### The message queue A message is a string or an object with toast props. Add messages to the `v-model` array: the queue shows them one by one, and the rest wait for their place. The `closable` prop adds a close button with the `close-text` label to every toast. Props shared by the toasts — `location`, `timer`, `status` and others — are set right on the queue: they apply to every message. While the browser tab is hidden, auto-closing is paused. **Example — `Messages.vue`:** ```vue ``` ### Limit and overflow The `total-visible` prop caps the number of simultaneously visible toasts: a new one takes the place at the edge of the screen and pushes the previous ones aside. The `display-strategy` prop decides what to do with the extra ones: `hold` (the default) keeps them in the queue until a place frees up, `overflow` closes the oldest ones. **Example — `Overflow.vue`:** ```vue ``` ### The stack The `collapsed` prop folds all the toasts except the last one into a compact stack. Hover the cursor — the stack unfolds, and the timers pause while the cursor is inside. **Example — `Collapsed.vue`:** ```vue ``` ### Slots The slots customize every toast of the queue; each of them receives the `item` object of the current message. | Slot | Description | | --------- | ----------------------------------------------------------------------------------------- | | `header` | Header of the toast | | `text` | Text of the toast. Replaces the `text` of the message | | `actions` | Actions of the toast. `props` carries an `onClick` handler that closes the toast | | `item` | Full replacement of the toast. The message props are passed through `CdsDefaultsProvider` | ## Scenarios ### Background operations Pass a `promise` in the message — the toast gets a loading indicator and does not close until the operation is done. The `success` and `error` callbacks return the toast props for the result: the status, the text and the auto-close delay. **Example — `AsyncOperations.vue`:** ```vue ``` ### Notification center The events of the application pile up into a single queue in the corner of the screen: `location="bottom right"` moves the toasts out of the working area, `collapsed` hides the older ones in a stack, and `closable` lets the user close every notification. **Example — `EventFeed.vue`:** ```vue ``` ### Controlling the queue The `onDismiss` callback of a message receives the reason it was closed — `auto`, `dismissed`, `overflow` or `cleared` — and the exposed `clear()` method closes all the toasts and empties the queue. **Example — `QueueControl.vue`:** ```vue ``` ## API ### CdsToastQueue **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `absolute` | `boolean \| undefined` | — | no | Positions the element absolutely instead of fixed. This is useful for overlays that must stay inside a certain area, for example inside a container with `position: relative`. | | `activator` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| undefined` | — | no | The element that activates the component | | `activatorProps` | `Record \| undefined` | `{}` | no | Props for the activator element | | `attach` | `string \| boolean \| Element \| undefined` | — | no | Sets the DOM element the overlay content is moved to. It accepts a direct element reference, a querySelector string, or true to disable moving. By default the body element is used. Changing this prop is usually not recommended except for edge cases: the default positioning algorithm handles most scenarios better than it can without moving, and unexpected behavior may appear if the menu ends up being a child of its activator. | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `closable` | `string \| boolean \| undefined` | — | no | Adds a close button to every toast. A string value sets the color of the button. | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `false` | no | Closes the overlay content when the browser Back button is pressed or $router.back() is called, cancelling the original navigation. `persistent` overlays cancel the navigation and animate as if they were clicked outside instead of closing. | | `closeOnContentClick` | `boolean \| undefined` | — | no | Hide the component on a click on the content | | `closeText` | `string \| undefined` | `'$cds.dismiss'` | no | Text of the close button. | | `collapsed` | `boolean \| undefined` | — | no | Folds the inactive toasts into a stack under the last visible one. | | `contained` | `boolean \| undefined` | — | no | Limits the size of the component and of its grid to the offset parent. Implies the `absolute` and `attach` props. (Note: the parent element must have `position: relative`.) | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `contentClass` | `any` | — | no | Applies a custom class to the content element. This is handy because the content is moved to the beginning of the cds-app component (unless `attach` is set) and cannot be selected with classes passed to the component directly. | | `contentProps` | `any` | — | no | Applies custom props to the moved content | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `displayStrategy` | `"overflow" \| "hold" \| undefined` | `'hold'` | no | Strategy when `totalVisible` is exceeded: `hold` — wait until a toast closes, `overflow` — push the oldest ones out. | | `eager` | `boolean \| undefined` | — | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `gap` | `string \| number \| undefined` | `8` | no | Gap between the toasts, in pixels. | | `height` | `string \| number \| undefined` | — | no | Component height | | `icon` | `false \| IconValue \| undefined` | `null` | no | Icon before the content. Taken from `status` by default; `false` hides the icon. | | `loading` | `boolean \| undefined` | — | no | Shows a loading indicator instead of the icon. | | `location` | `Anchor \| null \| undefined` | `'top center'` | no | Position of the element relative to its container, for example "top left", "center", "bottom right". | | `locationStrategy` | `"static" \| "connected" \| LocationStrategyFunction \| undefined` | `'static'` | no | Sets the way the overlay content is positioned. By default static is used, which centers the content in its container. Use connected to attach the content to the activator element. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `readonly ToastMessage[] \| undefined` | `[]` | no | The queue of messages (v-model). A string or an object with toast props. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the scrim element. Applies only when `scrim=true`. | | `openDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component opens. Works only together with open-on-hover. | | `openOnClick` | `boolean \| undefined` | — | no | Show the component on a click on the activator | | `openOnFocus` | `boolean \| undefined` | — | no | Show the component when the activator gets focus | | `openOnHover` | `boolean \| undefined` | — | no | Show the component on hover over the activator | | `origin` | `Anchor \| "auto" \| "overlap" \| undefined` | `'auto'` | no | Sets the anchor point of the overlay content that is aligned with the `location` anchor of the target. With "auto" the opposite side of the `location` point is used. With "overlap" the same anchor point is used, so the overlay overlaps the target. It also sets the CSS `transform-origin` property for the enter/leave transitions. | | `position` | `"absolute" \| "static" \| "fixed" \| "relative" \| "sticky" \| undefined` | — | no | CSS positioning of the component — the value of the `position` property | | `prependAvatar` | `string \| undefined` | — | no | Source of the avatar image before the content. Takes priority over the icon. | | `reverseTimer` | `boolean \| undefined` | — | no | Reverses the timer bar: it fills up instead of draining. | | `status` | `"progress" \| "danger" \| "success" \| "warning" \| "info" \| undefined` | `'info'` | no | Semantic status — drives the color and the default icon. | | `target` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| "cursor" \| [x: number, y: number] \| undefined` | — | no | When `locationStrategy` is set to "connected", specify the element or the array of x, y coordinates the overlay is positioned against. By default the activator element is used. | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `timeout` | `string \| number \| undefined` | `5000` | no | Delay in milliseconds before the toast hides automatically. The value `-1` turns auto-closing off. | | `timer` | `boolean \| "top" \| "bottom" \| undefined` | `false` | no | Shows the timer bar until auto-closing: `true`/`top` — on top, `bottom` — at the bottom. | | `timerColor` | `string \| undefined` | — | no | Color of the timer bar. | | `title` | `string \| undefined` | — | no | Heading of the toast. | | `totalVisible` | `string \| number \| undefined` | `1` | no | Maximum number of simultaneously visible toasts. | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'cds-toast-transition'` | no | Transition animation | | `vertical` | `boolean \| undefined` | — | no | Vertical layout: the actions move below the content. | | `width` | `string \| number \| undefined` | — | no | Component width | | `zIndex` | `string \| number \| undefined` | `2000` | no | The z-index value of the component. | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: ToastMessage[]]` | The queue of messages changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `{ item: ToastMessage; props: { onClick: () => void; }; }` | Slot for the actions of the toast. | | `header` | `{ item: ToastMessage; }` | Slot for the header of the toast. | | `item` | `{ item: ToastMessage; }` | Slot that fully replaces the toast. The toast props are passed through CdsDefaultsProvider. | | `text` | `{ item: ToastMessage; }` | Slot for the text of the toast. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `clear` | `() => void` | Empties the queue and closes all the visible toasts. | --- # CdsToggle _Category: Controls · since 4.0.0_ _Tests: API 69/69 · 66 unit · lines 100% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ A toggle is an on/off switch for a setting that applies immediately, without a "Save" button: notifications, auto-renewal, profile visibility. It is built on CdsInput: it can do a label and a description, messages and errors, loading and the indeterminate state. **See also:** A toggle changes the setting instantly. If the choice is applied together with the rest of the form by a button, take CdsCheckbox, and to pick one option out of a set — CdsRadioGroup. ## Anatomy On the left is the track with the thumb: their position and color show the state. On the right are the label and the description of the setting, at the bottom is the messages block. A click on the label toggles the switch exactly like a click on the track. ## Variations ### Label and description `label` names the setting, `description` explains what turning it on leads to. Phrase the label so that it is clear what happens in the on position. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Sizes Five sizes on the `size` scale — from `xs` to `xl`, `md` by default. **Example — `Sizes.vue`:** ```vue ``` ### States `disabled` blocks the toggle and lowers the contrast, `readonly` forbids changing the value, `error` paints the track with the error color. `indeterminate` is the undefined state: the thumb stops in the middle while the value is unknown — when only some of the nested options are on, for example. The first toggle removes it. **Example — `States.vue`:** ```vue ``` ### Loading and icons `loading` shows an indicator inside the thumb — handy while the setting is being saved on the server; a string value sets the color of the loader. `true-icon` and `false-icon` add an icon to the thumb for each position. **Example — `LoadingAndIcons.vue`:** ```vue ``` ### Colors `color` paints the track of a switched-on toggle, `base-color` — of a switched-off one, `thumb-color` — the thumb. The values are the names of the palette colors. **Example — `Colors.vue`:** ```vue ``` ### Your own values By default the model is `true`/`false`. `true-value` and `false-value` bind the toggle to your own values — to an API field with a string status, for example. **Example — `CustomValues.vue`:** ```vue ``` ### Messages `messages` shows a hint under the toggle, `error-messages` — a ready error message together with the error state. `hide-details` removes the bottom block entirely. **Example — `Messages.vue`:** ```vue ``` ### Slots When the text props are not enough, parts of the component are replaced by slots. | Slot name | Description | | :--------------------------- | :----------------------------------------------------- | | `label` | Label content (replaces `label`) | | `description` | Description content (replaces `description`) | | `thumb` | Thumb content; receives the current icon and the model | | `track-true` / `track-false` | Track content in the on / off position | | `loader` | Custom loading indicator | | `prepend` / `append` | Elements before and after the control | | `messages` / `details` | Content of the messages block / the whole bottom block | In the demo the `thumb` slot changes the icon of the thumb depending on the value, and `track-true` and `track-false` show icons on the track. **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A toggle is for a setting that applies right after it is switched. | Consents and choices that go to the server together with the form are a checkbox, not a toggle. | | Phrase the label positively: the on position turns the capability on. | A negation in the label forces the user to decode a double “no” when the toggle is off. | | The label names the setting — the state is visible from the position and the color of the thumb. | A label repeating the state changes on every click: it is unclear what exactly is turned on. | ## Scenarios ### Notification settings The main toggle controls the whole group: while notifications are off, the channels are blocked through `disabled`. The choice of channels is kept though — after switching back on the group returns to its previous values. **Example — `NotificationSettings.vue`:** ```vue ``` ### Saving on the server The setting is saved right after the switch: while the request is in flight the toggle shows `loading` and does not accept clicks because of `readonly`. If the server rejected the change, the value comes back and the reason is shown in `error-messages`. Try switching the toggle off. **Example — `ServerSave.vue`:** ```vue ``` ### Paid options Every toggle adds an option to the plan, and the total is recalculated at once — the user sees the consequences of the choice before paying. **Example — `PaidOptions.vue`:** ```vue ``` ## API ### CdsToggle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `centerAffix` | `boolean \| undefined` | `true` | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `color` | `string \| undefined` | — | no | Component color | | `defaultsTarget` | `string \| undefined` | — | no | Name of the child component the group prop values are passed to as defaults | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `error` | `boolean \| undefined` | — | no | Puts the component into the visual error state | | `errorMessages` | `string \| readonly string[] \| null \| undefined` | `[]` | no | Puts the component into the error state and passes custom error messages. They are merged with any checks defined in the `rules` prop. This field does not trigger validation. | | `falseIcon` | `IconValue \| undefined` | — | no | Icon of the unselected state | | `falseValue` | `any` | — | no | Value for the false state. | | `focused` | `boolean \| undefined` | — | no | Controls the focus state of the component. When `true`, the component is considered focused and may apply the corresponding styles or behavior. | | `hideDetails` | `boolean \| "auto" \| undefined` | — | no | Hides the details block (messages and hints). With the 'auto' value the block is hidden when there are no messages | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `hint` | `string \| undefined` | — | no | Hint text shown under the input | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `indeterminate` | `boolean \| undefined` | — | no | Indeterminate state of the toggle. | | `inline` | `boolean \| undefined` | — | no | Renders the control as an inline element — the container does not stretch to the full width | | `label` | `string \| undefined` | — | no | Label text of the component | | `loading` | `string \| boolean \| undefined` | `false` | no | Loading indicator. Accepts a boolean or a string with the color of the loader. | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `any` | — | no | Value of the component (v-model). In a group it is the value of the selected control, with `multiple` — an array of the selected values | | `multiple` | `boolean \| null \| undefined` | `null` | no | Allows selecting several values — the model becomes an array. Turns on automatically when an array is passed to `modelValue` | | `name` | `string \| undefined` | — | no | The `name` attribute of the native input element. In a group one name joins all the nested controls | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `rules` | `readonly ValidationRule[] \| undefined` | `[]` | no | Accepts an array of items of different types: functions, booleans and strings. Functions take the input value as an argument and must return either true / false, or a string with an error message. The input goes into the error state if a function returns false (or any value in the array is false) or is a string. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `thumbColor` | `string \| undefined` | — | no | Color of the thumb. | | `trueIcon` | `IconValue \| undefined` | — | no | Icon of the selected state | | `trueValue` | `any` | — | no | Value for the true state. | | `type` | `string \| undefined` | — | no | Type of the native input element — `radio` or `checkbox`, for example | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `value` | `any` | — | no | Value used when the component is selected inside a group. When it is not set, a unique identifier is used. | | `valueComparator` | `ValueComparator \| undefined` | `true` | no | Function comparing the model value with the `value` of the control. Deep comparison by default | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `update:focused` | `[focused: boolean]` | Fires when the focus state of the component changes. | | `update:indeterminate` | `[value: boolean]` | Fires when the indeterminate state changes. | | `update:modelValue` | `[value: any]` | Fires when the model of the component changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `default` | `{ backgroundColorClasses: Ref; backgroundColorStyles: Ref; }` | Default slot | | `description` | `{ description: string \| undefined; props: Record; }` | Default slot of the CdsDescription component | | `details` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `input` | `SelectionControlSlot` | Slot for the default input element. | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | | `loader` | `LoaderSlotProps` | Slot for a custom loading indicator. | | `message` | `CdsMessageSlot` | Slot for customizing the content of a message | | `messages` | `CdsInputSlot` | Slot for custom content that lets you customize how the messages are displayed | | `prepend` | `CdsInputSlot` | Adds an element before the input | | `thumb` | `{ icon: IconValue \| undefined; } & CdsToggleSlot` | Slot for the content of the thumb. | | `track-false` | `CdsToggleSlot` | Slot for the content of the off part of the track. | | `track-true` | `CdsToggleSlot` | Slot for the content of the on part of the track. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isDirty` | `boolean` | Whether the input is dirty | | `isDisabled` | `boolean` | Whether the input is disabled | | `isPure` | `boolean` | Whether the input is pure | | `isReadonly` | `boolean` | Whether the input is read-only | | `isValid` | `boolean \| null` | Whether the input is valid | | `isValidating` | `boolean` | Whether the input is being validated | | `reset` | `() => Promise` | Resets the input to its initial state | | `resetValidation` | `() => Promise` | Resets the validation of the input | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsToolbar _Category: Layouts · since 4.0.0_ _Tests: API 10/10 · 11 unit · lines 100% (v4.0.0-alpha.13) · a11y: 5 axe recommendations (v4.0.0-alpha.11)_ A horizontal bar with a title and actions: it fills the header and the footer of the application, and on a page it assembles the title of a section together with its buttons. `CdsToolbarTitle` stretches and pushes the left and the right groups to the edges on its own. **See also:** The toolbar only lays the content out — the place in the layout is reserved by CdsHeader and CdsFooter. For navigating the subsections take CdsTabs; for an action bar over a record take CdsButtonGroup. ## Anatomy The toolbar lines the content up in a row and centers it vertically. The `CdsToolbarTitle` title takes all the free space, so the elements before it stick to the left edge and the ones after it stick to the right. ## Variations ### Title `CdsToolbarTitle` stretches and truncates long text with an ellipsis without breaking the line. The `shrink` prop turns the stretching off: the title shrinks to its content and stays next to the neighboring element — a handy way to put a status or a counter right after the name. **Example — `Title.vue`:** ```vue ``` ### Paddings The `no-gutters` prop removes the inner paddings entirely — the toolbar aligns with the content of the page. The `no-gutter` prop removes the padding on one side: `start` or `end`. The `inset` prop does the opposite and adds a padding on the left — that is how a nested second-level toolbar is set off. **Example — `Spacing.vue`:** ```vue ``` ### Separator and color The `bordered` prop draws the bottom border — it separates the title of a section from its content. The `bg-color` and `color` props paint the background and the text. Inside `CdsHeader` and `CdsFooter` the toolbar does not draw its own background: the color comes from the part of the layout, so the bar does not cover it. **Example — `Colors.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A title in CdsToolbarTitle pushes the left and the right groups to the edges on its own. | A title as plain text does not stretch — the actions stick to the name. | | One primary action and a couple of secondary icons — the toolbar stays readable. | Five buttons of equal weight in a row: it is unclear what matters here. | ## Scenarios ### Section title on a page The name, the status and the actions in a single row: `shrink` keeps the status next to the name, `mr-auto` pushes the buttons to the right edge, `no-gutters` aligns the toolbar with the content of the card, and `bordered` separates the header of the section from the text. **Example — `PageHeader.vue`:** ```vue ``` ### Application header and footer In `CdsHeader` the toolbar holds the menu button, the title and the profile; in `CdsFooter` it holds the copyright. The background is set on the parts of the layout, and the toolbar inherits it together with the contrasting text color. **Example — `HeaderToolbar.vue`:** ```vue ``` ## API ### CdsToolbar **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `bordered` | `boolean \| undefined` | `false` | no | Shows the bottom border. | | `color` | `string \| undefined` | — | no | Component color | | `inset` | `boolean \| undefined` | `false` | no | Nested toolbar (indented from the left). | | `noGutter` | `"start" \| "end" \| undefined` | — | no | Removes the padding on one side: `start` or `end`. | | `noGutters` | `boolean \| undefined` | `false` | no | Removes all inner paddings. | | `theme` | `string \| undefined` | — | no | Component theme | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the toolbar. | ### CdsToolbarTitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `shrink` | `boolean \| undefined` | `false` | no | Shrinks the title to its content instead of stretching it. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text of the title. | --- # CdsTooltip _Category: Content · since 4.0.0_ _Tests: API 55/55 · 50 unit · 7 e2e · lines 100% (v4.0.0-alpha.13) · a11y: 11 axe recommendations (v4.0.0-alpha.11)_ A tooltip briefly explains an interface element on hover or focus: it names an icon button, shows the full text of a truncated line, explains why an action is unavailable. It appears and disappears on its own — the user does not have to press or close anything. **See also:** A tooltip is for a short text without interaction. A list of actions on click is the job of CdsMenu, and a dialog with a form and buttons is the job of CdsModal. ## Variations ### Activator The element the tooltip is attached to is set through the `activator` slot: the slot props (`v-bind="props"`) put the hover handlers and the `aria-describedby` attribute on it. The content of the tooltip comes from the `text` prop or from the default slot when you need markup. If the activator is already there and you would rather not wrap it, put `CdsTooltip` inside it with `activator="parent"` — that is how the examples in “Placement” and in the scenarios below are built. **Example — `Default.vue`:** ```vue ``` ### Placement The `location` prop sets the side of the activator the tooltip appears on: `top` by default, `bottom`, `left`, `right` — and their combinations with an alignment (`top left`, `bottom right`). If there is not enough room, the tooltip flips to the opposite side by itself. The `offset` prop tunes the distance to the activator. **Example — `Location.vue`:** ```vue ``` ### Arrow The arrow points at the activator and follows the actual position of the tooltip — including after an automatic flip near the edge of the screen. The `hide-arrow` prop hides it. **Example — `HideArrow.vue`:** ```vue ``` ### Opening behavior By default the tooltip opens on hover and on keyboard focus, with no delay. The `open-delay` and `close-delay` props add a pause — the tooltip does not blink when the cursor passes by. The `open-on-click` prop together with `:open-on-hover="false"` switches opening to a click. **Example — `OpenBehavior.vue`:** ```vue ``` ### Controlling the display `v-model` opens and closes the tooltip from code — this is how you show it in response to interface events, not only on hover. **Example — `VModel.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The tooltip names the action of an icon button — without it the icon is easy to misread. | The tooltip repeats the visible text word for word and adds nothing new. | | A short phrase reads in a second — the tooltip does not hold the user up. | An instruction of several sentences does not get read inside a tooltip: move it into the interface or into a modal. | | For a disabled button the tooltip explains why the action is closed and what to do about it. | A disabled button without an explanation leaves the user guessing. | ## Scenarios ### Icon button bar A tooltip gives an icon button back the name of its action. `CdsTooltip` lives inside the button with `activator="parent"` — there is no need to wrap the markup. `aria-label` is still required: the tooltip appears on hover, while the name of the action must be available at all times. **Example — `IconToolbar.vue`:** ```vue ``` ### Truncated text When space is limited, long titles are cut off with `truncate` — the tooltip shows the full text on hover over the line. The same `text` prop serves both as the content of the line and as the content of the tooltip. **Example — `TruncatedText.vue`:** ```vue ``` ### Unavailable action A disabled button should not stay silent — the tooltip explains why the action is closed. A button with `disabled` has its mouse events turned off, so the tooltip is attached to a wrapper through `activator="parent"`. The `disabled` prop of the tooltip itself turns it off as soon as the action becomes available. **Example — `DisabledHint.vue`:** ```vue ``` ### Confirming an action A tooltip can confirm an instant action when there is no room for a message — copying to the clipboard, for example. The display is driven by `v-model` on click, and `:open-on-hover="false"` keeps the tooltip from opening on a plain hover. After a second and a half a timer closes it on its own. **Example — `CopyFeedback.vue`:** ```vue ``` ### Onboarding The `interactive` prop allows interaction with the content: hovering the tooltip does not close it, and the elements inside stay clickable. So that the pointer can cross the gap from the activator to the tooltip, an interactive tooltip closes after a 250 ms delay; an explicit `close-delay` overrides it. Together with `open-on-click` and `v-model` this makes an onboarding tooltip: a “Learn more” link and a button that closes the tooltip. The `width` prop keeps the text width comfortable to read. **Example — `Onboarding.vue`:** ```vue ``` ## API ### CdsTooltip **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activator` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| undefined` | — | no | The element that activates the component | | `activatorProps` | `Record \| undefined` | `{}` | no | Props for the activator element | | `attach` | `string \| boolean \| Element \| undefined` | — | no | Sets the DOM element the overlay content is moved to. It accepts a direct element reference, a querySelector string, or true to disable moving. By default the body element is used. Changing this prop is usually not recommended except for edge cases: the default positioning algorithm handles most scenarios better than it can without moving, and unexpected behavior may appear if the menu ends up being a child of its activator. | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `false` | no | Closes the overlay content when the browser Back button is pressed or $router.back() is called, cancelling the original navigation. `persistent` overlays cancel the navigation and animate as if they were clicked outside instead of closing. | | `closeOnContentClick` | `boolean \| undefined` | — | no | Hide the component on a click on the content | | `color` | `string \| undefined` | — | no | Background color of the tooltip. | | `contained` | `boolean \| undefined` | — | no | Limits the size of the component and of its grid to the offset parent. Implies the `absolute` and `attach` props. (Note: the parent element must have `position: relative`.) | | `contentClass` | `any` | — | no | Applies a custom class to the content element. This is handy because the content is moved to the beginning of the cds-app component (unless `attach` is set) and cannot be selected with classes passed to the component directly. | | `contentProps` | `any` | — | no | Applies custom props to the moved content | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `eager` | `boolean \| undefined` | `true` | no | Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO. | | `height` | `string \| number \| undefined` | — | no | Component height | | `hideArrow` | `boolean \| undefined` | — | no | Hides the arrow pointing at the activator. The arrow is shown by default. | | `id` | `string \| undefined` | — | no | Unique id that links the tooltip to its activator. Generated automatically when omitted. | | `interactive` | `boolean \| undefined` | — | no | Allows interaction with the tooltip content: hovering the content does not close it. The tooltip closes after a 250 ms delay unless `closeDelay` is set, so the pointer can cross the gap between the activator and the tooltip. | | `location` | `Anchor \| undefined` | `'top'` | no | Sets the anchor point used to position the component, aligning it horizontally, vertically or in both directions | | `locationStrategy` | `"static" \| "connected" \| LocationStrategyFunction \| undefined` | `'connected'` | no | Sets the way the overlay content is positioned. By default static is used, which centers the content in its container. Use connected to attach the content to the activator element. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | `0` | no | Minimum component width | | `modelValue` | `boolean \| undefined` | — | no | The v-model value of the component. If the component supports the **multiple** prop, an empty array is used by default. | | `noClickAnimation` | `boolean \| undefined` | — | no | Disables the bounce effect on a click outside the content element when `persistent` is set. | | `offset` | `string \| number \| number[] \| undefined` | `10` | no | Increases the distance to the target. If two numbers are passed, the second one shifts the anchor sideways, away from the target. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the scrim element. Applies only when `scrim=true`. | | `openDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component opens. Works only together with open-on-hover. | | `openOnClick` | `boolean \| undefined` | `false` | no | Show the component on a click on the activator | | `openOnFocus` | `boolean \| undefined` | — | no | Show the component when the activator gets focus | | `openOnHover` | `boolean \| undefined` | `true` | no | Show the component on hover over the activator | | `origin` | `Anchor \| "auto" \| "overlap" \| undefined` | `'auto'` | no | Sets the anchor point of the overlay content that is aligned with the `location` anchor of the target. With "auto" the opposite side of the `location` point is used. With "overlap" the same anchor point is used, so the overlay overlaps the target. It also sets the CSS `transform-origin` property for the enter/leave transitions. | | `persistent` | `boolean \| undefined` | — | no | A click outside the element or the Esc key does not close it. | | `scrim` | `string \| boolean \| undefined` | `false` | no | Backdrop shown while the overlay is active. Accepts true/false to toggle the backdrop and a string to set its color. | | `scrollStrategy` | `"none" \| "close" \| "block" \| "reposition" \| ScrollStrategyFunction \| undefined` | `'reposition'` | no | Strategy applied when the component is active and the user scrolls the page. | | `stickToTarget` | `boolean \| undefined` | — | no | Lets the overlay content go off screen while scrolling. | | `target` | `(string & {}) \| Element \| "parent" \| ComponentPublicInstance \| "cursor" \| [x: number, y: number] \| undefined` | — | no | When `locationStrategy` is set to "connected", specify the element or the array of x, y coordinates the overlay is positioned against. By default the activator element is used. | | `text` | `string \| undefined` | — | no | Text of the tooltip. Used when the default slot is not passed. | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `null` | no | Transition animation | | `viewportMargin` | `string \| number \| undefined` | `12` | no | Sets a custom viewport margin for the overlay content | | `width` | `string \| number \| undefined` | — | no | Component width | | `zIndex` | `string \| number \| undefined` | `2000` | no | The z-index value of the component. | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: boolean]` | Fires when the tooltip is shown or hidden. Passes the new visibility state | **Slots** | Name | Type | Description | | --- | --- | --- | | `activator` | `{ isActive: boolean; props: Record; targetRef: TemplateRef; }` | Slot for the element that acts as the activator of the overlay. | | `default` | `{ isActive: Ref; }` | Slot for the overlay content. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `activatorEl` | `HTMLElement \| undefined` | The DOM element of the activator. | | `activatorRef` | `TemplateRef` | Template ref for assigning the activator manually. | | `animateClick` | `() => void` | Runs the bounce animation of the content — the same as on a click outside a `persistent` overlay. | | `contentEl` | `HTMLElement \| undefined` | The DOM element of the overlay content. | | `globalTop` | `boolean` | Whether the overlay is the top one in the global stack of open overlays. | | `rootEl` | `HTMLElement \| undefined` | The root DOM element of the overlay. | | `scrimEl` | `HTMLElement \| undefined` | The DOM element of the scrim that dims the page. | | `targetEl` | `HTMLElement \| undefined` | The DOM element of the positioning target. | | `targetRef` | `TemplateRef` | Template ref for assigning the positioning target manually. | | `updateLocation` | `((e: Event) => void) \| undefined` | Recalculates the position of the content relative to the target. | --- # CdsTree _Category: Content · since 4.0.0_ _Tests: API 116/116 · 152 unit · 8 e2e · 23 known bugs · lines 81.5% (v4.0.0-alpha.13) · a11y: 38 axe recommendations (v4.0.0-alpha.11)_ A tree shows a hierarchy: catalog sections, project files, an org structure. Nodes expand, get selected by a click or with checkboxes, load from the server and can be dragged, while virtual scrolling keeps everything smooth even with thousands of nodes. **See also:** For a flat set without nesting take CdsList, for navigation between sections take CdsMenu, and for collapsible sections of content take CdsExpandablePanel. ## Anatomy A tree node is made of the nesting indent, the expand switcher and the content with the title. The checkbox appears with the `checkable` prop, the node icon with `show-icon`. ## Variations ### Expanding nodes The data of the tree is an array of `{ title, key, children }` nodes in the `tree-data` prop. The expanded state is driven by `v-model:expanded-keys`; if you do not need to control it, set the initial state through `default-expanded-keys` or `default-expand-all`. **Example — `Default.vue`:** ```vue ``` The `expand-action` prop expands a node by a click on the whole row: `click` for a single click, `dblclick` for a double one. Without it a node expands only from the switcher. **Example — `ExpandAction.vue`:** ```vue ``` ### Selecting nodes and checkboxes The `selectable` prop turns on selecting a node by a click (`v-model:selected-keys`), `multiple` allows selecting several nodes. The `checkable` prop adds checkboxes with their own `v-model:checked-keys` state: checking a parent checks all its descendants, and a partially checked parent goes into the indeterminate state (turned off with the `check-strictly` prop). Individual nodes are disabled with the `disabled` and `disableCheckbox` flags right in the data. **Example — `Checkable.vue`:** ```vue ``` ### Connecting lines The `show-line` prop draws lines between the nodes — in deep trees this makes it easier to follow the levels. The `{ showLeafIcon }` object controls the icon of the leaf nodes. **Example — `ShowLine.vue`:** ```vue ``` ### Icons and slots Slots customize every part of a node; they receive the node context — `key`, `title`, `expanded`, `selected` and other fields. | Slot | Description | | -------------- | --------------------------------------------------------------------- | | `default` | Declarative description of the nodes in markup instead of `tree-data` | | `icon` | Icon of the node. Shown with `show-icon` | | `switcherIcon` | Icon of the expand switcher | | `title` | Content of the node title | **Example — `Slots.vue`:** ```vue ``` ### Asynchronous loading The `load-data` prop loads the child nodes on the first expand: the function receives the node, returns a promise and adds `children` to the data. Until the promise resolves, the node shows a loading indicator. **Example — `LoadData.vue`:** ```vue ``` ### Dragging The `draggable` prop allows dragging the nodes; the `{ icon: true }` variant shows a drag handle. The tree does not change the data by itself — the `@drop` handler rebuilds `tree-data`, and `allow-drop` limits the valid drop targets. **Example — `Draggable.vue`:** ```vue ``` ### Virtual scrolling The virtual list is on by default (the `virtual` prop). Set `height` and the tree scrolls inside a fixed height, rendering only the visible nodes: thousands of rows do not slow the page down. **Example — `VirtualScroll.vue`:** ```vue ``` ### Directory mode `CdsTreeDirectory` is a tree with presets for files and folders: directory icons, expanding on click and full-width nodes. It accepts the same props as `CdsTree`. **Example — `Directory.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A tree reveals nesting: its nodes have child levels. | A flat set without a hierarchy is a list — take CdsList. | | For selecting many nodes turn on checkboxes — the selection state is visible at once. | Multiple selection by clicking nodes is invisible and expects the user to know about Ctrl. | | Short node titles read like a table of contents. | Long phrases wrap onto several lines and break the rhythm of the tree. | ## Scenarios ### Picking sections for an export Checkboxes collect a set of sections, and the counter in the button hints at the size of the selection. The `loading` prop of the button shows the export in progress, `disabled` prevents starting it with an empty selection. **Example — `CategoryExport.vue`:** ```vue ``` ### Search across the tree An input field filters `tree-data` on the fly: the matches and their parents stay in the tree, and `v-model:expanded-keys` expands the branches with the found nodes. When there are no matches, show an empty state instead of the tree. **Example — `TreeSearch.vue`:** ```vue ``` ### Project files `CdsTreeDirectory` with `v-model:selected-keys` works as a file explorer: a click on a folder expands it, a click on a file selects it. The node keys hold the path to the file, so the selected item is ready to be shown or requested right away. **Example — `FileExplorer.vue`:** ```vue ``` ## API ### CdsTree **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `allowDrop` | `NTree.TAllowDrop \| undefined` | `true` | no | Decides whether a node accepts a drop | | `autoExpandParent` | `boolean \| undefined` | `false` | no | Expands the parent node automatically | | `blockNode` | `boolean \| undefined` | `false` | no | The tree node fills all the remaining horizontal space | | `checkable` | `boolean \| undefined` | `false` | no | Adds a checkbox before the tree nodes | | `checkedKeys` | `NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; } \| undefined` | — | no | (v-model) Keys of the checked tree nodes. When the key of a parent node is given, all its child nodes become checked; and the other way around, when the key of a child node is given, its parent node becomes checked too. When `checkable` and `checkStrictly` are both true, the object has the `checked` and `halfChecked` fields, and checking a child or a parent node no longer affects the other. | | `checkStrictly` | `boolean \| undefined` | `false` | no | Checks only the node itself, without its parents and children. | | `defaultExpandAll` | `boolean \| undefined` | `false` | no | Expands all the nodes by default | | `defaultExpandedKeys` | `NTree.TKey[] \| undefined` | `[]` | no | Expands all the nodes by default | | `defaultExpandParent` | `boolean \| undefined` | `true` | no | Expands the parent nodes by default | | `defaultSelectedKeys` | `NTree.TKey[] \| undefined` | — | no | Tree nodes selected by default | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `draggable` | `boolean \| NTree.TDraggableConfig \| undefined` | `false` | no | Allows dragging the tree nodes | | `expandAction` | `NTree.TExpandAction \| undefined` | — | no | Action that expands or collapses the tree nodes | | `expandedKeys` | `NTree.TKey[] \| undefined` | — | no | (v-model) Keys of the expanded tree nodes. | | `fieldNames` | `NTree.IFieldNames \| undefined` | — | no | Maps the title, key and children fields of a tree node to the matching fields of treeData | | `filterTreeNode` | `((treeNode: NTree.IEventDataNode) => boolean) \| undefined` | — | no | Function that filters (highlights) the tree nodes. When it returns true, the node is highlighted. | | `height` | `number \| undefined` | — | no | Height of the virtual scrolling list | | `icon` | `((nodeProps: NTree.ITreeNodeAttribute) => any) \| undefined` | — | no | Icon of the tree node (also available through slot#icon) | | `loadData` | `((treeNode: NTree.IEventDataNode) => Promise) \| undefined` | — | no | Loads the data of a tree node asynchronously | | `loadedKeys` | `NTree.TKey[] \| undefined` | `[]` | no | Keys of the already loaded tree nodes. Required to work with loadData | | `multiple` | `boolean \| undefined` | `false` | no | Allows selecting several tree nodes | | `openAnimation` | `Function \| undefined` | — | no | Animation function for expanding and collapsing a tree node | | `selectable` | `boolean \| undefined` | `false` | no | Makes the tree nodes selectable | | `selectedKeys` | `NTree.TKey[] \| undefined` | — | no | (v-model) Keys of the selected tree nodes. | | `showIcon` | `boolean \| undefined` | `false` | no | Shows the icon of the tree node | | `showLine` | `boolean \| { showLeafIcon: string \| boolean; } \| undefined` | — | no | Shows the lines between the tree nodes | | `switcherIcon` | `((nodeProps: SwitcherIconProps) => any) \| undefined` | — | no | Icon of the expand/collapse switcher (also available through slot#switcherIcon) | | `theme` | `string \| undefined` | — | no | Component theme | | `treeData` | `NTree.IDataNode[] \| undefined` | — | no | Data of the tree | | `virtual` | `boolean \| undefined` | `true` | no | Enables virtual scrolling of the list inside the tree; enabled by default | **Events** | Name | Type | Description | | --- | --- | --- | | `check` | `[checked: NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; }, info: NTree.ICheckInfo]` | A node was checked with its checkbox. | | `click` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Click on a node. | | `dblclick` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Double click on a node. | | `doubleclick` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Double click on a node (alias). | | `dragend` | `[info: NTree.TNodeDragEventParams]` | Dragging of a node finished. | | `dragenter` | `[info: NTree.TNodeDragEventParams & { expandedKeys: NTree.TKey[]; }]` | A dragged node entered the drop area. | | `dragleave` | `[info: NTree.TNodeDragEventParams]` | A dragged node left the drop area. | | `dragover` | `[info: NTree.TNodeDragEventParams]` | A dragged node moves inside the drop area. | | `dragstart` | `[info: NTree.TNodeDragEventParams]` | Dragging of a node started. | | `drop` | `[info: NTree.TNodeDragEventParams & { dragNode: NTree.IEventDataNode; dragNodesKeys: NTree.TKey[]; dropPosition: number; dropToGap: boolean; }]` | A node was dropped. | | `expand` | `[expandedKeys: NTree.TKey[], info: { node: NTree.IEventDataNode; expanded: boolean; nativeEvent: MouseEvent; }]` | A node was expanded or collapsed. | | `load` | `[loadedKeys: NTree.TKey[], info: { event: "load"; node: NTree.IEventDataNode; }]` | Children of a node were loaded (async loadData). | | `rightClick` | `[info: { event: MouseEvent; node: NTree.IEventDataNode; }]` | Right click on a node. | | `select` | `[selectedKeys: NTree.TKey[], info: { event: "select"; selected: boolean; node: NTree.IEventDataNode; selectedNodes: NTree.IDataNode[]; nativeEvent: MouseEvent; }]` | A node was selected. | | `update:checkedKeys` | `[checkedKeys: NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; }]` | Checking of a node changed (v-model). | | `update:expandedKeys` | `[expandedKeys: NTree.TKey[]]` | Expansion of a node changed (v-model). | | `update:selectedKeys` | `[selectedKeys: NTree.TKey[]]` | Selection of a node changed (v-model). | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Tree nodes by default (when described declaratively in markup). | | `icon` | `NTree.ITreeNodeAttribute` | Custom icon of the tree node. | | `switcherIcon` | `any` | Custom icon of the expand/collapse switcher. | | `title` | `NTree.IEventDataNode` | Custom title of the tree node. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `halfCheckedKeys` | `any` | Keys of the nodes with partially checked children — the “half checked” state. | | `loadingKeys` | `any` | Keys of the nodes whose children are being lazily loaded right now. | | `scrollTo` | `ScrollTo` | Scrolls the tree to a node by its key or to a given position. | | `treeRef` | `any` | Reference to the internal tree instance. | ### CdsTreeDirectory **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `allowDrop` | `NTree.TAllowDrop \| undefined` | `true` | no | Decides whether a node accepts a drop | | `autoExpandParent` | `boolean \| undefined` | `false` | no | Expands the parent node automatically | | `blockNode` | `boolean \| undefined` | `false` | no | The tree node fills all the remaining horizontal space | | `checkable` | `boolean \| undefined` | `false` | no | Adds a checkbox before the tree nodes | | `checkedKeys` | `NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; } \| undefined` | — | no | (v-model) Keys of the checked tree nodes. When the key of a parent node is given, all its child nodes become checked; and the other way around, when the key of a child node is given, its parent node becomes checked too. When `checkable` and `checkStrictly` are both true, the object has the `checked` and `halfChecked` fields, and checking a child or a parent node no longer affects the other. | | `checkStrictly` | `boolean \| undefined` | `false` | no | Checks only the node itself, without its parents and children. | | `defaultExpandAll` | `boolean \| undefined` | `false` | no | Expands all the nodes by default | | `defaultExpandedKeys` | `NTree.TKey[] \| undefined` | `[]` | no | Expands all the nodes by default | | `defaultExpandParent` | `boolean \| undefined` | `true` | no | Expands the parent nodes by default | | `defaultSelectedKeys` | `NTree.TKey[] \| undefined` | — | no | Tree nodes selected by default | | `draggable` | `boolean \| NTree.TDraggableConfig \| undefined` | `false` | no | Allows dragging the tree nodes | | `expandAction` | `string \| false \| undefined` | — | no | Action that expands or collapses the tree nodes | | `expandedKeys` | `NTree.TKey[] \| undefined` | — | no | (v-model) Keys of the expanded tree nodes. | | `fieldNames` | `NTree.IFieldNames \| undefined` | — | no | Maps the title, key and children fields of a tree node to the matching fields of treeData | | `filterTreeNode` | `((treeNode: NTree.IEventDataNode) => boolean) \| undefined` | — | no | Function that filters (highlights) the tree nodes. When it returns true, the node is highlighted. | | `height` | `number \| undefined` | — | no | Height of the virtual scrolling list | | `icon` | `((nodeProps: NTree.ITreeNodeAttribute) => any) \| undefined` | — | no | Icon of the tree node (also available through slot#icon) | | `loadData` | `((treeNode: NTree.IEventDataNode) => Promise) \| undefined` | — | no | Loads the data of a tree node asynchronously | | `loadedKeys` | `NTree.TKey[] \| undefined` | `[]` | no | Keys of the already loaded tree nodes. Required to work with loadData | | `multiple` | `boolean \| undefined` | `false` | no | Allows selecting several tree nodes | | `openAnimation` | `Function \| undefined` | — | no | Animation function for expanding and collapsing a tree node | | `selectable` | `boolean \| undefined` | `false` | no | Makes the tree nodes selectable | | `selectedKeys` | `NTree.TKey[] \| undefined` | — | no | (v-model) Keys of the selected tree nodes. | | `showIcon` | `boolean \| undefined` | `false` | no | Shows the icon of the tree node | | `showLine` | `boolean \| { showLeafIcon: string \| boolean; } \| undefined` | — | no | Shows the lines between the tree nodes | | `switcherIcon` | `((nodeProps: SwitcherIconProps) => any) \| undefined` | — | no | Icon of the expand/collapse switcher (also available through slot#switcherIcon) | | `treeData` | `NTree.IDataNode[] \| undefined` | — | no | Data of the tree | | `virtual` | `boolean \| undefined` | `true` | no | Enables virtual scrolling of the list inside the tree; enabled by default | **Events** | Name | Type | Description | | --- | --- | --- | | `check` | `[checked: NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; }, info: NTree.ICheckInfo]` | A node was checked with its checkbox. | | `click` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Click on a node. | | `dblclick` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Double click on a node. | | `doubleclick` | `[event: MouseEvent, node: NTree.IEventDataNode]` | Double click on a node (alias). | | `dragend` | `[info: NTree.TNodeDragEventParams]` | Dragging of a node finished. | | `dragenter` | `[info: NTree.TNodeDragEventParams & { expandedKeys: NTree.TKey[]; }]` | A dragged node entered the drop area. | | `dragleave` | `[info: NTree.TNodeDragEventParams]` | A dragged node left the drop area. | | `dragover` | `[info: NTree.TNodeDragEventParams]` | A dragged node moves inside the drop area. | | `dragstart` | `[info: NTree.TNodeDragEventParams]` | Dragging of a node started. | | `drop` | `[info: NTree.TNodeDragEventParams & { dragNode: NTree.IEventDataNode; dragNodesKeys: NTree.TKey[]; dragPosition: number; dropToGap: boolean; }]` | A node was dropped. | | `expand` | `[expandedKeys: NTree.TKey[], info: { node: NTree.IEventDataNode; expanded: boolean; nativeEvent: MouseEvent; }]` | A node was expanded or collapsed. | | `load` | `[treeNode: NTree.IEventDataNode]` | Children of a node were loaded (async loadData). | | `rightClick` | `[info: { event: MouseEvent; node: NTree.IEventDataNode; }]` | Right click on a node. | | `select` | `[selectedKeys: NTree.TKey[], info: { event: "select"; selected: boolean; node: NTree.IEventDataNode; selectedNodes: NTree.IDataNode[]; nativeEvent: MouseEvent; }]` | A node was selected. | | `update:checkedKeys` | `[checkedKeys: NTree.TKey[] \| { checked: NTree.TKey[]; halfChecked: NTree.TKey[]; }]` | Checking of a node changed (v-model). | | `update:expandedKeys` | `[expandedKeys: NTree.TKey[]]` | Expansion of a node changed (v-model). | | `update:selectedKeys` | `[selectedKeys: NTree.TKey[]]` | Selection of a node changed (v-model). | ### CdsTreeNode **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Highlights the node as active | | `checkable` | `boolean \| undefined` | — | no | Shows a checkbox next to the node | | `data` | `NTree.IDataNode \| undefined` | `undefined as unknown as NTree.IDataNode` | no | Data of the node — the original list item the node is built from | | `disableCheckbox` | `boolean \| undefined` | — | no | Disables only the checkbox of the node, leaving the node itself available | | `disabled` | `boolean \| undefined` | — | no | Disables the node: it cannot be selected, checked or expanded | | `domRef` | `((arg: any) => void) \| undefined` | — | no | Callback that receives the DOM element of the node after mounting | | `eventKey` | `NTree.TKey \| undefined` | `''` | no | Unique key of the node — the tree uses it to track selection, expansion and checking | | `icon` | `Function \| undefined` | — | no | Function that returns the icon of the node | | `isEnd` | `boolean[] \| undefined` | — | no | “Last on its level” flags for every nesting level — the connecting lines are drawn from them | | `isLeaf` | `boolean \| undefined` | — | no | The node is a leaf: it has no children and shows no expand switcher | | `isStart` | `boolean[] \| undefined` | — | no | “First on its level” flags for every nesting level — the connecting lines are drawn from them | | `parent` | `NTree.IDataNode \| undefined` | `undefined as unknown as NTree.IDataNode` | no | Data of the parent node. Not set for the top-level nodes | | `prefixCls` | `string \| undefined` | — | no | Prefix of the CSS classes of the node | | `selectable` | `boolean \| undefined` | — | no | Allows selecting the node | | `switcherIcon` | `Function \| undefined` | — | no | Function that returns the icon of the expand switcher | | `title` | `string \| (Function & string) \| undefined` | — | no | Tree node title: a string or a render function | --- # CdsUploader _Category: Controls · since 4.0.0_ _Tests: API 77/77 · 102 unit · 3 e2e · 18 known bugs · lines 96.8% (v4.0.0-alpha.13) · a11y: 27 axe recommendations (v4.0.0-alpha.11)_ The uploader sends files to the server right from the interface: the user picks them in the system dialog or drags them onto the button, and the component shows the list of what was uploaded — with a status, progress, downloading and removal. Every step of the file lifecycle comes with an event. **See also:** The uploader sends the files over HTTP itself. If the files only have to be picked and sent together with the form, take the CdsFileInput field, and for a drop zone with image previews — CdsFileUpload. ## Anatomy The first diagram is the frame: the label, the description, the upload button and the messages. The second one is an item of the file list during the upload: the status, the name as a link, the actions and the progress bar. ## Variations ### The upload button By default the upload is started by the primary "Загрузить файл" button with the `upload-icon` icon. The `button-props` prop passes any CdsButton props to the button, and the `default` slot replaces it entirely — the ready props of the button arrive in the `props` slot argument. **Example — `TriggerButton.vue`:** ```vue ``` ### Allowed file types The `accept` prop limits the choice in the system dialog and filters out the unsuitable files on a drop — the rejected ones arrive in the `reject` event. **Example — `Default.vue`:** ```vue ``` ### The file list The list of the uploaded files lives in `v-model` — put the files received from the server into it and they will be shown right away. The `show-upload-list` prop controls the list: `false` hides it entirely, an object turns on the download and removal icons. **Example — `FileList.vue`:** ```vue ``` ### Number of files The `max-count` prop limits the length of the list: with `max-count="1"` a new file replaces the previous one, with a larger limit the extra files are dropped. **Example — `MaxCount.vue`:** ```vue ``` ### Uploading directories The `directory` prop turns on picking a whole folder — the files are collected from it recursively, on a drop as well. **Example — `Directories.vue`:** ```vue ``` ### States `disabled` blocks the button and removes the removal icons from the list, `readonly` forbids changing the list but keeps the downloading. **Example — `States.vue`:** ```vue ``` ### Slots When props are not enough, the content of any block is replaced by a slot. | Slot name | Description | | :------------ | :--------------------------------------------------------------------------- | | `label` | Label content (replaces `label`) | | `description` | Description content (replaces `description`) | | `prepend` | Element before the upload button | | `default` | Your own upload button; receives the ready `props` for CdsButton | | `append` | Element after the upload button | | `messages` | Content of the messages block | | `itemRender` | Your own rendering of a list item; receives `file`, `fileList` and `actions` | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The description names the allowed formats and size upfront — the user does not waste an attempt. | Without a description the restrictions are learned only from an error after the upload. | | The text of the button names exactly what to upload. | “Click here” says nothing about the action nor about the content. | | The list shows what has already been uploaded and lets the extra files be removed. | With the list hidden the user does not see the result and uploads the files again. | ## Scenarios ### Deferred sending The `before-upload` hook returning `false` turns the automatic sending off: the files pile up in the list, and the upload is started by a separate button in the `append` slot — together with the submission of the whole form, for example. **Example — `UploadManual.vue`:** ```vue ``` ### A check before the upload The same `before-upload` is the place for validation: return `false` and the file will not go to the server. A rejected file still gets into the list — remove it in the `change` handler and show the reason through `error-messages`. **Example — `BeforeUpload.vue`:** ```vue ``` ### Upload errors A file rejected by the server stays in the list with the error status. The `show-tooltip-with-error` prop shows the server response in a tooltip next to the status, and the `error` event lets you collect the messages under the field — here they pile up in `error-messages` and are reset when the file is removed. **Example — `UploadErrors.vue`:** ```vue ``` ### Uploading without a server The `custom-request` prop replaces the built-in XHR transport with your own function: it receives the file and the `onProgress`, `onSuccess`, `onError` callbacks and returns an object with an `abort` method. Here the upload is simulated with a timer — files can be sent through an SDK or a WebSocket in the same way. **Example — `CustomRequest.vue`:** ```vue ``` ### Events The component reports every step: `change` — any change of the list, `progress`, `success` and `error` — the course of the upload, `remove`, `drop`, `reject`, `download`, `preview` — the actions of the user. Open the console to see them. **Example — `Events.vue`:** ```vue ``` ## API ### CdsUploader **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `accept` | `string \| string[] \| undefined` | `''` | no | Allowed file types | | `action` | `NUploader.TAction \| undefined` | `''` | no | URL the files are uploaded to | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendIcon` | `IconValue \| undefined` | — | no | Icon in the append slot, after the content | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `beforeUpload` | `((file: NUploader.IUploadFile, fileList: NUploader.IUploadFile[]) => NUploader.TBeforeUploadFileType \| Promise) \| undefined` | — | no | Lifecycle hook called before a file is uploaded | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `buttonProps` | `Partial \| undefined` | `null` | no | Props for the CdsButton component | | `capture` | `boolean \| "user" \| "environment" \| undefined` | — | no | Type of the media the file is captured from on mobile devices | | `centerAffix` | `boolean \| undefined` | `true` | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `color` | `string \| undefined` | — | no | Component color | | `customRequest` | `((options: NUploader.IUploadRequestOption) => void) \| undefined` | — | no | Your own file upload request. Overrides the default xhr | | `data` | `Record \| ((file: string \| Blob \| NUploader.IRcFile) => Record) \| {} \| undefined` | `{}` | no | Parameters of the file upload or a function returning them | | `defaultFileList` | `NUploader.IUploadFile[] \| undefined` | — | no | Default list of files | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `directory` | `boolean \| undefined` | — | no | Upload directories | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `downloadIcon` | `IconValue \| undefined` | `'download'` | no | File download icon | | `error` | `boolean \| undefined` | — | no | Puts the component into the error state | | `errorMessages` | `string \| readonly string[] \| null \| undefined` | `[]` | no | Puts the component into the error state and passes custom error messages. They are merged with any checks defined in the `rules` prop. This field does not trigger validation. | | `focused` | `boolean \| undefined` | — | no | Controls the focus state of the component. When `true`, the component is considered focused and may apply the corresponding styles or behavior. | | `headers` | `NUploader.TUploadRequestHeaders \| undefined` | — | no | Request headers | | `hideDetails` | `boolean \| "auto" \| undefined` | — | no | Hides the details block (messages and hints). With the 'auto' value the block is hidden when there are no messages | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `hint` | `string \| undefined` | — | no | Hint text shown under the input | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `isImageUrl` | `((file: NUploader.IUploadFile) => boolean) \| undefined` | — | no | Configuration of the thumbnails of the uploaded files (not supported yet) | | `itemRender` | `NUploader.TItemRender \| undefined` | — | no | Render function for an item of the uploaded file list | | `label` | `string \| undefined` | — | no | Label text of the component | | `listType` | `NUploader.TUploadListType \| undefined` | `'text'` | no | Type of the uploaded file list ('text' only is supported) | | `maxCount` | `number \| undefined` | — | no | Maximum number of uploaded files | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `method` | `NUploader.TUploadRequestMethod \| undefined` | — | no | HTTP method of the upload request | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `any` | — | no | Value of the component in v-model. If the component supports the multiple prop, an empty array is used by default. | | `multiple` | `boolean \| undefined` | `true` | no | Uploading several files at once | | `name` | `string \| undefined` | — | no | Name of the input | | `openFileDialogOnClick` | `boolean \| undefined` | — | no | Whether to open the system dialog on a click on the uploader | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `prependIcon` | `IconValue \| undefined` | — | no | Icon in the prepend slot, before the content | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `removeIcon` | `IconValue \| undefined` | `'delete'` | no | File removal icon | | `rules` | `readonly ValidationRule[] \| undefined` | `[]` | no | Accepts an array of items of different types: functions, booleans and strings. Functions take the input value as an argument and must return either true / false, or a string with an error message. The input goes into the error state if a function returns false (or any value in the array is false) or is a string. | | `showTooltipWithError` | `boolean \| undefined` | `false` | no | Whether to show a tooltip with the error next to every file | | `showUploadList` | `boolean \| NUploader.TShowUploadList \| undefined` | `true` | no | Show the list of the uploaded files | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `tag` | `string \| JSXComponent \| undefined` | `'span'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `uploadIcon` | `IconValue \| undefined` | `'upload'` | no | File upload icon | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `width` | `string \| number \| undefined` | — | no | Component width | | `withCredentials` | `boolean \| undefined` | — | no | Send the request with cookies | **Events** | Name | Type | Description | | --- | --- | --- | | `change` | `[info: NUploader.IUploadChangeParam>]` | Fires when the field changes | | `download` | `[file: NUploader.IUploadFile]` | Fires when a file is downloaded | | `drop` | `[event: DragEvent]` | Fires when a file is dropped | | `error` | `[error: ProgressEvent \| NUploader.IUploadRequestError, response: any, file: NUploader.IUploadFile]` | Fires when a file upload fails | | `preview` | `[file: NUploader.IUploadFile]` | Fires when a file preview is opened | | `progress` | `[event: { percent: number; } \| undefined, file: NUploader.IUploadFile]` | Fires while a file is being uploaded | | `reject` | `[fileList: NUploader.IUploadFile[]]` | Fires when a file upload is rejected | | `remove` | `[file: NUploader.IUploadFile]` | Fires when a file is removed | | `success` | `[response: Record, file: NUploader.IUploadFile]` | Fires when a file has been uploaded successfully | | `update:modelValue` | `[fileList: NUploader.IUploadFile[]]` | Fires when the value changes (v-model) | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `any` | Content of the append slot after the upload button. | | `default` | `{ props: Partial; }` | The upload button or activator. Receives the props for CdsButton. | | `description` | `any` | Description under the label. | | `itemRender` | `{ originNode: VNode; file?: NUploader.IUploadFile \| undefined; fileList?: NUploader.IUploadFile[] \| undefined; actions: { download?: (() => void) \| undefined; preview?: (() => void) \| undefined; remove?: (() => void) \| undefined; }; }` | Custom rendering of an item of the uploaded file list. | | `label` | `any` | Label of the upload field. | | `messages` | `any` | Hint and error messages. | | `prepend` | `any` | Content of the prepend slot before the upload button. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `fileList` | `NUploader.IUploadFile[]` | Current list of files together with their upload statuses. | | `uploadRef` | `NUploader.IUploaderRef \| undefined` | Ref to the inner upload element — gives access to choosing files programmatically and to aborting. | --- # CdsVirtualScroll _Category: Content · since 4.0.0 · status: new_ _Tests: API 16/16 · 23 unit · 3 e2e · 1 known bug · lines 93.5% (v4.0.0-alpha.13) · a11y: 6 axe recommendations (v4.0.0-alpha.11)_ Virtual scrolling keeps long lists fast: only the visible rows get into the DOM, not the whole array. Pass the records to `items`, the markup of a row to the slot, and a list of tens of thousands of positions scrolls as smoothly as a list of ten. **See also:** The dropdowns of CdsSelect and CdsAutocomplete, as well as the CdsTree tree, already virtualize their items — there is no need to wrap them. Render a short list — up to a couple of hundred rows — with the regular CdsList: virtualization will not pay off there. ## Variations ### Fixed height The `height` prop sets the height of the viewport — the scrolling happens inside it. If all the rows have the same height, set `item-height`: the component will not measure every row, and the positions and the scrollbar will be exact from the very first render. **Example — `FixedHeight.vue`:** ```vue ``` ### Dynamic height Without `item-height` the component measures the rows automatically — this fits content of variable length: comments, messages, descriptions. The heights get refined as you scroll, so the scrollbar may shift slightly. **Example — `DynamicHeight.vue`:** ```vue ``` ### Renderless mode The `renderless` prop removes the own scroll container: the component listens to the scrolling of the nearest scrollable parent and renders the rows without wrappers. The slot additionally receives `itemRef` — bind it to the root node of the row so that the component knows its height. This is how the list fits into an existing scroll — of a panel or of the whole page. Give the scrollable parent `position: relative` — the component counts the row positions from it. **Example — `Renderless.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A short list renders in full — with the regular CdsList, without a nested scroll. | Virtualizing a few rows speeds up nothing, while an extra scroll container hides part of the list. | | A search next to a long list leads to the right row in seconds. | Scrolling by hand is the only way to find a record among thousands of rows. | ## Scenarios ### Catalog search Pass an already filtered array to `items`: a `computed` recalculates the records on input, and the component picks the new list up on its own. `item-key="id"` binds the rows to the records rather than to the positions in the array — so the rows do not get mixed up while filtering. **Example — `CatalogSearch.vue`:** ```vue ``` ### Jumping through a journal The component exposes the `scrollToIndex` method — get it through a ref and scroll the list programmatically. The month buttons calculate the index of the first operation of the month; with a fixed `item-height` the jump lands exactly on the right row. **Example — `MonthNavigation.vue`:** ```vue ``` ### Selection in a long list The rows outside the screen do not exist in the DOM, so keep the selection state in the data, not in the rows themselves. In the demo the checked `id`s live in a `Set`: the checkbox of a row reads it and changes it on click — the selection survives any scrolling. **Example — `RecipientsPicker.vue`:** ```vue ``` ## API ### CdsVirtualScroll **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `height` | `string \| number \| undefined` | — | no | Component height | | `itemHeight` | `string \| number \| undefined` | `null` | no | Height of a single item in pixels. When omitted, the height is measured automatically. | | `itemKey` | `SelectItemKey` | `null` | no | Key that identifies an item (a field name, a path or a function). The index is used by default. | | `items` | `readonly unknown[] \| undefined` | `[]` | no | Array of the items rendered by the virtual scroll. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `renderless` | `boolean \| undefined` | — | no | Renderless mode: the component does not create its own scroll container and uses the nearest scrollable parent instead. | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsVirtualScrollSlot & { itemRef?: TemplateRef \| undefined; }` | Content of a single list item. In `renderless` mode it additionally receives `itemRef`. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `calculateVisibleItems` | `() => void` | Recalculates the window of visible items — needed after their height changes outside the update cycle. | | `scrollToIndex` | `(index: number) => void` | Scrolls the list to the item with the given index. | ### CdsVirtualScrollItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `renderless` | `boolean \| undefined` | — | no | Renderless mode: the item renders only the slot content, without a wrapper. | **Events** | Name | Type | Description | | --- | --- | --- | | `update:height` | `[height: number]` | Tells the virtual list that the height of the item has changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ itemRef: TemplateRef; }` | Content of the item. In `renderless` mode it receives `itemRef` to measure the height. | --- # Миграция на CDS 4 `@central-design-system/components` v4 — мажорное обновление дизайн-системы. Этот документ — **живой** migration guide: записи добавляются по мере появления breaking-изменений в alpha/beta релизах CDS 4. > Версии: CDS 3 — `3.10.1` (стабильная), CDS 4 — `4.0.0-alpha.4` (в разработке). ## Как читать этот документ - Каждая запись имеет **severity** (см. ниже). Сначала разбирайтесь с `BREAKING`, затем с `RENAMED`, затем с `DEPRECATED`. - Записи сгруппированы по **категориям** (Архитектура, Иконки, …). Изменения по конкретным компонентам — в разделе [Компоненты](#8-компоненты). - Каждая запись содержит блоки **Было (CDS 3)** и **Стало (CDS 4)** с примерами кода и поле **Действие** — конкретный шаг миграции. - При запуске приложения смотрите на консольные `[CDS UPGRADE]` warnings — они подсказывают точки миграции в рантайме (реализация: `src/utils/dom/warn.ts → deprecate()`). ## Легенда severity | Маркер | Что значит | | --- | --- | | ⚠️ **BREAKING** | Ломает существующий код — обязательное действие. | | 🔁 **RENAMED** | Переименование (частный случай breaking) — механический поиск/замена. | | 🟠 **DEPRECATED** | Работает в 4.x, будет удалено в 5.x. Желательно обновить. | | ✨ **NEW** | Новая возможность без ломки. Информативно. | ## Оглавление - [Быстрый чек-лист](#быстрый-чек-лист) - [1. Архитектура](#1-архитектура) - [2. Иконки](#2-иконки) - [3. Пропсы](#3-пропсы) - [4. Стили и токены](#4-стили-и-токены) - [5. Композаблы](#5-композаблы) - [6. Hooks](#6-hooks) - [7. Сборка и экспорты](#7-сборка-и-экспорты) - [8. Компоненты](#8-компоненты) ## Быстрый чек-лист - ✅ Прочитать раздел [«Архитектура»](#1-архитектура) — публичный API инициализации мог измениться. - ✅ Если используете `@central-design-system/icons` — см. раздел [«Иконки»](#2-иконки) (есть legacy-режим). - ✅ Заменить `rgb(var(--cds-…))` на `var(--cds-…)` — цвета в переменных теперь готовые значения (скилл `cds-migrate`, см. [«Стили и токены»](#4-стили-и-токены)). - ✅ Проверить [индекс изменений по компонентам](#индекс-изменений-по-компонентам). - ✅ Прогнать сборку приложения и проверить консоль: `[CDS UPGRADE]` warnings указывают на устаревшие пропсы. --- ## 1. Архитектура Сюда попадают изменения публичного API инициализации (`createCds`), DI через `provide/inject`, точек входа и общих принципов работы фреймворка. ### Библиотека переписана на новую архитектуру (JSX, `propsFactory`, `composables` / `hooks`) > ✨ **NEW** — внутренняя архитектура CDS 4 переписана с нуля. На публичный API компонентов это, как правило, не влияет, но меняет способ расширения библиотеки и пути «глубоких» импортов. **Было (CDS 3):** ```ts // CDS 3 — SFC на