# Central Design System (CDS 4) — components > Version: 4.0.0-alpha.13 > Documentation for all `@central-design-system/components` components: purpose, examples, and the full API contract. > 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`. --- # CdsApp _Category: Other_ _Tests: API 3/3 · 7 unit · lines 100% (v4.0.0-alpha.13)_ ## API ### CdsApp **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `storybook` | `boolean \| "fluid" \| undefined` | `false` | no | Режим отображения внутри Storybook: убирает полноэкранную обёртку, `'fluid'` дополнительно снимает ограничение ширины | | `theme` | `string \| undefined` | — | no | Component theme | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default slot | --- # CdsAutocomplete _Category: Controls · since 4.0.0_ _Tests: API 127/127 · 106 unit · 11 e2e · 12 known bugs · lines 82.5% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ An autocomplete is a field for picking from a long list: the user types a query, the list is filtered on the fly and the matches are highlighted. The field is built on CdsTextInput, and the menu and the list are the same as in CdsSelect, so the label, the messages, validation and the menu behave identically. **See also:** If there are few options and search is not needed, take CdsSelect. If the user may enter values outside the list — CdsCombobox. ## Anatomy The first diagram shows the frame of the component: the label, the description, the field and the messages block. The second one shows how the field itself is built: the zone of the selected value, the clear button and the menu indicator; the inner and outer icon zones are the same as in CdsTextInput. ## Variations The autocomplete repeats the variations of CdsSelect — grouping, "select all", list and menu settings. Below is what search adds. ### List items The list is set by the `items` prop — an array of strings or of objects with the same interface as in CdsList. Start typing and the list is filtered by item titles, with the matching fragments highlighted. **Example — `Default.vue`:** ```vue ``` ### Search across several fields By default the filter compares the query with the item title. The `filter-keys` prop widens the search area: `title` — the title, `raw.*` — a path to a field of the source object. Your own comparison logic is set by the `custom-filter` function, and `no-filter` turns the built-in filtering off entirely — when the results are already filtered by the server, for example. **Example — `Filtering.vue`:** ```vue ``` ### Auto-selecting the first item The `auto-select-first` prop highlights the first matching item — Enter or Tab select it without arrow keys or a click. The `exact` value highlights an item only when the query matches its title completely. **Example — `AutoSelectFirst.vue`:** ```vue ``` ### Multiple selection and chips The `multiple` prop allows selecting several values, `chips` shows them as CdsTag tags, and `closable-chips` adds a cross — the value is removed right in the field. `clear-on-select` clears the search query after every selection, `hide-selected` removes the already selected items from the list. **Example — `MultipleChips.vue`:** ```vue ``` ### Slots The menu and field slots are the same as in CdsSelect and CdsTextInput; for examples of `item`, `selection`, `chip` and the menu slots see the select page — in the autocomplete they work the same way. | 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 search result is empty | | `subheader` / `divider` | Group subheader and divider | | `menu-header` / `menu-footer` | Menu header and footer; receive `search` and `filteredItems` | The `no-data` slot is seen more often in the autocomplete than in the select: a query is easy to mistype. Bind the query through `v-model:search` and offer a way out — adding the entered value to the reference book, for example. **Example — `NoData.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | An autocomplete pays off on a long list — typing a couple of letters is faster than scrolling. | Two or three options do not need a search: take CdsSelect or radio buttons. | | If values outside the list are allowed, take CdsCombobox — what is typed is kept as is. | The autocomplete accepts list items only: text typed without a selection is lost. | | An empty result explains what happened and suggests the next step. | A hidden menu (hide-no-data) looks like a breakage: the user does not understand why the list disappeared. | ## Scenarios ### Search on the server When the reference book is too large to load in full, search on the server: `v-model:search` gives out the query, the response goes into `items`, and `no-filter` turns off the repeated filtering on the client. `loading` shows that a request is in progress, and the `no-data` slot changes the caption of the empty menu by state: a hint before the input, "Searching…" during the request, "Nothing found" after an empty response — the menu never stays blank. **Example — `ServerSearch.vue`:** ```vue ``` ### Picking recipients The combination of `multiple`, `chips`, `closable-chips` and `clear-on-select` collects the recipients as tags and is immediately ready for the next input. `filter-keys` searches both by name and by email, `hide-selected` removes the already added ones from the list, and the `item` slot shows the avatar and the address — that way it is easier not to confuse namesakes. **Example — `Recipients.vue`:** ```vue ``` ### Submitting a form The autocomplete takes part in CdsForm validation on a par with text fields: `rules` will not let the form through without a chosen city. Remember that only the selected item stays as the value — text typed without a selection does not get into the model. **Example — `FormSubmit.vue`:** ```vue ``` ### A large reference book The menu renders items through virtual scrolling, so a list of tens of thousands of entries does not slow down either on opening or on filtering. `auto-select-first` speeds up the input: type the number — press Enter. **Example — `LargeList.vue`:** ```vue ``` ## API ### CdsAutocomplete **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` | `'off'` | 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 | | `autoSelectFirst` | `boolean \| "exact" \| undefined` | — | no | Highlights the first matching item as you type; Enter or Tab select it. The `exact` value highlights it only on a full match of the search query with the item title. | | `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 | | `clearOnSelect` | `boolean \| undefined` | — | no | Clears the search query after an item is selected (relevant for `multiple`). | | `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` | `['title']` | 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 | | `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` | `[value: 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 search query has not changed since the last selection. | | `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 | --- # CdsAvatar _Category: Content · since 4.0.0 · status: new_ _Tests: API 17/17 · 25 unit · 2 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 8 axe recommendations (v4.0.0-alpha.11)_ An avatar shows a person, a team or a company: a photo, initials or an icon inside a round container. Use it in member lists, comments and profile headers — anywhere the reader needs to recognize "who is this" at a glance. **See also:** The built-in badge shows a status or a counter right on the avatar; for a marker on arbitrary content take CdsBadge, and for a text label inside a line — CdsTag. ## Anatomy An avatar is a container with one of three kinds of content and an optional badge in the top corner. ## Variations ### Content The content comes from one of three props: `image` — a photo, `icon` — an icon, `text` — initials. If you pass several of them, `image` wins, then `icon`. **Example — `Content.vue`:** ```vue ``` ### Sizes The `size` prop takes a token from `xs` to `xl` or a number of pixels. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### Colors The `color` prop paints the background of an avatar with initials or an icon: a theme token or any CSS color will do. **Example — `Colors.vue`:** ```vue ``` ### Badge The `badge` prop set to `true` shows a dot in the corner of the avatar. An object is passed through as props of CdsBadge: this is how you change the color of the dot, show a counter (`dot: false` plus `content`) or move the badge away from the edge (`floating`). The `badge` slot replaces the content of the badge with anything you like — an icon, for example. **Example — `Badge.vue`:** ```vue ``` ### Spacing The `start` and `end` props add a margin on the side of the neighboring content: `start` — for an avatar at the beginning of a line, `end` — at the end. This way the avatar fits into text without wrappers that carry outer margins. **Example — `Spacing.vue`:** ```vue ``` ### Slots | Slot | Description | | --------- | ---------------------------------------------------------- | | `default` | Avatar content. Replaces `image`, `icon` and `text` | | `badge` | Badge content. Shown instead of the dot when `badge` is on | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Initials are one or two letters: the first letters of the first and last name. | Long text does not fit into the round container and gets cut off. | | Inside one list keep avatars the same size — the row reads as a whole. | Different sizes read as different importance of the members. | | A colored dot shows the status — it is noticeable and does not fight the content. | A text badge covers the avatar; for a caption there is the line next to it. | ## Scenarios ### Member list In a list of people the avatar is a fast visual anchor. The `start` prop gives the margin before the text, photos and initials alternate depending on what the user has, and the badge dot shows who is online right now. **Example — `MembersList.vue`:** ```vue ``` ### Group of members When there are many members and little space, avatars are stacked with a slight overlap — a border in the background color separates the neighbors from each other. The last avatar with `text="+3"` tells how many people did not fit. **Example — `AvatarStack.vue`:** ```vue ``` ### Uploading a profile photo While there is no photo yet, the avatar shows the initials from `text` — the page is not left with an empty circle. As soon as `image` gets a link, the photo replaces the initials; after the photo is removed, the initials come back on their own. **Example — `ProfilePhoto.vue`:** ```vue ``` ## API ### CdsAvatar **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `badge` | `boolean \| CdsBadgeProps \| undefined` | `false` | no | Avatar badge. `true` shows a dot, an object is passed through as `CdsBadge` props. | | `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 | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `end` | `boolean \| undefined` | — | no | Adds a margin on the left — for an avatar at the end of a line of content. | | `icon` | `IconValue \| undefined` | — | no | Icon shown in the avatar when no image is set. | | `image` | `string \| undefined` | — | no | Source of the avatar image. Takes priority over `icon` and `text`. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `start` | `boolean \| undefined` | — | no | Adds a margin on the right — for an avatar at the beginning of a line of content. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | 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 | **Slots** | Name | Type | Description | | --- | --- | --- | | `badge` | `any` | Content of the avatar badge. | | `default` | `any` | Avatar content. Overrides `image`, `icon` and `text`. | --- # CdsBadge _Category: Feedback · since 4.0.0_ _Tests: API 26/26 · 38 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 7 axe recommendations (v4.0.0-alpha.11)_ A badge is a small marker in the corner of an element or next to it: a counter of unread messages, a "there is something new" dot, a short label. A badge is not interactive — it draws attention to the element it is attached to instead of acting on its own. **See also:** For a textual object status ("Done", "In progress") take CdsStatus, and CdsAvatar has a built-in `badge` prop for the common indicators on an avatar. ## Anatomy The badge attaches to the element from the `default` slot and is positioned relative to it. The content is a number or text from `content`, an icon from `icon`, or the markup from the `badge` slot. ## Variations ### Content The `content` prop sets what the badge shows — most often a counter of events. By default the badge sits in the top right corner of the element from the slot. **Example — `Default.vue`:** ```vue ``` The `max` prop caps the counter: anything above it collapses into "99+". Without `max` the value is printed in full. **Example — `WithMaxValue.vue`:** ```vue ``` Besides a number, `content` accepts a short text — a "new section" mark in a menu, for example. Here the badge is placed into the line by the `inline` prop — more on it in the positioning section. **Example — `StringContent.vue`:** ```vue ``` The `icon` prop shows an icon instead of text. **Example — `WithIcon.vue`:** ```vue ``` ### Dot The `dot` prop shrinks the badge to a dot and hides its content — only the "there is something new" signal is left. The diameter is changed via `dot-size`. **Example — `DotBadge.vue`:** ```vue ``` ### Colors The `color` prop accepts any color alias of the design system, `text-color` changes the color of the content. By default the badge is red — the color of indication. **Example — `CustomColors.vue`:** ```vue ``` ### Positioning By default the badge is positioned absolutely relative to the element from the slot. The `location` prop picks the corner. **Example — `Locations.vue`:** ```vue ``` The `floating` prop moves the badge 8 pixels away from the content, so it overlaps the element less. For fine-tuning there are `offset-x` and `offset-y`. **Example — `FloatingBadge.vue`:** ```vue ``` The `inline` prop puts the badge into the flow next to the content — as in the menu example above. `location`, `floating` and `offset-*` are ignored then. ### Visibility The `model-value` prop shows and hides the badge. The change of state is animated, and the animation is configured through `transition`. **Example — `ToggleVisibility.vue`:** ```vue ``` ### Slots | Slot | Description | | --------- | -------------------------------------------- | | `default` | The element the badge is attached to | | `badge` | Badge content. Replaces `content` and `icon` | **Example — `CustomBadgeSlot.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The max prop collapses large numbers, so the badge stays compact. | Точное «1528» не помогает принять решение и растягивает бейдж. | | A badge appears only where an update waits for the user to react. | A badge on every icon turns the signal into noise — nothing gets attention. | | The badge text is one short word. | A long phrase turns the indicator into a label and breaks the layout. | ## Scenarios ### Notification center A counter on the notifications icon: `max` keeps the badge compact for any number of events, and `model-value` hides it once nothing is unread — an empty "0" does not hang on the icon. **Example — `NotificationCenter.vue`:** ```vue ``` ### Menu with updates Counters in menu items hint where to look. A badge with `inline` goes into the `append` slot of a list item, and once the section is opened `model-value` removes it. Open "Входящие" — the counter disappears. **Example — `MenuUpdates.vue`:** ```vue ``` ### Contacts online A dot indicator shows the state without words: `color="green"` — the contact is online, `neutral` — not. `inline` puts the dot into the list row, and the `label` prop announces the state to screen readers. **Example — `ContactsOnline.vue`:** ```vue ``` ## API ### CdsBadge **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Component color | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `dot` | `boolean \| undefined` | — | no | Shrinks the component and hides its content, rendering it as a dot | | `dotSize` | `string \| number \| undefined` | — | no | Dot size | | `floating` | `boolean \| undefined` | — | no | Moves the component further away from the content — an 8 pixel offset. | | `height` | `string \| number \| undefined` | — | no | Component height | | `icon` | `IconValue \| undefined` | — | no | Icon shown inside the component. Ignored when the `dot` prop is set. | | `inline` | `boolean \| undefined` | — | no | Renders as an inline block instead of using absolute positioning. The location, floating and offset props are ignored. | | `label` | `string \| undefined` | `'$cds.badge'` | no | Aria-label for the component. Falls back to the default value when not set. | | `location` | `Anchor \| null \| undefined` | `'top end'` | no | Position of the element relative to its container, for example "top left", "center", "bottom right". | | `max` | `string \| number \| undefined` | — | no | Sets the maximum allowed value when content holds a number. If the number exceeds the maximum, a "+" suffix is added. | | `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` | `true` | no | Controls whether the component is shown or hidden. | | `offsetX` | `string \| number \| undefined` | — | no | Offset along the X axis | | `offsetY` | `string \| number \| undefined` | — | no | Offset along the Y axis | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | 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 | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'fade-transition'` | no | Transition animation | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `badge` | `any` | Slot for the content placed inside the badge. | | `default` | `any` | Default slot | --- # CdsBreadcrumbs _Category: Navigation · since 4.0.0_ _Tests: API 35/35 · 55 unit · 8 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 8 axe recommendations (v4.0.0-alpha.11)_ Breadcrumbs show the path to the current page in the hierarchy of sections and take you back to any level above in one click. The list is built from the `items` array or by hand — from `CdsBreadcrumbsItem` and `CdsBreadcrumbsDivider`. **See also:** To switch between sections of the same level, use CdsTabs; for a link styled as text inside a paragraph, use CdsLink; and to move through the steps of a process, use CdsSteps. ## Anatomy Breadcrumbs are a `ul` list where links to the levels of the hierarchy alternate with dividers. The last item marks the current page and is not clickable, and an icon can precede the list. ## Variations ### Items The `items` array builds the breadcrumbs automatically: a string turns into text, an object turns into a link with `href` or `to`. The component marks the last item as the current page itself: it disables the link and paints it in a neutral color. **Example — `Default.vue`:** ```vue ``` ### Divider By default the items are separated by `/`. The `divider` prop replaces the character, and the `divider` slot replaces the whole markup — with a chevron icon, for example. **Example — `Divider.vue`:** ```vue ``` ### Icon The `icon` prop renders an icon before the list — a sign of the root section, for example. The `prepend` slot replaces it with arbitrary content. **Example — `Icon.vue`:** ```vue ``` ### Slots Slots override parts of the list without giving up the automatic assembly from `items`. The `title`, `divider` and `item` slots receive `item` and `index`, so the content can be changed for every item separately. | Slot | Description | | --------- | ---------------------------------------------------------------- | | `prepend` | Content before the list. Replaces the icon from `icon` | | `title` | Item text — a shared template for all items | | `divider` | Divider content. Replaces the character from `divider` | | `item` | The whole item — your own markup instead of `CdsBreadcrumbsItem` | | `default` | Content after the items from `items`; used for manual assembly | **Example — `Slots.vue`:** ```vue ``` ### Manual assembly When the path is not described by a flat array — you need your own handlers or non-standard items — build the list in the `default` slot from `CdsBreadcrumbsItem` and `CdsBreadcrumbsDivider`. Mark the current page with `disabled`, and limit a long title with `max-width` — the text is truncated with an ellipsis. **Example — `Manual.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The last item is the current page: no link, neutral color. | The current page is styled as a link — clicking it leads nowhere and confuses the reader. | | Short level names — the path reads at a glance. | Full page titles stretch the path and wrap onto several lines. | | With a single level of nesting, a link back to the parent is enough. | Breadcrumbs of two items do not help you navigate and just take up space. | ## Scenarios ### Section navigation Breadcrumbs lead the user through the catalog tree: links in the list open deeper sections, a click on a crumb returns one level up. In an application with vue-router, pass `to` to the items instead of handlers — the navigation and the active state of the link work on their own. **Example — `Catalog.vue`:** ```vue ``` ### Long path Collapse a deep hierarchy down to the first level, an ellipsis and the last two steps — the path stays on a single line. A click on the ellipsis expands the full list. **Example — `LongPath.vue`:** ```vue ``` ## API ### CdsBreadcrumbs **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeClass` | `string \| undefined` | — | no | Class applied to the component when it is in the active state | | `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 | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `divider` | `string \| undefined` | `'/'` | no | Divider between the child components | | `icon` | `IconValue \| undefined` | — | no | Icon displayed next to the component | | `items` | `readonly BreadcrumbItem[] \| undefined` | `[]` | no | Array of strings or objects used to build the child components automatically | | `tag` | `string \| JSXComponent \| undefined` | `'ul'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content | | `divider` | `{ item: BreadcrumbItem; index: number; }` | Divider content between the items; can be overridden for each item | | `item` | `{ item: InternalBreadcrumbItem; index: number; }` | Item content; can be overridden for each item | | `prepend` | `any` | Content at the start | | `title` | `{ item: InternalBreadcrumbItem; index: number; }` | Content inside each item; can be overridden for each item | ### CdsBreadcrumbsDivider **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `divider` | `string \| number \| undefined` | — | no | Divider | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content | ### CdsBreadcrumbsItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state of the component; usually marks the current page in the navigation | | `activeClass` | `string \| undefined` | — | no | Class applied to the component when it is in the active state | | `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 | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `tag` | `string \| JSXComponent \| undefined` | `'li'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `title` | `string \| undefined` | — | no | Item title displayed in the component | | `to` | `LinkTo \| undefined` | — | no | Target route or route location object for RouterLink. When set, the component behaves as a RouterLink | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content | --- # CdsButton _Category: Content · since 4.0.0_ _Tests: API 37/38 · 59 unit · 2 e2e · 2 known bugs · lines 98% (v4.0.0-alpha.13) · a11y: 11 axe recommendations (v4.0.0-alpha.11)_ A button is the primary way to trigger an action: submit a form, open a modal, confirm a choice. Its variant (`variant`) and color (`color`) signal the role it plays: a filled `solid` button is the main action on the screen, `soft`, `outline` and `ghost` are the supporting ones. **See also:** For a link styled as text inside a paragraph, use CdsLink; to pick one option out of several, use CdsButtonToggle. ## Anatomy A button consists of a container and three content areas. Icons come from the `prepend-icon` / `append-icon` props or from the slots of the same name; while `loading` is on, the content is replaced by the indicator from the `loader` slot. ## Variations ### Variant The `variant` prop sets how the button is drawn. The default is `solid`. | Variant | Looks like | When | | --------- | --------------------------------- | ---------------------------------------- | | `solid` | filled with the color | the main action on the screen | | `soft` | a translucent tint of the color | a supporting action | | `outline` | a border, transparent background | a supporting action on a busy background | | `surface` | a border on a surface backdrop | an action over an image or a chart | | `ghost` | neither background nor border | an action inside a panel, table or toast | **Example — `Variants.vue`:** ```vue ``` ### Color The `color` prop sets the color in any variant. The default is `brand`. It accepts: - a role: `brand` — the brand color, `accent` — the accent button (the same as `brand` in the design system, a theme can repaint it), `neutral` — a neutral button, `danger` — an irreversible action, `inverse` — for dark backgrounds; - a palette alias: `red`, `green`, `cyan`, … `black`, `white`; - a theme token name: `status-success-surface`, `other-lime-fill`; - any CSS color: `#7c3aed`, `oklch(…)`. The state film builds hover, press and disabled for any color, so no per-color tokens are needed. **Example — `Colors.vue`:** ```vue ``` #### The deprecated `appearance` prop `appearance` still works and resolves into a `variant` + `color` pair, logging `[CDS UPGRADE]` to the development console once per value. Explicit `variant` and `color` take precedence over `appearance`. | `appearance` | `variant` | `color` | | ------------- | --------- | --------- | | `primary` | `solid` | `brand` | | `secondary` | `soft` | `brand` | | `tertiary` | `soft` | `neutral` | | `inverse` | `solid` | `inverse` | | `transparent` | `ghost` | `brand` | ### Sizes The `size` prop changes the height and the paddings of the button. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### Icons The `prepend-icon` and `append-icon` props add an icon before and after the text from `text`. **Example — `IconsAndContent.vue`:** ```vue ``` The `icon` prop turns the button into an icon button: the text is hidden and a square button with a single icon remains. **Example — `IconOnly.vue`:** ```vue ``` ### Layout The `block` prop stretches the button to the full width of its parent container. **Example — `Block.vue`:** ```vue ``` The `stacked` prop places the icon above the text. Such a button is twice as tall as a regular one of the same size, and its minimum width equals its height. **Example — `Stacked.vue`:** ```vue ``` The `spaced` prop pushes the `prepend` and `append` slots to the edges of the button. The value decides on which side of the content the free space appears: `start` moves the content towards `append`, `end` moves it towards `prepend`, `both` keeps it centered. The effect shows up only when the button is wider than its content, so `spaced` usually goes together with `block` or an explicit width. **Example — `Spaced.vue`:** ```vue ``` ### Slots Slots replace the content coming from props when you need full control over the markup. | Slot | Description | | --------- | -------------------------------------------------------------- | | `prepend` | Content before the text. Replaces the icon from `prepend-icon` | | `default` | Content inside the button. Replaces the text from `text` | | `append` | Content after the text. Replaces the icon from `append-icon` | | `loader` | Loading indicator. Shown instead of the content when `loading` | **Example — `Slots.vue`:** ```vue ``` ### Link button Pass `href` (or `to` with a `RouteLocationRaw` object from vue-router) and the button renders as an `a` tag with all the link attributes, keeping the look and the props of a button. **Example — `Link.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | One main action per screen is solid; everything else stays less prominent. | Several solid buttons compete for attention, and the main action gets lost. | | The label names the action and its outcome. | По «Да» и «ОК» не понятно, что именно произойдёт. | | Use an icon button only for widely understood actions: edit, copy, delete. | A rare operation is impossible to guess from an icon alone — give the button a label. | | Use the danger color for an irreversible action such as deleting or revoking access, next to a neutral cancel. | A red button used just for emphasis teaches people to ignore the warning. | ## Scenarios ### Submitting a form The filled button triggers the main action of the form. The `loading` prop shows the request in progress and guards against a double submit, while the neighboring `soft` button in the `neutral` color gives a way to back out. **Example — `FormActions.vue`:** ```vue ``` ### Action bar Repeating actions on a record — edit, duplicate, delete — fit nicely into a compact bar of icon buttons. The `icon` prop drops the text and `size="sm"` saves space. Do not forget `aria-label`: without text it stays the only name of the action. **Example — `Toolbar.vue`:** ```vue ``` ### Step navigation In wizards and multi-step forms the filled button moves forward and the `soft` one moves back. Chevron icons in `prepend-icon` and `append-icon` reinforce the direction, and `disabled` blocks moving past the first and the last step. **Example — `StepNavigation.vue`:** ```vue ``` ## API ### CdsButton **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Controls the active state of the component | | `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. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `height` | `string \| number \| undefined` | — | no | Component height | | `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` | — | no | CSS class applied in the selected state | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `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 | **Events** | Name | Type | Description | | --- | --- | --- | | `group:selected` | `[value: { value: boolean; }]` | Fires when the button is selected inside a group. `value` is a boolean that tells whether the button is now selected (true) or not (false). | **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 | **Exposed** | Name | Type | Description | | --- | --- | --- | | `group` | `GroupItemProvide \| null` | Returns the current group context when the button is used inside a group component (for example, CdsButtonGroup). | --- # CdsButtonGroup _Category: Content · since 4.0.0 · status: new_ _Tests: API 9/10 · 14 unit · lines 100% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ A button group joins several CdsButton into one block: the buttons sit flush against each other, only the outer corners stay rounded, and shared props are set once on the group. This is how you present sets of related actions — a toolbar over a record or zoom controls. **See also:** If the user does not trigger an action but picks one of several options, use CdsButtonToggle — it keeps the selected state. ## Variations The group passes the `variant`, `color`, `base-color` and `size` props down to every button inside — you do not need to repeat them on each button. A prop set on the button itself takes precedence over the group value. ### Variant and color `variant` and `color` set the look of every button in the group — from a filled `solid` for the main set of actions to `color="inverse"` for dark backgrounds. The deprecated `appearance` still works and resolves into the same pair as on CdsButton. **Example — `Appearances.vue`:** ```vue ``` ### Sizes `size` changes the height and padding of all buttons at once, so a group in a filter bar and a group in a table header stay consistent. **Example — `Sizes.vue`:** ```vue ``` ### Color `color` paints the button background with a palette alias. Use status colors when the whole group leads to one outcome — accept or reject. **Example — `Colors.vue`:** ```vue ``` ### Dividers and direction Without `divided` the buttons sit flush against each other; with it a line appears between them, so neighboring actions do not blend together. `direction="vertical"` turns the group into a column — for zoom controls on a map, for example. **Example — `Variations.vue`:** ```vue ``` ## API ### CdsButtonGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `appearance` _(deprecated)_ | `"inverse" \| "primary" \| "secondary" \| "tertiary" \| "transparent" \| undefined` | — | no | Visual appearance of the component. Deprecated: use `variant` and `color` | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `color` | `(string & {}) \| "neutral" \| "brand" \| "accent" \| "danger" \| "inverse" \| undefined` | `'brand'` | no | Component color: a role, a palette alias, a theme token or a CSS color | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `divided` | `boolean \| undefined` | — | no | Adds dividers between the buttons of the group. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `variant` | `"solid" \| "soft" \| "outline" \| "surface" \| "ghost" \| undefined` | `'solid'` | no | Component variant: `solid`, `soft`, `outline`, `surface`, `ghost` | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Buttons of the group. | --- # CdsButtonToggle _Category: Content · since 4.0.0 · status: new_ _Tests: API 19/24 · 24 unit · lines 100% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ A toggle group turns CdsButton into a switch: the pressed button stays selected, and the choice is available through `v-model`. Use it for modes and filters that are visible right away — the layout of a list, the period of a report, formatting options. **See also:** If the buttons trigger actions instead of storing a choice, take CdsButtonGroup. To pick from a long list use CdsSelect, and inside forms — CdsRadioGroup. ## Variations ### Selection By default a single button is selected, and clicking it again clears the choice. `v-model` receives the `value` of the button, or its index when no value is set. **Example — `Default.vue`:** ```vue ``` ### Multiple selection The `multiple` prop allows selecting several buttons — `v-model` becomes an array of values. **Example — `Multiple.vue`:** ```vue ``` The `max` prop limits the number of selected buttons: once the limit is reached, clicks on the remaining buttons add nothing to the selection. **Example — `Max.vue`:** ```vue ``` ### Mandatory selection The `mandatory` prop keeps the last choice from being cleared — the group always stays in some state. With the `'force'` value the first available button is selected automatically, even when `v-model` is empty. **Example — `Mandatory.vue`:** ```vue ``` ### Color of the active button The `active-color` prop repaints the selected buttons — the choice stands out on panels crowded with controls. **Example — `ActiveColor.vue`:** ```vue ``` ### Group props CdsButtonToggle is built on CdsButtonGroup and accepts all of its props: `variant` and `size` apply to every button at once, and the default variant is `soft`. `active-color` or `color` set the color of the selected button (`brand` by default), `base-color` the unselected ones (`neutral` by default); `divided` adds dividers, and `direction="vertical"` turns the group into a column. **Example — `Divided.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A toggle group keeps the choice: the mode or the filter stays pressed. | Actions run once and do not stay selected — those are plain buttons or a CdsButtonGroup. | | The screen is always in some mode — mandatory keeps the last choice from being cleared. | Without mandatory the choice can be cleared, and the mode of the screen becomes unclear. | | Labels are short and alike — the options read as one row of equals. | Long mismatched labels and a mix of text with icons break the row. | ## Scenarios ### View mode The classic toggle group — switching between a list and a grid. Icon buttons with `aria-label` save space, `mandatory` guarantees that the list is always shown in one of the modes, and the neutral default look with `size="sm"` keeps the control from stealing attention from the content. **Example — `ViewMode.vue`:** ```vue ``` ### Formatting toolbar Text styles are independent of each other, so the group works with `multiple`: each button turns its own style on and off, and `v-model` collects the selected values into an array. **Example — `TextFormatting.vue`:** ```vue ``` ### Period filter Give the buttons a `value` — and `v-model` returns a meaningful value to query the data with. `mandatory` keeps the user from ending up without a period: the numbers always belong to the selected range. **Example — `PeriodFilter.vue`:** ```vue ``` ## API ### CdsButtonToggle **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` | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `color` | `(string & {}) \| "neutral" \| "brand" \| "accent" \| "danger" \| "inverse" \| undefined` | `'brand'` | no | Component color: a role, a palette alias, a theme token or a CSS color | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `divided` | `boolean \| undefined` | — | no | Adds dividers between the buttons of the group. | | `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 | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `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` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `variant` | `"solid" \| "soft" \| "outline" \| "surface" \| "ghost" \| undefined` | `'soft'` | no | Buttons variant: `solid`, `soft`, `outline`, `surface`, `ghost` | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: unknown]` | Fires when the selected value changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsButtonToggleSlotProps` | Buttons of the toggle group. The slot props expose the state of the group (selection, navigation). | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isSelected` | `(id: string) => boolean` | Checks whether the button with this id is selected | | `next` | `() => void` | Selects the next button | | `prev` | `() => void` | Selects the previous button | | `select` | `(id: string, value: boolean) => void` | Selects a button by its id | | `selected` | `readonly string[]` | Ids of the selected buttons | --- # CdsCard _Category: Content · since 4.0.0_ _Tests: API 98/98 · 139 unit · 8 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 7 axe recommendations (v4.0.0-alpha.11)_ A card gathers related content — a title, text, an image, actions — into one bordered block. Use it when an object (a product, a plan, a document) should read as a whole: a card can act as a link and as a selectable item in a group. **See also:** For uniform lists of rows use CdsList, for collapsible sections use CdsExpandablePanel, and when you only need a surface without any structure, use CdsSurface. ## Anatomy A card is assembled from ready-made blocks. The first diagram shows the frame: header, divider, text and the actions bar. The second one shows how the `CdsCardItem` header works: the `prepend` and `append` areas at the edges, the title and the subtitle in the middle. Every block is available as a prop, as a slot and as a separate component. ## Variations ### Content There are three ways to fill a card: the `title`, `subtitle` and `text` props for typical cases; the slots of the same name when you need your own markup instead of a string; the `CdsCardItem`, `CdsCardTitle`, `CdsCardSubtitle` and `CdsCardText` components when you need full control over the structure. The `divider` prop adds a divider between the header and the text. **Example — `Default.vue`:** ```vue ``` | Slot | Description | | :---------------------------- | :------------------------------------------------------------------ | | `title` / `subtitle` / `text` | Replace the props of the same name | | `prepend` / `append` | Content at the edges of the header; replace `*-icon` and `*-avatar` | | `item` | Extra header content below the title | | `default` | Arbitrary card content | | `image` | Background image; replaces `image` | | `actions` | Actions bar — rendered inside `CdsCardActions` | | `loader` | Your own loading indicator while `loading` is on | ### Header The `prepend-icon` and `append-icon` props put an icon at the edges of the header, `prepend-avatar` and `append-avatar` put an avatar by image URL. By default the prepend and append areas are pinned to the top of the header; `item-align="center"` centers them against the title and the subtitle (on `CdsCardItem` this prop is called `align`). **Example — `HeaderMedia.vue`:** ```vue ``` ### Appearance A clickable card — one with a link, a click handler, inside a group or with the `link` prop — highlights its border on hover by itself, you do not need to turn anything on. `borderless` removes the border — for cards on a surface or inside other containers. **Example — `Appearance.vue`:** ```vue ``` ### Link Pass `href` (or `to` with a vue-router route) and the card is rendered as an `a` tag and becomes clickable as a whole, keeping its appearance. **Example — `Link.vue`:** ```vue ``` ### Images An image at the top is a CdsImage component placed first inside the card. You can overlay content on top of it by putting the header into the image slot. **Example — `Image.vue`:** ```vue ``` The `image` prop stretches the image as the background of the whole card. Take care of the contrast: set the text color through `color` and pick a dark image or a gradient. **Example — `BackgroundImage.vue`:** ```vue ``` ### Group with selection Wrap the cards in `CdsCardGroup` and give each of them a `value` — the group turns into a selection control with `v-model`, and the selected card gets a highlighted border. `required` forbids clearing the selection. **Example — `Group.vue`:** ```vue ``` The `multiple` prop enables multiple selection — `v-model` then holds an array of values. **Example — `Multiselectable.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A clickable card means one action: its whole area leads to the same result. | Buttons inside a clickable card compete with the click on the card itself. | | The actions bar holds one main action as primary; the rest are less prominent. | Several primary buttons in one card compete for attention. | | The subtitle adds a new fact to the title — a place, a date, a price. | A subtitle that repeats the title in other words tells the reader nothing. | ## Scenarios ### Choosing a plan A group of cards replaces radio buttons when every option needs room for a price and a description. The `check-fill` icon in `append-icon` repeats the selection in the header, and the button below stays disabled until an option is picked. **Example — `TariffPlans.vue`:** ```vue ``` ### Product cards A storefront is assembled from ready-made blocks: CdsImage with the photo, a rating made of icons in `CdsCardText`, CdsTag tags with the specs and a pair of actions in `CdsCardActions` — the main "add to cart" button and a secondary icon button for favorites that toggles the bookmark and tints it with a utility class. The `loading` and `disabled` props show the loading bar and protect the card from repeated clicks while the request runs — press «В корзину». **Example — `ProductCards.vue`:** ```vue ``` ### Expandable details Hide secondary content behind an expander: a block with `v-if` is wrapped in `CdsTransitionExpand` for a smooth animation. Anything can trigger the expansion — a chevron icon or a button in the actions bar. **Example — `Expanded.vue`:** ```vue ``` ### Gallery Cards nest into each other: the outer one is an album with a header and a counter, the inner ones are photo tiles in a mosaic built on a CSS grid with a fixed row height; `col-span` / `row-span` make individual shots larger. The `absolute` mode of CdsImage stretches the photo across the whole tile, `borderless` removes the borders, and a gradient darkens the last tile under the counter of the remaining photos. **Example — `Grid.vue`:** ```vue ``` ## API ### CdsCard **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendAvatar` | `string \| undefined` | — | no | Avatar shown after (to the right of) the content in the card header. | | `appendIcon` | `IconValue \| undefined` | — | no | Icon shown after (to the right of) the content in the card header. | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `borderless` | `boolean \| undefined` | — | no | Removes the border of the card | | `color` | `string \| undefined` | — | no | Component color | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `divider` | `boolean \| undefined` | — | no | Adds a divider between the header and the content | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `height` | `string \| number \| undefined` | — | no | Component height | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `image` | `string \| undefined` | — | no | URL of the background image of the card. | | `itemAlign` | `"start" \| "end" \| "center" \| undefined` | — | no | Alignment of the `prepend` / `append` areas against the header content. Passed to `CdsCardItem` as `align`. | | `link` | `boolean \| undefined` | — | no | Gives the card the styles and the behavior of a link. | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `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 | | `prependAvatar` | `string \| undefined` | — | no | Avatar shown before (to the left of) the content in the card header. | | `prependIcon` | `IconValue \| undefined` | — | no | Icon shown before (to the left of) the content in the card header. | | `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 | | `subtitle` | `string \| number \| boolean \| undefined` | — | no | Card subtitle. Rendered inside `CdsCardItem` below the title. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | 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 | | `title` | `string \| number \| boolean \| undefined` | — | no | Card title. Rendered inside `CdsCardItem` above the subtitle. | | `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 | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `any` | Actions bar of the card | | `append` | `any` | Content after the main content (in place of the append icon or avatar) | | `default` | `any` | Default content inside the card | | `image` | `any` | Background image of the card | | `item` | `any` | Custom rendering of the card item (CdsCardItem) | | `loader` | `LoaderSlotProps` | Slot for a custom loading indicator, shown while the `loading` prop is true. | | `prepend` | `any` | Content before the main content (in place of the prepend icon or avatar) | | `subtitle` | `any` | Subtitle content | | `text` | `any` | Main text content of the card | | `title` | `any` | Title content | ### CdsCardActions **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `align` | `"start" \| "end" \| "center" \| undefined` | `'start'` | no | Horizontal alignment of the action buttons | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Card actions, usually buttons | ### CdsCardDivider **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the divider. | | `contentOffset` | `string \| number \| (string \| number)[] \| undefined` | — | no | Increases the spacing between the content and the lines. When passed as an array, the second value shifts the slot content down (or right when vertical = true). | | `gradient` | `boolean \| undefined` | — | no | Adds a fade-out effect on both ends. | | `inset` | `boolean \| undefined` | — | no | Adds an indent to horizontal dividers and reduces the maximum height of vertical ones. | | `length` | `string \| number \| undefined` | — | no | Length of the divider. Defaults to pixels. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the divider. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `thickness` | `string \| number \| undefined` | — | no | Thickness of the divider. Defaults to pixels. | | `variant` | `"solid" \| "dotted" \| "dashed" \| "double" \| undefined` | `'solid'` | no | Visual variant of the divider | | `vertical` | `boolean \| undefined` | — | no | Renders the divider vertically | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the card divider | ### CdsCardGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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 | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `selectedClass` | `string \| undefined` | `'cds-card--selected'` | 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 | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `GroupProvide` | Cards of the group. The slot props expose the group state (selection, navigation). | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isSelected` | `(id: string) => boolean` | Checks whether a card with the given id is selected | | `next` | `() => void` | Selects the next card | | `prev` | `() => void` | Selects the previous card | | `select` | `(id: string, value: boolean) => void` | Selects a card by its id | | `selected` | `readonly string[]` | Identifiers of the selected cards | ### CdsCardItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `align` | `"start" \| "end" \| "center" \| undefined` | — | no | Alignment of the `prepend` / `append` areas against the content. | | `appendAvatar` | `string \| undefined` | — | no | Avatar shown after (to the right of) the content. | | `appendIcon` | `IconValue \| undefined` | — | no | Icon shown after (to the right of) the content. | | `prependAvatar` | `string \| undefined` | — | no | Avatar shown before (to the left of) the content. | | `prependIcon` | `IconValue \| undefined` | — | no | Icon shown before (to the left of) the content. | | `subtitle` | `string \| number \| boolean \| undefined` | — | no | Subtitle of the card item. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `title` | `string \| number \| boolean \| undefined` | — | no | Title of the card item. | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `any` | Content after the main content (in place of the append icon or avatar) | | `default` | `any` | Default content inside the body of the card item | | `prepend` | `any` | Content before the main content (in place of the prepend icon or avatar) | | `subtitle` | `any` | Subtitle content | | `title` | `any` | Title content | ### CdsCardSubtitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the subtitle text. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the card subtitle | ### CdsCardText **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the card text. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text content of the card | ### CdsCardTitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the card title | --- # CdsCarousel _Category: Content · since 4.0.0 · status: new_ _Tests: none yet — behavior is not covered by automated tests_ A carousel shows images or arbitrary content slide by slide: promo banners, photo galleries, onboarding steps. Arrows and delimiter dots give you navigation, autoplay flips the slides on its own, and the progress bar shows the current position. **See also:** To switch content without delimiters and autoplay, take CdsSlideView — the carousel is built on top of it; for a single image take CdsImage. ## Anatomy A carousel is made of slides, navigation arrows, delimiter dots and an optional progress bar. Arrows and dots loop around: the first slide follows the last one. ## Variations ### Images `CdsCarouselItem` combines a slide and CdsImage — pass it any image prop: `src`, `alt`, `cover`, `gradient`. The `height` prop sets the height of the carousel (500 by default). **Example — `Default.vue`:** ```vue ``` ### Custom content A slide does not have to be an image: put any markup into the slot of `CdsCarouselItem` and it stretches over the whole frame. **Example — `CustomContent.vue`:** ```vue ``` ### Autoplay The `cycle` prop flips the slides automatically, `interval` sets the pause in milliseconds (6000 by default). The timer restarts after a manual switch, so the reader always has time to finish looking at a slide. **Example — `Cycle.vue`:** ```vue ``` ### Progress The `progress` prop adds a position bar at the bottom of the carousel. A string value sets its color — any of the tokens that CdsProgressBar accepts. **Example — `Progress.vue`:** ```vue ``` ### Delimiters Props control the navigation dots: `hide-delimiters` removes them completely, `hide-delimiter-background` removes only the backdrop, `vertical-delimiters` (`left` / `right`) puts the dots vertically along the edge, and `delimiter-icon` changes the dot icon. **Example — `Delimiters.vue`:** ```vue ``` The `item` slot replaces a dot with your own element: it receives the ready-made delimiter props (click handler, `aria-label`, active class) and the group item itself — all that is left is to bind them with `v-bind`. **Example — `CustomDelimiters.vue`:** ```vue ``` ### Arrows The arrow props are inherited from CdsSlideView: `show-arrows="hover"` shows them on hover only, `:show-arrows="false"` removes them completely, `prev-icon` / `next-icon` change the icons, and the `prev` / `next` slots replace the buttons themselves. **Example — `Arrows.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Images with cover fill the whole slide — the carousel looks solid. | Without cover the image leaves empty margins, and the frame height jumps from slide to slide. | | Up to 5–7 slides: the dots stay readable and you can tell how many are left. | A dozen and a half slides blur into a strip of dots — nobody scrolls through to the important content. | | Text over an image sits on a gradient — it reads on any frame. | Text without a backdrop gets lost on a busy image. | ## Scenarios ### Promo banners The classic banner rotation: `cycle` with a 5 second `interval` flips the slides on its own, `progress` shows when the next one comes. The text and the button live in the slide slot, and the `gradient` from CdsImage darkens the top of the frame beneath them — so they stay readable on any image. **Example — `PromoBanners.vue`:** ```vue ``` ### Gallery with thumbnails The dots are replaced by thumbnails: `hide-delimiters` removes the built-in delimiters, and a click on a thumbnail changes `v-model`. The counter next to it reads the same `v-model` — the carousel, the thumbnails and the counter always stay in sync. **Example — `ProductGallery.vue`:** ```vue ``` ### Vertical feed A stories feed in the spirit of social networks: `direction="vertical"` flips the frames top to bottom, `vertical-arrows="left"` and `vertical-delimiters="right"` pull the arrows and the dots apart to the side edges and free up the frame. The author card and the counter sit in an absolute layer above the carousel: `pointer-events-none` lets clicks through to the arrows, and a transition keyed by `v-model` swaps the card together with the slide. **Example — `VerticalFeed.vue`:** ```vue ``` ### Onboarding Product introduction steps: the arrows are off (`:show-arrows="false"`), the movement is driven by the "Back" and "Next" buttons through `v-model`. On the last step "Next" turns into a call to action. **Example — `Onboarding.vue`:** ```vue ``` ## API ### CdsCarousel **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the active delimiter and of the progress bar | | `continuous` | `boolean \| undefined` | `true` | 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 | | `cycle` | `boolean \| undefined` | — | no | Flips the slides automatically after the given interval | | `delimiterIcon` | `IconValue \| undefined` | `'dot'` | no | Icon of the delimiter (navigation dot) | | `direction` | `"horizontal" \| "vertical" \| undefined` | `'horizontal'` | no | Switches the component between horizontal and vertical layout. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `height` | `string \| number \| undefined` | `500` | no | Height of the carousel | | `hideDelimiterBackground` | `boolean \| undefined` | — | no | Hides the backdrop under the delimiters | | `hideDelimiters` | `boolean \| undefined` | — | no | Hides the delimiters (navigation dots) | | `interval` | `string \| number \| undefined` | `6000` | no | Autoplay interval in milliseconds (when `cycle` is on) | | `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 | | `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 | | `progress` | `string \| boolean \| undefined` | — | no | Shows the progress bar of the current slide. A string sets the color of the bar | | `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` | `true` | 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 | | `verticalDelimiters` | `boolean \| "left" \| "right" \| undefined` | — | no | Vertical placement of the delimiters: `left`, `right` or `true` (left) | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[]` | Fires when the active slide changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ group: GroupProvide; }` | Slides. The slot props carry the group state for controlling the active slide | | `item` | `{ props: CarouselDelimiterProps; item: { id: string; value: unknown; disabled: boolean \| undefined; }; }` | Custom delimiter (navigation dot) for each 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 | ### CdsCarouselItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `absolute` | `boolean \| undefined` | — | no | Positions the image with `position: absolute`, filling its parent. | | `alt` | `string \| undefined` | — | no | Alternative text of the image (the `alt` attribute). | | `aspectRatio` | `string \| number \| undefined` | — | no | Aspect ratio of the content. For example `1.7778` (16/9) or `'4/3'`. | | `color` | `string \| undefined` | — | no | Background color of the placeholder shown while loading. | | `contentClass` | `any` | — | no | CSS class applied to the content wrapper. | | `cover` | `boolean \| undefined` | — | no | Scales the image so that it covers the whole container (`object-fit: cover`). | | `crossorigin` | `"" \| "anonymous" \| "use-credentials" \| undefined` | — | no | Value of the `crossorigin` attribute. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `draggable` | `boolean \| "true" \| "false" \| undefined` | — | no | Controls whether the image can be dragged (the `draggable` attribute). | | `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. | | `gradient` | `string \| undefined` | — | no | CSS gradient laid over the image. For example `'to top, rgba(0,0,0,.4), transparent'`. | | `height` | `string \| number \| undefined` | — | no | Component height | | `imageClass` | `any` | — | no | CSS class applied to the inner `` element. | | `inline` | `boolean \| undefined` | — | no | Renders the component as an inline block (`inline-flex`) instead of a block one. | | `lazySrc` | `string \| undefined` | — | no | Source of the low-quality placeholder image shown until the main one loads. | | `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 | | `options` | `IntersectionObserverInit \| undefined` | `{}` | no | `IntersectionObserver` options for lazy loading. | | `position` | `string \| undefined` | — | no | Value of `object-position` that places the image inside the container. | | `referrerpolicy` | `"origin" \| "no-referrer" \| "no-referrer-when-downgrade" \| "origin-when-cross-origin" \| "same-origin" \| "strict-origin" \| "strict-origin-when-cross-origin" \| "unsafe-url" \| undefined` | — | no | Value of the `referrerpolicy` attribute. | | `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 | | `sizes` | `string \| undefined` | — | no | Value of the `sizes` attribute for responsive images. | | `src` | `string \| CdsImageSrcObject \| undefined` | `''` | no | Image source. A string or an object with `src`/`srcset`/`lazySrc`/`aspect`. | | `srcset` | `string \| undefined` | — | no | Set of image sources for different resolutions (the `srcset` attribute). | | `theme` | `string \| undefined` | — | no | Component theme | | `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 | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content shown over the image. | | `error` | `any` | Content shown when the image fails to load. | | `placeholder` | `any` | Content shown while the image is loading. | | `sources` | `any` | Extra `` elements for the `` tag. | --- # CdsCheckbox _Category: Controls · since 4.0.0_ _Tests: API 65/65 · 63 unit · 5 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ A checkbox turns an independent option on and off: consent to terms, an entry in a filter list, a profile setting. Every checkbox in a group is selected on its own, which makes it right for multiple choice. **See also:** To pick one option out of several use CdsRadio, for settings that apply immediately — CdsToggle. If you need the control alone, without a label and messages — in a table cell, for example — take CdsCheckboxButton. ## Anatomy A checkbox is made of the control with the state icon, the label with its description and the messages block under them. A click on the label toggles the checkbox exactly like a click on the control. ## Variations ### Label and description The `label` prop names the option, `description` adds an explanation under the label. The slots of the same name accept arbitrary markup — a link to the terms, for example (see the "Consent in a form" scenario). **Example — `LabelAndDescription.vue`:** ```vue ``` ### States `disabled` blocks the checkbox and lowers the contrast, `readonly` forbids changes but does not change the appearance. **Example — `States.vue`:** ```vue ``` ### Indeterminate state The `indeterminate` prop shows an intermediate state — usually on a parent checkbox when only some of the nested entries are selected. This is a visual flag: it does not change the model value, and the icon is set by `indeterminate-icon`. A live example is in the "Select all" scenario. **Example — `Indeterminate.vue`:** ```vue ``` ### Sizes The `size` prop accepts values from `xs` to `xl`, `md` by default. The label and the description scale together with the control. **Example — `Sizes.vue`:** ```vue ``` ### Colors The `color` prop sets the color of a selected checkbox, `base-color` — the color of an unselected one. **Example — `Colors.vue`:** ```vue ``` ### Messages and errors `messages` shows a supporting text under the checkbox, `error-messages` — a ready error message (the one coming from the server, for example) together with the error state. Validation rules through `rules` are in the "Consent in a form" scenario. **Example — `Messages.vue`:** ```vue ``` ### Your own values By default the model keeps `true` or `false`. The `true-value` and `false-value` props replace them with your own values — handy when the API expects strings or codes. **Example — `TrueFalseValue.vue`:** ```vue ``` ### A group of checkboxes To build a group, pass the same array in `v-model` to all the checkboxes and give them unique `value`s — the selected values are collected into the array. `hide-details` removes the bottom block and the rows sit right next to each other; the common heading and description of the group are set by CdsLabel and CdsDescription. **Example — `Group.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Checkboxes are for independent options: each one can be turned on and off separately. | Checkboxes do not fit mutually exclusive options — use radio buttons. | | The label is phrased positively: a checked checkbox means the option is on. | A negation in the label makes the user guess what an unchecked box means. | | A short label names the option, the details go into the description. | In a long label the point of the option drowns in details. | ## Scenarios ### Select all The parent checkbox controls the group: a computed model checks and unchecks all the entries at once, and `indeterminate` turns on while only some of them are selected. **Example — `SelectAll.vue`:** ```vue ``` ### Consent in a form A required consent is a rule in `rules` that returns the error text while the checkbox is unchecked. The `label` slot adds a link to the terms into the label, and the button starts the check through the `validate()` of the CdsForm. **Example — `ConsentForm.vue`:** ```vue ``` ### Filtering a list A group of checkboxes with an array in `v-model` filters the list on the fly: a computed keeps the documents of the selected types, and an empty selection means "show everything". **Example — `FilterList.vue`:** ```vue ``` ## API ### CdsCheckbox **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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 | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `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` | `'checkbox-off'` | 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 checkbox. | | `indeterminateIcon` | `IconValue \| undefined` | `'checkbox-indeterminate-fill'` | no | Icon shown in the indeterminate state. | | `label` | `string \| undefined` | — | no | Label text of 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 | | `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 | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `trueIcon` | `IconValue \| undefined` | `'checkbox-on-fill'` | 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: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 | | `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 | **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 | --- # CdsCheckboxButton _Category: Controls · since 4.0.0 · status: new_ _Tests: API 33/33 · 17 unit · 5 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ The checkbox control without a label and a messages block — the atom CdsCheckbox is built on. Use it where the caption is not needed or lives outside: in a table cell, a list row, a card. **See also:** For a standalone option with a label, a description and validation use CdsCheckbox — states, colors and groups work the same way here and are described in detail on its page. ## Basic example The control is driven through `v-model`, `indeterminate` shows the intermediate state, `disabled` blocks the choice. There is no visible label, so add an `aria-label` — that way the control stays clear for screen readers. **Example — `Basic.vue`:** ```vue ``` ## API ### CdsCheckboxButton **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` | `'checkbox-off'` | no | Icon of the unselected state | | `falseValue` | `any` | — | no | Value for the false state. | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `indeterminate` | `boolean \| undefined` | — | no | Indeterminate state of the checkbox. | | `indeterminateIcon` | `IconValue \| undefined` | `'checkbox-indeterminate-fill'` | no | Icon shown in the indeterminate state. | | `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` | `'checkbox-on-fill'` | 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:indeterminate` | `[value: boolean]` | Fired when the indeterminate state of the checkbox changed | | `update:modelValue` | `[value: boolean]` | Fired when the checkbox was toggled. Passes the new state | **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 | --- # CdsCombobox _Category: Controls · since 4.0.0_ _Tests: API 130/130 · 118 unit · 8 e2e · 13 known bugs · lines 86.4% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ A combobox is a field with a dropdown list and free input: the value can be picked from the offered ones or typed in — the text itself becomes the value. The field is built on CdsTextInput, and the menu and the list are the same as in CdsSelect, so the label, the messages, validation and the menu behave identically. **See also:** If the value must come from the list only, take CdsAutocomplete. If there are few options and free input is not needed — CdsSelect. ## Anatomy The first diagram shows the frame of the component: the label, the description, the field and the messages block. The second one shows how the field itself is built: the zone of the selected value, the clear button and the menu indicator; the inner and outer icon zones are the same as in CdsTextInput. ## Variations The combobox repeats the variations of CdsSelect and CdsAutocomplete — grouping, "select all", filtering, auto-selecting the first item and menu settings. Below is what free input adds. ### List items The list is set by the `items` prop — an array of strings or of objects with the same interface as in CdsList. The input filters the list but does not have to match an item: the typed text goes into the model right away — there is no need to press Enter or to pick an item. **Example — `Default.vue`:** ```vue ``` ### Multiple selection and chips The `multiple` prop allows selecting several values, `chips` shows them as CdsTag tags, and `closable-chips` adds a cross — the value is removed right in the field. Your own value is added with the Enter key — like "Медиация" in the example, which is not in the list. The search query is cleared automatically after every selection (`clear-on-select` is on by default). **Example — `MultipleChips.vue`:** ```vue ``` ### Delimiters The `delimiters` prop sets the delimiter characters: typing or pasting a string containing them splits it into separate values. It works together with `multiple` only; a line break is always a delimiter, so a multiline list from the clipboard turns into a set of values even without any configuration. **Example — `Delimiters.vue`:** ```vue ``` ### Slots The menu and field slots are the same as in CdsSelect and CdsTextInput; for examples of `item`, `selection`, `chip` and the menu slots see the select page — in the combobox they work the same way. | 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 search result is empty | | `subheader` / `divider` | Group subheader and divider | | `menu-header` / `menu-footer` | Menu header and footer; receive `search` and `filteredItems` | Unlike in the autocomplete, `hide-no-data` is on by default: an empty result simply closes the menu, because the typed value is a valid outcome on its own. To show a placeholder or the `no-data` slot, pass `:hide-no-data="false"`. ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A combobox fits when custom values are allowed: labels, keywords, units of measurement. | A strict reference book does not tolerate free input: typos create duplicates. Take CdsAutocomplete. | | Tell the user that the field accepts custom values and how to add them. | A “Pick from the list” placeholder hides the main skill of a combobox — free input. | | Chips with a cross show the collected values and let any of them be removed in one click. | Without chips the values merge into one string, and only the last one can be removed — with the Backspace key. | ## Scenarios ### Recipients of a letter The combination of `multiple`, `chips` and `closable-chips` collects the recipients as tags, and `delimiters` splits a pasted list of addresses by commas and semicolons. `filter-keys` searches both by email and by name, `hide-selected` removes the already added ones from the list, and the `item` slot shows the avatar and the address. An address that is not in the reference book becomes a chip as is — external participants can be invited without being written into the contacts first. **Example — `Recipients.vue`:** ```vue ``` ### Growing the reference book The combobox extends the reference book gently: the user picks the usual values from the list and types the rare ones. The `@update:focused` handler adds the new value to `items` when the field is left — next time it will be found by search. Enter your own unit of measurement and click outside the field — the counter in the hint will grow. **Example — `Dictionary.vue`:** ```vue ``` ### Submitting a form The combobox takes part in CdsForm validation on a par with text fields: `rules` will not let the form through without a job title. Unlike in the autocomplete, it is exactly the typed text that is checked — the value goes into the model right away, picking a list item is not required. **Example — `FormSubmit.vue`:** ```vue ``` ## API ### CdsCombobox **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 | | `alwaysFilter` | `boolean \| undefined` | — | no | Filters the list even when the search query has not changed since the last selection. | | `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` | `'off'` | 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 | | `autoSelectFirst` | `boolean \| "exact" \| undefined` | — | no | Highlights the first matching item as you type; Enter or Tab select it. The `exact` value highlights it only on a full match of the search query with the item title. | | `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 | | `clearOnSelect` | `boolean \| undefined` | `true` | no | Clears the search query after an item is selected (relevant for `multiple`). | | `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 }` | | `delimiters` | `readonly string[] \| undefined` | — | no | Delimiter characters: typing or pasting a string containing them splits it into several values (for `multiple` only). | | `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` | `['title']` | 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` | `true` | 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 | | `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` | `true` | 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. | | `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` | `[value: 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. | | `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 search query has not changed since the last selection. | | `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 | | `search` | `string` | Current value of the search query. | | `selectAll` | `() => void` | Toggle the selection of all available items (for `multiple` + `isSelectAll` only). | | `selectionIndex` | `number` | Index of the selected value highlighted by the arrow keys during navigation. | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsCounter _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 6/6 · 12 unit · lines 100% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ The counter shows how many characters are already typed and how many are allowed: `42 / 100`. When the value exceeds the maximum, the counter turns red — the user sees the problem before submitting the form. **See also:** The ready-made fields already have the counter built in — turn on the `counter` prop of CdsTextInput or CdsTextArea. A standalone `CdsCounter` is needed when you build your own control. ## Variations ### Value and maximum The `value` prop sets the current number, `max` sets the limit. Without `max` the counter shows a single number, with `max` it shows a fraction. As soon as `value` is greater than `max`, the text turns red. **Example — `Values.vue`:** ```vue ``` ### Appearance The counter is visible only with `active` — by default it is hidden. Showing and hiding are animated, and the animation is set by the `transition` prop. **Example — `Active.vue`:** ```vue ``` ### Slot The `default` slot replaces the text of the counter and receives `value`, `max` and the ready `counter` string. **Example — `Slot.vue`:** ```vue ``` ## Scenarios ### Character limit of a field The `details` slot of an input is the place for a counter next to the messages. Count the length of the value yourself and pass it into `value`: when the text outgrows the limit, the counter turns red. **Example — `CharacterLimit.vue`:** ```vue ``` ## API ### CdsCounter **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `max` | `string \| number \| undefined` | — | no | Maximum value | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| { component: Component; } \| null \| undefined` | `{ component: slide-transition-y }` | no | Transition animation | | `value` | `string \| number \| undefined` | `0` | no | Value of the counter | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsCounterSlot` | Your own look for the counter. The slot props carry the ready counter string, the current and the maximum number of characters | --- # CdsDateInput _Category: Controls · since 4.0.0 · status: new_ _Tests: API 123/123 · 105 unit · 5 e2e · 9 known bugs · lines 95.7% (v4.0.0-alpha.13) · a11y: 16 axe recommendations (v4.0.0-alpha.11)_ A date field: a text field with a calendar icon that opens CdsDatePicker in a dropdown menu on click. The date can be picked with the mouse or typed on the keyboard — the value arrives as a string in the `mask` format (`DD.MM.YYYY` by default). **See also:** If the calendar is needed right on the page, without a field, take CdsDatePicker. For the time alone — CdsTimePicker, to pick from a ready list — CdsSelect. ## Anatomy The field is built on CdsTextInput, so the label, the description, the messages, clearing and validation work the same way. The calendar icon takes the `prepend-inner` zone and opens the menu — just like a click on the field itself. ## Variations ### Value and format The date arrives in `v-model` as a string in the `mask` format. By default the placeholder shows the mask itself, so there is no need to state the format separately. **Example — `Default.vue`:** ```vue ``` `display-format` changes only what the user sees: the model still keeps a string in `mask`. It accepts a mask (`D MMMM YYYY`) or a function receiving the native `Date`. If the date has to be stored differently — in ISO, for example — change `mask`: it defines both the storage and the parsing of the manual input. **Example — `DisplayFormat.vue`:** ```vue ``` ### Date and time `with-time` adds a CdsTimePicker under the calendar and appends the time to the mask: `DD.MM.YYYY` turns into `DD.MM.YYYY HH:mm` (`with-seconds` — into `DD.MM.YYYY HH:mm:ss`). The value stays a single string, and the calendar and the clock change their own parts of it. The time picker settings are available right on the field — `now-btn`, `format12h`, `allowed-hours`, `allowed-minutes` — or as a whole through `time-picker-props`. With the time on, the menu does not close on a click on a date: the user is still picking the hours. If you need an explicit finish, add `:hide-actions="false"` — the buttons will stand under the time picker. **Example — `WithTime.vue`:** ```vue ``` ### Several dates and a range `multiple` allows marking several dates — the model becomes an array of strings. `range` switches the calendar to picking a period: the value arrives as a `{ from, to }` object, and the menu stays open until both bounds are chosen. A set of dates and a range have no common time, so `with-time` does not work with them. **Example — `MultipleAndRange.vue`:** ```vue ``` ### Confirmation buttons By default the chosen date is applied at once and the menu closes. Pass `:hide-actions="false"` — and the choice becomes a draft: it gets into the model only after the "OK" button, while "Cancel" restores the previous value. The component emits `save` and `cancel`. **Example — `Actions.vue`:** ```vue ``` The `actions` slot replaces the pair of buttons with your own: it receives `save`, `cancel` and `isPristine` — the flag telling that nothing was changed in the calendar. **Example — `CustomActions.vue`:** ```vue ``` ### Manual input `update-on` sets the moment the typed value is parsed and gets into the model: by default these are `blur` and `enter`. A string that cannot be parsed by `mask` (or by a string `display-format`) is ignored — the field restores the previous value. An empty array forbids keyboard input and leaves the calendar only. The component does not impose an input mask — add one with a directive, using the lightweight (2.5 KB) [Maska](https://github.com/beholdr/maska) library, for example. **Example — `ManualInput.vue`:** ```vue ``` ### Date restrictions The calendar props are available right on the field: `allowed-dates` leaves only the needed days available, `min-year-month` and `max-year-month` do not let the navigation go beyond the range. **Example — `AllowedDates.vue`:** ```vue ``` ### States `disabled` blocks both the field and the calendar, `readonly` forbids changes but keeps focus and copying, `error-messages` shows an error under the field. **Example — `States.vue`:** ```vue ``` ### The calendar and the menu `picker-props` passes settings to the calendar — a header with the summary of the choice, for example, and `menu-props` and `location` control the dropdown menu. **Example — `PickerAndMenu.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Unavailable dates are turned off through allowed-dates — a past day cannot be picked. | Any day can be picked, and the user learns about the restriction from an error only after submitting the form. | | One period in one field: the bounds are visible side by side and are edited together. | Two separate fields let the end be set before the start — that has to be checked by hand. | | The input mask is hinted in the placeholder, and the field accepts both the keyboard and the calendar. | Manual input is turned off for no reason: a date from an email has to be hunted for in the calendar by clicking. | ## Scenarios ### A reporting period The period lives in one field: `range` gives `{ from, to }`, `:hide-actions="false"` turns the choice into a draft, and the preset buttons write into the same model — the calendar picks their value up. **Example — `ReportPeriod.vue`:** ```vue ``` ### A delivery date The restrictions work together: `allowed-dates` leaves only the weekdays, `min-year-month` and `max-year-month` — the nearest two months. Manual input is turned off here on purpose: an unavailable day cannot be typed in, and `display-format` shows the date in words. **Example — `DeliveryDate.vue`:** ```vue ``` ### A date in a form The field takes part in CdsForm on a par with the others: `rules` receive the same string value that lies in the model, so a "not in the past" check is a plain function. Limiting the navigation through `min-year-month` backs the rule up rather than replaces it. **Example — `BookingForm.vue`:** ```vue ``` ## API ### CdsDateInput **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 | | `allowedDates` | `TCalendarAllowedDates \| undefined` | — | no | Array of dates available in the calendar. When a function is used, it receives the date in the YYYY/MM/DD format and must return true or false. | | `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. | | `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 | | `defaultDate` | `string \| undefined` | — | no | Date used by default when the model is empty (in the YYYY/MM/DD format). | | `defaultYearMonth` | `string \| undefined` | — | no | Displayed year/month in the YYYY/MM format. The current year/month by default when v-model is not set. | | `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 | | `displayFormat` | `string \| ((date: Date) => string) \| undefined` | — | no | Display format of the date in the field. A mask (`'D MMMM YYYY'`) or a function receiving the native `Date` and returning a string. By default the value is shown as is — in the `mask` format. | | `emitImmediately` | `boolean \| undefined` | — | no | Emit the update:modelValue event right when the month or the year changes. Not available with multiple and range. | | `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. | | `events` | `TCalendarEvents \| undefined` | — | no | List of events shown in the calendar. Format: YYYY/MM/DD. | | `eventsColor` | `TCalendarEventsColor \| undefined` | `'default'` | no | Color of the events in the calendar. | | `firstDayOfWeek` | `string \| number \| undefined` | `1` | no | First day of the week (Monday by default). | | `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. | | `format12h` | `boolean \| undefined` | — | no | Shows the time in the 12-hour AM/PM format. | | `header` | `boolean \| undefined` | — | no | Show the calendar header | | `hideActions` | `boolean \| undefined` | `true` | no | Hide the confirmation buttons under the calendar — the chosen date is applied immediately. | | `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 | | `hideSiblingMonth` | `boolean \| undefined` | — | no | Hide the days of the neighboring months in the calendar. | | `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 | | `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`. | | `location` | `Anchor \| undefined` | `'bottom start'` | no | Position of the dropdown calendar relative to the field. | | `mask` | `string \| undefined` | `'DD.MM.YYYY'` | no | Date/time format | | `maxErrors` | `string \| number \| undefined` | `1` | no | Maximum number of validation errors shown | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `maxYearMonth` | `string \| undefined` | — | no | Forbid navigating the calendar past the given maximum date in the YYYY/MM format. | | `menu` | `boolean \| undefined` | — | no | State of the dropdown calendar (v-model:menu). | | `menuProps` | `CdsMenuProps \| undefined` | — | no | Props passed through to the CdsMenu component of the dropdown calendar. | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `minYearMonth` | `string \| undefined` | — | no | Forbid navigating the calendar before the given minimum date in the YYYY/MM format. | | `modelModifiers` | `Record \| undefined` | — | no | v-model modifiers passed by Vue to process the field value | | `modelValue` | `TDateInputValue \| undefined` | `null` | no | Value of the field: a string in the `mask` format, a `{ from, to }` range object or an array of them with `multiple`/`range`. | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several dates. The v-model must be an array. | | `name` | `string \| undefined` | — | no | Name of the input | | `noUnset` | `boolean \| undefined` | — | no | Forbid resetting the date in the calendar. | | `nowBtn` | `boolean \| undefined` | — | no | Shows the "Now" button. | | `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 | | `pickerProps` | `CdsDatePickerProps \| undefined` | — | no | Props passed through to the CdsDatePicker component. They win over the props of the field with the same name. | | `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` | `'calendar'` | no | Icon in the inner prepend slot, before the content of the field | | `range` | `boolean \| undefined` | — | no | Allows selecting a range of dates. The v-model must be an array. | | `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 | | `timePickerProps` | `CdsTimePickerProps \| undefined` | — | no | Props passed through to the CdsTimePicker component. They win over the props of the field with the same name. | | `todayBtn` | `boolean \| undefined` | — | no | Show the "Today" button in the calendar header | | `type` | `string \| undefined` | `'text'` | no | Type of the native input | | `updateOn` | `("enter" \| "blur")[] \| undefined` | `['blur', 'enter']` | no | Events that apply the manually entered value. An empty array forbids manual input — the field becomes read-only. | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `view` | `"Calendar" \| "Years" \| "Months" \| undefined` | `'Calendar'` | no | Default calendar view. Possible values: 'Calendar', 'Years', 'Months'. | | `width` | `string \| number \| undefined` | — | no | Component width | | `withSeconds` | `boolean \| undefined` | — | no | Adds seconds to the time selection. | | `withTime` | `boolean \| undefined` | — | no | Adds a time selection (CdsTimePicker) under the calendar and appends the time to the mask. Works for a single date only — ignored with `multiple` and `range`. | **Events** | Name | Type | Description | | --- | --- | --- | | `cancel` | `[]` | The selection was cancelled by the cancel button. | | `navigation` | `[payload: { year: number \| undefined; month: number \| undefined; }]` | Navigation to another month or year in the calendar. | | `rangeEnd` | `[payload: { from: Partial; to: Partial; }]` | End of a date range selection. | | `rangeStart` | `[value: Partial]` | Start of a date range selection. | | `save` | `[value: TDateInputValue]` | The value was confirmed — by a selection in the calendar or by the save button. | | `update:focused` | `[focused: boolean]` | The focus state of the field changed (v-model:focused). | | `update:menu` | `[value: boolean]` | The state of the dropdown calendar changed (v-model:menu). | | `update:modelValue` | `[value: TDateInputValue]` | The value of the field changed (v-model). | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `CdsDateInputActionsSlot` | Confirmation buttons under the calendar (relevant with `hide-actions="false"`). | | `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). | | `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 | | `picker-description` | `{ year: string \| number \| undefined; }` | Description in the calendar header. | | `picker-title` | `{ date: string; }` | Title in the calendar header. | | `prepend` | `CdsInputSlot` | Adds an element before the input | | `prepend-inner` | `CdsInputDefaultSlot` | Slot added at the start of the input | **Exposed** | Name | Type | Description | | --- | --- | --- | | `cancel` | `() => void` | Cancels the selection, restores the previous value and closes the popup. | | `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 | | `save` | `() => void` | Confirms the date chosen in the calendar and closes the popup. | | `validate` | `(silent?: boolean) => Promise` | Validates the input | --- # CdsDatePicker _Category: Controls · since 4.0.0_ _Tests: API 35/35 · 79 unit · 2 e2e · 14 known bugs · lines 94.6% (v4.0.0-alpha.13) · a11y: 32 axe recommendations (v4.0.0-alpha.11)_ A calendar for picking a date — a single one, several or a range. It lives right on the page or in a dropdown menu next to a field; the value is a string in the given format (`DD.MM.YYYY` by default), which is convenient to store and to send to the server. **See also:** If the calendar needs a field, take the ready CdsDateInput — it assembles the very same thing out of a field, a menu and this calendar, adding manual input and time. For picking the time alone there is CdsTimePicker. ## Anatomy The calendar consists of an optional header with the summary of the choice, the month and year navigation, the grid of days and the actions zone. The header is turned on by `header`, the "Today" button — by `today-btn`, and the actions are added into the default slot. ## Variations ### Value and format The chosen date arrives in `v-model` as a string in the `mask` format — `DD.MM.YYYY` by default. A repeated click on the selected day clears the selection; `no-unset` forbids such a reset, and `hide-sibling-month` hides the days of the neighboring months. **Example — `Default.vue`:** ```vue ``` ### Header `header` turns on the header with the summary of the choice: the title shows the date or the number of the chosen days, the description — the year. The texts are replaced by the `title` and `description` props or by the slots of the same name. `today-btn` adds a button that brings you back to the current day. **Example — `Header.vue`:** ```vue ``` ### A date range `range` switches the calendar to picking a period: the first click fixes the start (the `range-start` event), the second one — the end (`range-end`), and the value arrives as a `{ from, to }` object. Together with `multiple` several periods can be picked. **Example — `Range.vue`:** ```vue ``` ### Several dates `multiple` allows marking individual dates — the model becomes an array of strings. **Example — `Multiple.vue`:** ```vue ``` ### Events `events` marks dates with dots: it accepts an array of dates in the `YYYY/MM/DD` format or a predicate function. The color of a dot is set by `events-color` — as a string or as a function of the date, when there are several types of events. **Example — `Events.vue`:** ```vue ``` ### Available dates `allowed-dates` limits the choice: an array of dates or a function that receives a `YYYY/MM/DD` date and returns whether it can be picked. The rest of the days are turned off. **Example — `AllowedDates.vue`:** ```vue ``` ### Navigation bounds `min-year-month` and `max-year-month` (the `YYYY/MM` format) do not let you go beyond the range — the arrows at the bound are turned off. Watch the moves between months through the `navigation` event. **Example — `LimitedNavigation.vue`:** ```vue ``` ### Starting view `view` opens the calendar right at the list of months (`Months`) or years (`Years`) — handy for dates far from the current one. `default-year-month` sets the starting month when the model is empty. **Example — `DefaultView.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 used. `first-day-of-week` sets the first day of the week — for `en` it is usually Sunday. **Example — `Localization.vue`:** ```vue ``` ### States `disabled` turns the calendar off and dims it, `readonly` keeps the usual look but blocks both the selection and the navigation. **Example — `DisabledReadonly.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Unavailable days are turned off through allowed-dates — a wrong choice is impossible. | Every day looks available, and the user learns that weekends do not fit from an error only after the choice. | | Turn the header on when picking a range — it shows the whole chosen period. | Without the header the result of the choice is captioned nowhere: the user counts the days by the highlight. | | Only meaningful dates are marked with events — the dots are noticeable and guide the eye. | An event on every day turns the marks into noise: the calendar stops telling anything. | ## Scenarios ### A field with a date Most often the calendar lives not on the page but in a menu next to a text field. CdsDateInput exists for that — it is already assembled out of a field, a menu and the calendar, it parses the manual input and accepts all the calendar props directly. Build the control yourself only if you need a non-standard scheme: out of CdsTextInput, a CdsMenu with `activator="parent"` and the calendar — that way all the props and slots of the field and the menu stay available to you. In that case add the input mask yourself: we recommend the lightweight (2.5 KB) [Maska](https://github.com/beholdr/maska) library. **Example — `WithTextInputField.vue`:** ```vue ``` ### A reporting period The default slot adds actions under the calendar. Here the chosen range is a draft: it gets into the report only after the "Apply" button, while "Reset" returns the calendar to its initial state. **Example — `ReportPeriod.vue`:** ```vue ``` ### A delivery date The restrictions work together: `allowed-dates` leaves only the weekdays, and `min-year-month` and `max-year-month` do not let you go beyond the nearest two months — the unavailable options do not even have to be explained. **Example — `DeliveryDate.vue`:** ```vue ``` ### Date and time The calendar does not pick the time — put a CdsTimePicker next to it 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 the very same thing is turned on by a single prop — `with-time` on CdsDateInput. **Example — `DateAndTime.vue`:** ```vue ``` ## API ### CdsDatePicker **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `allowedDates` | `TCalendarAllowedDates \| undefined` | — | no | Array of dates available in the calendar. When a function is used, it receives the date in the YYYY/MM/DD format and must return true or false. | | `defaultYearMonth` | `string \| undefined` | — | no | Displayed year/month in the YYYY/MM format. The current year/month by default when v-model is not set. | | `description` | `string \| undefined` | — | no | Description of the calendar. Shown in the calendar header. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `emitImmediately` | `boolean \| undefined` | — | no | Emit the update:modelValue event right when the month or the year changes. Not available with multiple and range. | | `events` | `TCalendarEvents \| undefined` | — | no | List of events shown in the calendar. Format: YYYY/MM/DD. | | `eventsColor` | `TCalendarEventsColor \| undefined` | `'default'` | no | Color of the events in the calendar. | | `firstDayOfWeek` | `string \| number \| undefined` | `1` | no | First day of the week (Monday by default). | | `header` | `boolean \| undefined` | — | no | Show the calendar header | | `hideSiblingMonth` | `boolean \| undefined` | — | no | Hide the days of the neighboring months in the calendar. | | `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` | `'DD.MM.YYYY'` | no | Date/time format | | `maxYearMonth` | `string \| undefined` | — | no | Forbid navigating the calendar past the given maximum date in the YYYY/MM format. | | `minYearMonth` | `string \| undefined` | — | no | Forbid navigating the calendar before the given minimum date in the YYYY/MM format. | | `modelValue` | `string \| TDatetimeValueRange \| (string \| TDatetimeValueRange)[] \| null \| undefined` | `null` | no | Value of the model | | `multiple` | `boolean \| undefined` | — | no | Allows selecting several dates. The v-model must be an array. | | `noUnset` | `boolean \| undefined` | — | no | Forbid resetting the date in the calendar. | | `range` | `boolean \| undefined` | — | no | Allows selecting a range of dates. The v-model must be an array. | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `theme` | `string \| undefined` | — | no | Component theme | | `title` | `string \| undefined` | — | no | Title of the calendar. Shown in the calendar header. | | `todayBtn` | `boolean \| undefined` | — | no | Show the "Today" button in the calendar header | | `view` | `"Calendar" \| "Years" \| "Months" \| undefined` | `'Calendar'` | no | Default calendar view. Possible values: 'Calendar', 'Years', 'Months'. | **Events** | Name | Type | Description | | --- | --- | --- | | `navigation` | `[payload: { year: number \| undefined; month: number \| undefined; }]` | Navigation to another month or year (also fires when the model is changed from outside). | | `rangeEnd` | `[payload: { from: Partial; to: Partial; }]` | End of a date range selection. | | `rangeStart` | `[value: Partial]` | Start of a date range selection. | | `update:modelValue` | `[value: string \| TDatetimeValueRange \| (string \| TDatetimeValueRange)[] \| null, reason: string, details: Partial]` | The value changed (v-model). Passes the value, the reason of the change and the details of the date. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Additional buttons under the calendar. | | `description` | `{ year: string \| number \| undefined; }` | Description of the title. | | `title` | `{ date: string; }` | Title of the calendar. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `offsetCalendar` | `(type: "year" \| "month", descending: number) => void` | Moves the calendar one step forward or backward by months or by years. | | `setCalendarTo` | `(year: number, month: number) => void` | Scrolls the calendar to the given year and month without changing the selected value. | | `setEditingRange` | `(from: IRawDate, to: IRawDate) => void` | Sets the highlighted date range in `range` mode without confirming the selection. | | `setToday` | `() => void` | Selects today's date and scrolls the calendar to the current month. | | `setView` | `(viewMode: "Calendar" \| "Years" \| "Months") => void` | Switches the calendar view: days, months or years. | --- # CdsDefaultsProvider _Category: Other_ _Tests: API 6/6 · 13 unit · 2 known bugs · lines 100% (v4.0.0-alpha.13)_ ## API ### CdsDefaultsProvider **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `defaults` | `DefaultsOptions` | — | no | Значения пропсов по умолчанию для компонентов внутри — объект вида `{ CdsButton: { size: 'small' } }` | | `disabled` | `boolean \| undefined` | — | no | Отключает провайдер: вложенные компоненты используют значения из внешнего контекста | | `reset` | `string \| number \| undefined` | — | no | Сколько уровней вложенных провайдеров сбросить перед применением своих значений | | `root` | `string \| boolean \| undefined` | — | no | Применяет значения к корневому уровню приложения. Строка — имя корневого набора значений | | `scoped` | `boolean \| undefined` | — | no | Не наследовать значения внешних провайдеров — использовать только собственный `defaults` | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default slot | --- # CdsDescription _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 4/4 · 8 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ A description is muted text under the label of a field. It clarifies what to enter and in what format, so the label can stay short. **See also:** Inputs already have the description built in — the `description` prop of CdsTextInput and the other controls. A standalone `CdsDescription` is needed for groups of fields and for your own controls. For the label of a field take CdsLabel, for the messages under a field take CdsMessages. ## Variations ### Text The `text` prop sets the content. The `default` slot adds arbitrary markup to it — a highlighted input format, for example. **Example — `Text.vue`:** ```vue ``` ### Tag By default the description renders as a `div` tag. The `tag` prop changes the tag — to `p`, for example, when the description lives inside the text of the page. **Example — `Tag.vue`:** ```vue ``` ## Scenarios ### An explanation for a group of fields A group of checkboxes has no `description` of its own, so the label and the explanation are assembled by hand: `CdsLabel` names the group, `CdsDescription` explains what to pick. **Example — `FieldsetHint.vue`:** ```vue ``` ## API ### CdsDescription **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text of the description | --- # CdsDivider _Category: Atoms · since 4.0.0_ _Tests: API 11/11 · 24 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A divider is a thin line between the meaningful parts of an interface: the sections of a form, the rows of a list, the blocks of a card. It does nothing and asks for no attention, it only shows the border where the paddings are no longer enough. A short caption can go into its slot — "or" between two ways of doing something, for example. **See also:** The blocks of a card are separated by the `divider` prop of CdsCard — it draws the same line without adding markup. If the parts of the screen need to be moved onto different surfaces rather than separated, take CdsSurface. ## Variations ### Appearance The `variant` prop sets the style of the line: `solid` by default, while `dashed`, `dotted` and `double` mark the border as temporary or technical. **Example — `Variants.vue`:** ```vue ``` ### Thickness and length The `thickness` prop sets the thickness of the line in pixels, `length` sets its length. Without `length` the divider takes the whole width of its parent (or its whole height when the divider is vertical). **Example — `Thickness.vue`:** ```vue ``` **Example — `Length.vue`:** ```vue ``` ### Color and opacity The `color` prop accepts a color alias (`green`, `red`, `purple`) or a design system token, `opacity` accepts a value from 0 to 1. Color is appropriate when the line carries meaning: the border of an overdue period, a gap in the history of events. **Example — `Colors.vue`:** ```vue ``` ### Inset The `inset` prop shifts a horizontal divider 72 px from the start of the row — so the line starts under the text rather than under the icon or the avatar. On a vertical divider `inset` shortens the line from the top and the bottom. **Example — `Inset.vue`:** ```vue ``` ### Fading The `gradient` prop dissolves the line towards its edges. Such a divider is softer than the regular one and looks good inside dense blocks where a sharp border would read as a frame. **Example — `Gradient.vue`:** ```vue ``` ### Orientation The `vertical` prop turns the divider. A vertical line stretches to the height of its neighbors, so its parent needs a height — usually a `display: flex` row. **Example — `Vertical.vue`:** ```vue ``` ### Content The content of the `default` slot stands in the break of the line: the divider turns into a caption of the border — "or", a date, the name of a section. **Example — `Content.vue`:** ```vue ``` The `content-offset` prop increases the distance from the content to the line. An array of two values additionally shifts the content itself: downwards on a horizontal divider, to the right on a vertical one. **Example — `ContentOffset.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A divider sets the meaningful groups apart: the details separately, the contacts separately. | A line after every row creates noise and does not help reading the list. | | A caption in a divider is one or two words: it names the border instead of explaining it. | A long phrase breaks the line and pulls the attention onto itself. | | A thin neutral line: the border is visible and the attention stays on the content. | A thick colored divider reads as an interface element in its own right. | ## Scenarios ### An alternative way to sign in A divider with the "or" caption sets two equal paths apart and explains that the second one is not a continuation of the first. `content-offset` gives the caption some air so it does not blend with the buttons. **Example — `AuthOptions.vue`:** ```vue ``` ### Rows of a list Between the rows of a list a divider replaces the frames: the borders are visible, but the list does not turn into a table. The line goes between the items rather than after each one — the first and the last row do not have it. **Example — `DocumentList.vue`:** ```vue ``` ### Metadata of a record Vertical dividers break up a row of facts — status, date, author — taking almost no space. A `display: flex` and a height are enough for the parent row to make the lines stretch along the text. **Example — `RecordMeta.vue`:** ```vue ``` ### Sections of a form A divider with a caption in the slot names a new group of fields. It is calmer than a heading: the rest of the form reads as a continuation rather than as the start of another form. **Example — `FormSections.vue`:** ```vue ``` ## API ### CdsDivider **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the divider. | | `contentOffset` | `string \| number \| (string \| number)[] \| undefined` | — | no | Increases the spacing between the content and the lines. When passed as an array, the second value shifts the slot content down (or right when vertical = true). | | `gradient` | `boolean \| undefined` | — | no | Adds a fade-out effect on both ends. | | `inset` | `boolean \| undefined` | — | no | Adds an indent to horizontal dividers and reduces the maximum height of vertical ones. | | `length` | `string \| number \| undefined` | — | no | Length of the divider. Defaults to pixels. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the divider. | | `theme` | `string \| undefined` | — | no | Component theme | | `thickness` | `string \| number \| undefined` | — | no | Thickness of the divider. Defaults to pixels. | | `variant` | `"solid" \| "dotted" \| "dashed" \| "double" \| undefined` | `'solid'` | no | Visual variant of the divider | | `vertical` | `boolean \| undefined` | — | no | Renders the divider vertically | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text or content placed in the gap of the divider | --- # CdsDrawer _Category: Layouts · since 4.0.0_ _Tests: API 33/33 · 76 unit · 3 e2e · 3 known bugs · lines 93.1% (v4.0.0-alpha.13) · a11y: 14 axe recommendations (v4.0.0-alpha.11)_ The side panel of the application: navigation sections on the left, the context of a record or filters on the right. Inside `CdsLayout` the drawer takes its place in the layout and pushes the content aside, and in temporary mode it slides out over it. **See also:** For a list of sections inside the drawer take CdsList; for navigating the subsections of a single page take CdsTabs. The drawer is a part of the CdsLayout frame, but unlike the other parts it also works on its own: with the `fixed` prop it sticks to the window without a layout. ## Anatomy The drawer consists of a scrollable navigation list and two pinned areas: `prepend` on top — for a logo or a profile, `append` at the bottom — for the sign-out and utility links. The `border` prop draws borders between the areas. ## Variations ### Permanent drawer The `permanent` prop keeps the drawer on the screen at all times. Without it the drawer hides on screens narrower than 1056 px — the content gets the whole width, and the navigation is opened by a button. **Example — `Permanent.vue`:** ```vue ``` ### Collapsible drawer A regular drawer follows `v-model` at any screen width. On a wide screen it sits in the layout, and when closed it gives its place back to the content. On a narrow screen the same drawer slides out over the content. When the screen crosses 1056 px, the drawer closes and opens back on its own; `disable-resize-watcher` turns this sync off. The `width` prop sets the width in pixels, and the layout shifts the content by exactly that much. **Example — `Collapsible.vue`:** ```vue ``` ### Temporary drawer The `temporary` prop turns the drawer into a sliding one: it takes no place in the layout, opens through `v-model` and closes on a click on the overlay or on Esc. The `@opened` and `@closed` events report the change of state. **Example — `Temporary.vue`:** ```vue ``` On touch screens a sliding drawer can be pulled out with a swipe from the screen edge and put away with a swipe back. The `touchless` prop turns the gestures off. ### Without the scrim The `scrim` prop controls the backdrop under a sliding drawer. `false` removes it: the content under the drawer stays clickable, but a click outside no longer closes the drawer, so provide your own button for that. A string instead of `true` sets the backdrop color; pass it with transparency, for example `rgb(0 0 0 / 0.3)`, or the content under the drawer is hidden completely. **Example — `Scrim.vue`:** ```vue ``` ### Protection from an accidental close The `persistent` prop keeps a click on the scrim and the Esc key from closing the drawer: only `v-model` closes it. It suits a drawer with a form, where a stray click outside would wipe the input. **Example — `Persistent.vue`:** ```vue ``` ### Minified drawer The `minified` prop shrinks the drawer down to icons and gives the width back to the content. On hover the drawer expands over the page without pushing it, so the section labels stay reachable. **Example — `Minified.vue`:** ```vue ``` ### Position The `right` prop moves the drawer to the right edge. The application navigation usually lives on the left, and the context of the current record — history, comments, filters — on the right. Both drawers can work in the same layout at once. **Example — `Position.vue`:** ```vue ``` ### Color The `bg-color` prop paints the background of the drawer with a palette alias, `color` paints the text and the icons inside. A dark drawer next to light content emphasizes the border of the working area. **Example — `Colors.vue`:** ```vue ``` ### Background image The `image` prop puts an image from a URL under the drawer content, and the `image` slot takes custom background markup. Color the text on top with the `color` prop so it stays readable. **Example — `Image.vue`:** ```vue ``` ### Slots | Slot | Description | | --------- | -------------------------------------------------- | | `prepend` | Pinned area on top: logo, profile | | `default` | Navigation items | | `append` | Pinned area at the bottom: sign-out, utility links | | `image` | Background under the drawer content | The `fixed-slots` prop keeps `prepend` and `append` in place and gives the scroll to the list of sections only — long navigation no longer pushes the sign-out button past the edge. **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Icons help recognize the sections and stay readable in a minified drawer. | Without icons a minified drawer turns into an empty strip. | | The drawer holds the sections of the application; the current one is marked with the active state. | A drawer stuffed with actions and filters stops being navigation. | ## Scenarios ### Application navigation A logo in `prepend`, the sections in a `CdsList` with `active` on the current one, a sign-out button in `append`. The `lhh lpr fff` layout scheme gives the top left corner to the drawer, so it starts from the very top and reads as the backbone of the application. **Example — `Navigation.vue`:** ```vue ``` ### Notification panel A right drawer with `temporary` opens from an icon in the header, shows the list and closes on a click on the overlay. It takes no place in the layout, so the main content is not rebuilt when it opens. **Example — `Notifications.vue`:** ```vue ``` ## API ### CdsDrawer **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `border` | `boolean \| undefined` | `false` | no | Adds borders between the sections (prepend/append). | | `captureFocus` | `boolean \| undefined` | `true` | no | Returns the focus back into the content if it has left it — for example on Tab from the end of the page. A mouse click does not steal the focus. | | `color` | `string \| undefined` | — | no | Component color | | `disableResizeWatcher` | `boolean \| undefined` | `false` | no | Does not sync v-model with the screen width. By default a regular drawer closes when the screen narrows and it becomes a sliding one, and opens back on a wide screen. | | `fixed` | `boolean \| undefined` | `false` | no | Applies `position: fixed`. | | `fixedSlots` | `boolean \| undefined` | `false` | no | Uses an inner scroll for the content section. | | `height` | `string \| number \| undefined` | — | no | Component height | | `image` | `string \| undefined` | — | no | Background image of the drawer (URL). The `image` slot is available for custom background markup. | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minified` | `boolean \| undefined` | `false` | no | Minified look (icons only) until the mouse hovers over it. | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `boolean \| null \| undefined` | `null` | no | Shows/hides the drawer (v-model). Without it a regular drawer is open on a wide screen, and a sliding one is closed. | | `permanent` | `boolean \| undefined` | `false` | no | Always visible, regardless of the screen size. | | `persistent` | `boolean \| undefined` | `false` | no | A click on the scrim and the Esc key do not close the drawer, only v-model does. For drawers with a form where an accidental close loses the input. | | `retainFocus` | `boolean \| undefined` | `true` | no | Traps Tab navigation inside the content: from the last focusable element the focus moves to the first one and back. | | `right` | `boolean \| undefined` | `false` | no | Positions the drawer on the right. | | `scrim` | `string \| boolean \| undefined` | `true` | no | Backdrop under the drawer while it covers the content. `false` removes it entirely: the content stays clickable and the drawer closes only with Esc or through v-model; a string sets its color. | | `tag` | `string \| JSXComponent \| undefined` | `'aside'` | no | Custom HTML tag or component to render | | `temporary` | `boolean \| undefined` | `false` | no | Temporary drawer: slides out over the content at any screen width, opens through v-model and closes on the overlay. On a narrow screen any non-permanent drawer behaves this way. | | `theme` | `string \| undefined` | — | no | Component theme | | `touchless` | `boolean \| undefined` | `false` | no | Disables gestures: a sliding drawer neither opens with a swipe from the screen edge nor closes with a swipe. | | `width` | `string \| number \| undefined` | `240` | no | The drawer width, px. It also goes into the layout: the content shifts by exactly this width. | **Events** | Name | Type | Description | | --- | --- | --- | | `closed` | `[value: boolean]` | The drawer has closed. | | `opened` | `[value: boolean]` | The drawer has opened. | | `update:modelValue` | `[value: boolean]` | The v-model value has changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `any` | Content after the navigation. | | `default` | `any` | Navigation items (`CdsList`). | | `image` | `{ image: string \| undefined; }` | Custom drawer background instead of `CdsImage` from the `image` prop; stretches under the content. | | `prepend` | `any` | Content before the navigation. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `drawerRef` | `HTMLElement \| undefined` | Ref to the root DOM element of the drawer. | --- # CdsEmptyState _Category: Feedback · since 4.0.0_ _Tests: API 32/32 · 36 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 9 axe recommendations (v4.0.0-alpha.11)_ An empty state explains why there is no content on the screen and suggests the next step: no search results, an empty list, a loading error. It is assembled from a media area, headings, a description and an action button. **See also:** For a short message about the result of an operation take CdsToast, and while the data is still loading show CdsSkeletonLoader instead of an empty state. ## Anatomy An empty state is a vertical stack of zones. Each zone appears only when its prop or slot is set, so you pick the composition that fits the situation: from a single heading line to the full set with media and a button. ## Variations ### Content Every text zone has its own prop: `headline` is the large accent ("404", "Empty"), `title` states the situation, `text` gives the details and hints what to do. The width of the text is capped by `text-width` (500 by default), so a long description does not stretch across the whole screen. **Example — `Default.vue`:** ```vue ``` ### Media The `icon` prop shows an icon, `image` shows an image (it wins over the icon). The size of the media comes from `size`: 96 for an icon and 200 for an image by default. The color of the icon is changed by the `color` prop. **Example — `Media.vue`:** ```vue ``` ### Illustrations Legacy illustrations from the `@central-design-system/illustrations` package (CDS 3): the `illustration` prop accepts the kebab-case name of a globally registered component (they are registered through the `illustrations` option of `createCds`). You can render your own illustration through the `illustration` slot. **Example — `Illustration.vue`:** ```vue ``` ### Alignment The `justify` prop pushes the content to the edge of the container: `start`, `center` (default) or `end`. The dashed frame in the demo shows the bounds of the container. **Example — `Justify.vue`:** ```vue ``` ### Actions The `action-text` prop adds a button below the content; a click on it arrives as the `click:action` event. When there is more than one action, render your own buttons in the `actions` slot — bind `props.onClick` from the slot to the main button so that the `click:action` event keeps working. **Example — `Actions.vue`:** ```vue ``` ### Slots Slots replace the content coming from props when you need full control over the markup. | Slot | Description | | -------------- | ---------------------------------------------------------- | | `media` | Media area. Replaces the content from `icon` and `image` | | `illustration` | Illustration. Replaces the content from `illustration` | | `headline` | Accent heading. Replaces the text from `headline` | | `title` | Heading. Replaces the text from `title` | | `text` | Description. Replaces the text from `text` | | `description` | Extra description. Replaces the text from `description` | | `default` | Arbitrary content between the description and the actions | | `actions` | Action buttons; receives `props` with an `onClick` handler | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The text explains why the screen is empty, and the button offers a way out. | «Нет данных» не объясняет причину и не подсказывает, что делать дальше. | | One primary action: it is clear what to do first. | Several equally weighted buttons make the user choose instead of act. | ## Scenarios ### Search with no results When nothing matches the query, an empty state replaces the list. The button from `action-text` clears the query on `click:action` — the user returns to the full list in one click. Try typing a query that is not in the list. **Example — `SearchResults.vue`:** ```vue ``` ### Empty list The first visit to a section is a reason not to apologize for the emptiness but to help the user start: `title` names the situation, `text` promises a result, and the button from `action-text` creates the first record. Once a record is added, the list replaces the placeholder. **Example — `EmptyList.vue`:** ```vue ``` ### Loading error If the data failed to load, explain the reason and let the user retry right there. The button in the `actions` slot shows `loading` while the retry is in flight, and `props.onClick` from the slot keeps the `click:action` event. **Example — `LoadingError.vue`:** ```vue ``` ### 404 page `headline` prints the large error code, and `href` (or `to` for vue-router) is passed to the action button — it works as a link and takes the user away from the dead-end page. **Example — `NotFound.vue`:** ```vue ``` ## API ### CdsEmptyState **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `actionText` | `string \| undefined` | — | no | Text of the action button. When set, a button is rendered below the content. | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `color` | `string \| undefined` | — | no | Component color | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `description` | `string \| undefined` | — | no | Description | | `headline` | `string \| undefined` | — | no | Large accent heading above the main heading. | | `height` | `string \| number \| undefined` | — | no | Component height | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `icon` | `IconValue \| undefined` | — | no | Icon in the media area. | | `illustration` | `string \| undefined` | — | no | Legacy illustration from the `@central-design-system/illustrations` package (CDS 3): the kebab-case name of a globally registered component, for example `rocket`. Illustrations are registered through the `illustrations` option of `createCds`. | | `image` | `string \| undefined` | — | no | Source of the image in the media area (takes priority over `icon`). | | `justify` | `"start" \| "end" \| "center" \| undefined` | `'center'` | no | Horizontal alignment of the content: `start`, `center`, `end`. | | `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 | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | | `textWidth` | `string \| number \| undefined` | `500` | no | Maximum width of the description block. | | `theme` | `string \| undefined` | — | no | Component theme | | `title` | `string \| undefined` | — | no | Heading. | | `to` | `LinkTo \| undefined` | — | no | Target route or route location object for RouterLink. When set, the component behaves as a RouterLink | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click:action` | `[event: MouseEvent]` | Click on the action button. | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `{ props: { onClick: (event: MouseEvent) => void; }; }` | Actions slot; receives `props` with an `onClick` handler to bind to your own element. | | `default` | `any` | Arbitrary content between the description and the actions. | | `description` | `any` | Description slot (instead of the `description` prop). | | `headline` | `any` | Accent heading slot (instead of the `headline` prop). | | `illustration` | `any` | Media area slot for an illustration (instead of the `illustration` prop). | | `media` | `any` | Media area slot (instead of the `image` / `icon` props). | | `text` | `any` | Description slot (instead of the `text` prop). | | `title` | `any` | Heading slot (instead of the `title` prop). | --- # CdsExpandablePanel _Category: Content · since 4.0.0_ _Tests: none yet — behavior is not covered by automated tests_ An expandable panel hides the details behind a title: you see the list of topics and open only the one you need. Take it for FAQs, optional settings and long descriptions that turn a page into an endless feed. **See also:** If the sections are equal in weight and the reader switches between them, take CdsTabs. For a hierarchy of nested nodes take CdsTree, and for a block that simply separates content — CdsCard. ## Anatomy Panels always live inside a `CdsExpandablePanels` group: it keeps track of which panels are open and shares the common settings. Each panel is a title button with a state icon plus the content it reveals. ## Variations ### Panel group `CdsExpandablePanel` does not work without the `CdsExpandablePanels` wrapper — the group is what handles expansion. A simple panel is built from the `title` and `text` props, without slots. By default one panel stays open: opening the next one collapses the previous. **Example — `Default.vue`:** ```vue ``` ### Appearance The `appearance` prop sets the background of the panels: `primary` for a regular page, `secondary` for a colored backdrop, `transparent` when the panel sits inside an already styled block (a card, a sidebar). The `gap` prop changes the spacing between panels — it accepts a number or a string with CSS units. **Example — `Appearances.vue`:** ```vue ``` ### Layout The `variant="accordion"` prop removes the spacing and glues the panels into a single block with shared rounded corners. A list of several questions then reads as one table instead of a set of cards. **Example — `Accordion.vue`:** ```vue ``` ### Expansion The `multiple` prop allows several panels to stay open at once. Through `v-model` you read and set what is expanded: the index of the panel (or its `value`) in the regular mode, and an array in `multiple`. The `mandatory` prop forbids collapsing the last open panel, and `max` limits how many can be expanded at the same time. **Example — `Multiple.vue`:** ```vue ``` ### States The `disabled` prop blocks a single panel when set on the panel, and all of them when set on the group: the title stops responding and loses contrast. The `readonly` prop leaves the panels in their current state — use it in a view mode where the content has to be visible but there is nothing to toggle. **Example — `Disabled.vue`:** ```vue ``` ### Icons The state icon comes from the `expand-icon` and `collapse-icon` props — on the group, on the panel or on an individual title; the value from the closest level wins. The `action` slot of the title replaces the icon entirely and receives the state of the panel, and `hide-actions` removes it altogether. **Example — `Icon.vue`:** ```vue ``` ### Slots The `title` and `text` props are enough for a text panel. As soon as the title needs a counter, a status or an icon, assemble it from `CdsExpandablePanelTitle` and `CdsExpandablePanelContent`. | Slot | Description | | ------------------------------------- | ---------------------------------------------------------------------- | | `CdsExpandablePanels` → `default` | Panels of the group. Slot props carry the `next` and `prev` navigation | | `CdsExpandablePanel` → `title` | Title content. Replaces the text from `title` | | `CdsExpandablePanel` → `text` | Expandable content. Replaces the text from `text` | | `CdsExpandablePanelTitle` → `default` | Title content. Slot props: `expanded`, `disabled`, `readonly` | | `CdsExpandablePanelTitle` → `action` | Expansion icon. Slot props: the same panel state | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The title names the content — you can tell what is inside before opening it. | «Section 1» and «More» promise nothing: people open the panels at random. | | Hide the secondary things behind a panel. Required fields stay in plain sight. | Hidden required fields are easy to miss — the form gets submitted with an error. | | One level of panels: all the sections are visible at once. | A panel inside a panel buries the content two clicks deep — make a separate section instead. | ## Scenarios ### Questions and answers The classic case for `accordion`: the whole list of questions stays visible and an answer opens on click. Only one answer is open at a time, so the reader does not lose their place in the list. The content renders only after the first expansion; if the answers have to show up in search results, turn on `eager`. **Example — `Faq.vue`:** ```vue ``` ### Form with a summary The title shows the current value, and the expanded panel holds the field that changes it. The `default` slot of the title receives `expanded`, so the caption can change on the fly. Such a form takes little space and keeps what has already been filled in visible. **Example — `TripForm.vue`:** ```vue ``` ### Filters in a sidebar Groups of filters in a side panel: `multiple` keeps the needed sections open, `transparent` removes the extra background, and a badge in the title shows how many conditions are selected in a collapsed group. **Example — `Filters.vue`:** ```vue ``` ### Step-by-step filling The group slot hands over `next` and `prev` — buttons inside a panel move the reader to the next step, while `mandatory` prevents closing all of the steps at once. For long wizards with per-step validation take CdsSteps. **Example — `Wizard.vue`:** ```vue ``` ## API ### CdsExpandablePanel **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `collapseIcon` | `IconValue \| undefined` | `'chevron-up'` | no | Icon shown when the panel is expanded and can be collapsed | | `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. | | `expandIcon` | `IconValue \| undefined` | `'chevron-down'` | no | Icon shown when the panel is collapsed and can be expanded | | `focusable` | `boolean \| undefined` | — | no | Highlights the title with a background on focus | | `height` | `string \| number \| undefined` | — | no | Component height | | `hideActions` | `boolean \| undefined` | — | no | Hides the expand/collapse icon | | `hover` | `boolean \| undefined` | `true` | no | Highlights the title with a background on hover | | `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 | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `static` | `boolean \| undefined` | — | no | Turns off the animation of the title | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `text` | `string \| undefined` | — | no | Text of the expandable content of the panel | | `title` | `string \| undefined` | — | no | Text of the panel title | | `value` | `any` | — | no | Value of the component within the group | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `group:selected` | `[value: { value: boolean; }]` | Fires when the panel is expanded or collapsed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Arbitrary content of the panel. | | `text` | `any` | Expandable content of the panel. | | `title` | `any` | Content of the panel title. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isSelected` | `boolean` | The panel is expanded | | `select` | `(value: boolean) => void` | Expands or collapses the panel | | `toggle` | `() => void` | Toggles the expansion of the panel | ### CdsExpandablePanelContent **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Expandable content of the panel. | ### CdsExpandablePanels **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `appearance` | `"primary" \| "secondary" \| "transparent" \| undefined` | `'primary'` | no | Appearance of the panels | | `collapseIcon` | `IconValue \| undefined` | `'chevron-up'` | no | Icon shown when the panel is expanded and can be collapsed | | `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. | | `expandIcon` | `IconValue \| undefined` | `'chevron-down'` | no | Icon shown when the panel is collapsed and can be expanded | | `focusable` | `boolean \| undefined` | — | no | Highlights the title with a background on focus | | `gap` | `string \| number \| undefined` | — | no | Spacing between the panels | | `hideActions` | `boolean \| undefined` | — | no | Hides the expand/collapse icon | | `hover` | `boolean \| undefined` | `true` | no | Highlights the title with a background on hover | | `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 | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `required` | `boolean \| "force" \| undefined` | — | no | Requires at least one item to stay selected | | `selectedClass` | `string \| undefined` | — | no | CSS class applied in the selected state | | `static` | `boolean \| undefined` | — | no | Turns off the animation of the title | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `variant` | `"default" \| "accordion" \| undefined` | `'default'` | no | Display variant of the panel group | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: unknown]` | Fires when the set of selected panels changes. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `CdsExpandablePanelsSlotProps` | Panels of the group. The slot props carry the navigation between panels. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `next` | `() => void` | Expands the next panel | | `prev` | `() => void` | Expands the previous panel | ### CdsExpandablePanelTitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `collapseIcon` | `IconValue \| undefined` | `'chevron-up'` | no | Icon shown when the panel is expanded and can be collapsed | | `expandIcon` | `IconValue \| undefined` | `'chevron-down'` | no | Icon shown when the panel is collapsed and can be expanded | | `focusable` | `boolean \| undefined` | — | no | Highlights the title with a background on focus | | `height` | `string \| number \| undefined` | — | no | Component height | | `hideActions` | `boolean \| undefined` | — | no | Hides the expand/collapse icon | | `hover` | `boolean \| undefined` | `true` | no | Highlights the title with a background on hover | | `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 | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `static` | `boolean \| undefined` | — | no | Turns off the animation of the title | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `action` | `CdsExpandablePanelTitleSlotProps` | Expand/collapse icon. The slot props carry the state of the panel. | | `default` | `CdsExpandablePanelTitleSlotProps` | Content of the title. The slot props carry the state of the panel. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isSelected` | `boolean` | The panel is expanded | | `toggle` | `() => void` | Toggles the expansion of the panel | --- # CdsField _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 33/33 · 41 unit · 4 known bugs · lines 96.4% (v4.0.0-alpha.13) · a11y: 6 axe recommendations (v4.0.0-alpha.11)_ The frame of an input: the background, the border, the focus and error states, the inner icons, the clear button and the loading indicator. You put the control itself into the `default` slot — the text fields, selects and autocompletes of the design system are built on `CdsField`. **See also:** For regular input take the ready-made fields — CdsTextInput, CdsSelect, CdsTextArea. `CdsField` is needed when your control is not in the library. The label, the description and the messages around the frame are added by CdsInput. ## Anatomy The `default` slot receives a `props` object — bind it to your control so the field gets an `id`, a class and the link to the messages. Around the control `CdsField` lays out the inner icons and the clear button. ## Variations ### Icons The `prepend-inner-icon` and `append-inner-icon` props put an icon inside the frame — before and after the control. The same areas are available as the `prepend-inner` and `append-inner` slots when you need a button rather than an icon. **Example — `Icons.vue`:** ```vue ``` ### Clearing The `clearable` prop adds a cross; it shows up when the field is marked `dirty` and appears on hover or focus. The `persistent-clearable` prop keeps the cross visible at all times. The value is reset not by the component but by you — in the `@click:clear` handler. **Example — `Clearable.vue`:** ```vue ``` ### States The `disabled`, `readonly` and `error` props change the color of the frame and of the text. Set the state of the control inside separately: `CdsField` draws the frame but does not control your `input`. **Example — `States.vue`:** ```vue ``` ### Loading The `loading` prop shows a bar under the field. The `circle` value replaces it with a circular indicator inside the frame — handier when the field waits for a server response while typing. **Example — `Loading.vue`:** ```vue ``` ### Sizes The `size` prop changes the height of the frame and its inner paddings. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ## Scenarios ### A field with tags The control in the `default` slot is any markup you like, so a set of tags and an input for a new entry fit inside the frame. The `focus` and `blur` handlers from the slot turn the highlighting of the frame on, `dirty` shows the cross, and `@click:clear` empties the list. **Example — `TagsField.vue`:** ```vue ``` ## API ### CdsField **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 | | `appendInnerIcon` | `IconValue \| undefined` | — | no | Icon in the inner append slot, after the content of the field | | `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 | | `details` | `boolean \| undefined` | — | no | Reserves the space for hints and error messages under the field | | `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 | | `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. | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Field identifier — the value of the `id` HTML attribute for the inner control | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `persistentClearable` | `boolean \| undefined` | — | no | Always show the clear button, not only on hover or focus | | `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 | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | **Events** | Name | Type | Description | | --- | --- | --- | | `click:clear` | `[e: MouseEvent]` | Click on the clear button (clearable prop) | | `update:focused` | `[focused: boolean]` | Fires when the element gains or loses focus | **Slots** | Name | Type | Description | | --- | --- | --- | | `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). | | `default` | `CdsFieldSlot` | Content inside the field | | `loader` | `LoaderSlotProps` | Slot for a custom loader (shown when the loading prop is true). | | `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 | --- # CdsFileInput _Category: Controls · since 4.0.0 · status: new_ _Tests: API 81/81 · 106 unit · 4 e2e · 11 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 11 axe recommendations (v4.0.0-alpha.11)_ A file field: the user attaches documents by a click, by dragging or by pasting from the clipboard. Around the native `input type="file"` the component gathers everything a form needs: a label, a description, messages, a counter, clearing and a filter by file types. **See also:** If you need a prominent upload zone with a list of files, take CdsFileUpload; sending the files to the server is the job of CdsUploader. ## Anatomy The component is built on the same base as CdsTextInput: the label, the description, the messages, validation and the colors work the same way. What the field has of its own is the upload icon on the left (`prepend-icon`, `upload` by default), the names of the chosen files instead of the typed text and the file counter in the bottom block. Clearing (`clearable`) is on out of the box. ## Variations ### Label and hints `label` names the field, the requirements for the files go into `description`, and `placeholder` hints that a file can be dragged into the field. A chosen file is shown by its name. **Example — `Default.vue`:** ```vue ``` ### Several files The `multiple` prop allows choosing several files at once — their names are listed separated by commas. **Example — `Multiple.vue`:** ```vue ``` ### Showing as tags The `chips` prop shows every file as a separate tag (CdsTag) — a list of several files reads more easily. **Example — `Chips.vue`:** ```vue ``` ### Size and counter `show-size` adds the size to the file name, `counter` shows the number and the total size under the field. Long names are truncated in the middle — the threshold is set by `truncate-length` (22 characters by default). **Example — `SizeAndCounter.vue`:** ```vue ``` ### Filter by type `filter-by-type` accepts MIME types, wildcard types and extensions separated by commas (`image/*,.pdf`). The files that do not fit never get into the model — the `rejected` event reports them: show the user what exactly was rejected and why. **Example — `FilterByType.vue`:** ```vue ``` ### States `disabled` blocks the field, `readonly` lets you look at the selection but not change it, `loading` shows an indicator — while the files are going to the server, for example. **Example — `States.vue`:** ```vue ``` ### Slots The zones of the field match CdsTextInput: `prepend` / `append` outside the border, `prepend-inner` / `append-inner` inside it. The extra `selection` slot replaces the standard list of file names. | Slot name | Description | | :-------------- | :--------------------------------------------------- | | `label` | Label content (replaces `label`) | | `description` | Description content (replaces `description`) | | `prepend` | Element before the field (replaces the upload icon) | | `append` | Element after the field | | `prepend-inner` | Element at the start of the field, inside the border | | `append-inner` | Element at the end of the field, inside the border | | `selection` | Your own display of the chosen files | | `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 | The `selection` slot receives the truncated file names (`fileNames`) and the total size (`totalBytes`, `totalBytesReadable`). **Example — `Selection.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The file requirements are visible before the choice: the description names the formats and the size limit. | The user learns about the restrictions only from an error after picking a file. | | Tags and a counter: every file reads separately and the number is visible at once. | Comma-separated names merge together already at three or four files. | | The error names the reason and suggests what to do. | “Upload error” explains neither what is wrong nor how to fix it. | ## Scenarios ### Submitting a form with attachments The field takes part in CdsForm validation on a par with the others: `rules` receive the chosen files — check that the attachments are there and do not exceed the size limit before sending them to the server. `chips` and `counter` help the user keep track of the list. **Example — `AttachmentsForm.vue`:** ```vue ``` ### An upload button without a field The `hide-input` prop hides the field, leaving only the clickable icon — handy for embedding the upload into a toolbar or a comment line. Show the chosen files next to it yourself: here they are tags with `closable`, and a click on the cross removes a file from the model. **Example — `UploadButton.vue`:** ```vue ``` ### An image preview `filter-by-type="image/*"` lets images through only, and the preview is built from the model value through `URL.createObjectURL`. Do not forget to release the previous URL — otherwise the chosen files pile up in the memory of the tab. **Example — `ImagePreview.vue`:** ```vue ``` ## API ### CdsFileInput **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 | | `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 | Show the chosen files as tags (CdsTag) instead of a list of names. | | `clearable` | `boolean \| undefined` | `true` | no | Shows the clear button | | `clearIcon` | `IconValue \| undefined` | `'remove'` | no | Icon of the clear button | | `color` | `string \| undefined` | — | no | Component color | | `counter` | `boolean \| undefined` | — | no | Show a counter of the number (and, with `showSize`, of the total size) of the chosen files. | | `counterSizeString` | `string \| undefined` | `'$cds.fileInput.counterSize'` | no | Localization key for the text of the counter with the file size. | | `counterString` | `string \| undefined` | `'$cds.fileInput.counter'` | no | Localization key for the text of the file count counter. | | `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. | | `filterByType` | `string \| undefined` | — | no | Filtering of files by MIME type or extension (`image/*,.pdf`, for example). The rejected files do not get into the model. | | `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 | | `hideInput` | `boolean \| undefined` | — | no | Hide the field, leaving only the prepend icon (to use it as a button, for example). | | `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 | | `modelValue` | `File \| File[] \| null \| undefined` | `(props) => props.multiple ? [] : null` | no | Value of the model: an array of files (with `multiple`), a single file or `null`. | | `multiple` | `boolean \| undefined` | — | no | Allow selecting several files. | | `name` | `string \| undefined` | — | no | Name of the input | | `persistentClearable` | `boolean \| undefined` | — | no | Always show the clear button, not only on hover or focus | | `persistentHint` | `boolean \| undefined` | — | no | Always show the hint, not only on focus | | `placeholder` | `string \| undefined` | — | no | Placeholder text shown in an empty field (while no files are chosen yet). | | `prependIcon` | `IconValue \| undefined` | `'upload'` | 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 | | `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. | | `showSize` | `boolean \| 1000 \| 1024 \| undefined` | `false` | no | Show the size of the chosen files. A boolean or the base: 1000 (kB) or 1024 (KiB). | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `truncateLength` | `string \| number \| undefined` | `22` | no | Maximum length of a file name before it is truncated (the characters at the start and at the end are kept). | | `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. | | `rejected` | `[files: File[]]` | Fires when some of the files were rejected by the `filterByType` filter. | | `update:focused` | `[focused: boolean]` | Fires when the element gains or loses focus. | | `update:modelValue` | `[value: File \| File[]]` | Fires when the list of the chosen files 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. | | `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 | | `selection` | `CdsFileInputSelectionSlot` | Slot for a custom display of the chosen files. | **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 | --- # CdsFileUpload _Category: Controls · since 4.0.0 · status: new_ _Tests: API 214/214 · 149 unit · 7 e2e · 18 known bugs · lines 99% (v4.0.0-alpha.13) · a11y: 16 axe recommendations (v4.0.0-alpha.11)_ A file upload zone: it accepts files by dragging, by pasting from the clipboard and through the system dialog, and shows the selection as a list with image previews. Around the zone the component gathers everything a form needs: a label, a description, messages and validation. **See also:** For a compact file field in a form row use CdsFileInput; sending the files to the server is the job of CdsUploader. ## Anatomy The frame matches the other form fields (CdsTextInput): the label, the description, the messages and validation work the same way. What the component has of its own is the upload zone with an icon, a title and a browse button, and the list of the chosen files: every file gets a preview (for images), a name, a size and a remove button. ## Variations ### Choosing files The basic case is a single file: drag it into the zone, paste it from the clipboard or pick it with the button. A repeated choice replaces the file. **Example — `Default.vue`:** ```vue ``` The `multiple` prop allows choosing several files — they pile up as a list under the zone. `clearable` gives every one of them a remove button, `show-size` — the size. **Example — `Multiple.vue`:** ```vue ``` ### Texts and the icon Every caption of the zone is configurable: `title` — the heading, `subtitle` — the line with the file requirements (visible with `size` `md` and `lg`), `browse-text` — the text of the button, `divider-text` — the divider, `icon` — the icon in the center of the zone. **Example — `Texts.vue`:** ```vue ``` ### Sizes The `size` prop controls the density of the zone: `md` is the default, `lg` adds air, and `sm` shrinks the zone to a compact row — the browse button is hidden and the whole area becomes clickable. **Example — `Sizes.vue`:** ```vue ``` ### Layout `inset-file-list` moves the list of the chosen files inside the zone — the component does not grow downwards as files are added. `hide-browse` removes the browse button: the zone is clickable as a whole, but say so in the title. **Example — `Layout.vue`:** ```vue ``` ### States `disabled` blocks the component, `readonly` keeps the list visible but forbids changes, `loading` shows an indicator — while the files are going to the server, for example. `error-messages` puts the zone into the error state and shows the text under it. **Example — `States.vue`:** ```vue ``` ### Filtering by type `filter-by-type` accepts MIME types, wildcard types and extensions separated by commas (`image/*,.pdf`). The files that do not fit never get into the model — the `rejected` event reports them: show the user what exactly was rejected and why. **Example — `Filter.vue`:** ```vue ``` ### Slots The parts of the zone are replaced by the slots of the same name, and `item` redraws every file in the list: `CdsFileUploadItem` is available inside — it receives the props of the file automatically, it is enough to pass the handlers from the slot arguments. | Slot name | Description | | :----------------------------------- | :---------------------------------------------------------- | | `title` / `icon` / `divider` | The title, the icon and the divider of the zone | | `browse` | The file browse button (`props` holds the click handler) | | `item` | An item of the list of the chosen files | | `single` | The only file with `inset-file-list` and without `multiple` | | `default` | Your own upload zone as a whole | | `input` | The native `input type="file"` for manual placement | | `loader` | Your own loading indicator (with `loading`) | | `label` / `description` / `messages` | The texts of the frame — as in the other form fields | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The file requirements are visible before the choice: the subtitle names the formats and the size limit. | A filter without an explanation: unsuitable files are rejected and the reason stays invisible to the user. | | The error names the reason and suggests what to do. | “Error” explains neither what is wrong nor how to fix it. | | Files of the same kind are collected by one zone with multiple — the user adds everything at once. | A separate zone for every file forces picking them one by one and stretches the form. | ## Scenarios ### Applying for a job The component takes part in CdsForm validation on a par with the other fields: `rules` receive the chosen files. Here the résumé is required and is accepted as a PDF only — `filter-by-type` cuts the foreign formats off, and the rules insure against an empty submission and a file that is too heavy. **Example — `ResumeForm.vue`:** ```vue ``` ### An image gallery `filter-by-type="image/*"` lets images through only — every one of them gets a preview in the list automatically. `inset-file-list` gathers what was uploaded inside the zone, and `show-size` helps keep an eye on the volume. **Example — `ImageGallery.vue`:** ```vue ``` ### Uploading on selection The files do not have to wait for the form submission — start the upload right away: watch the model, turn `loading` on for the duration of the request and confirm the result through `messages`. The request here is simulated with a timer. **Example — `AutoUpload.vue`:** ```vue ``` ## API ### CdsFileUpload **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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 | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `browseText` | `string \| undefined` | `'$cds.fileUpload.browse'` | no | Text of the file browse button. Supports localization keys (`$cds.fileUpload.browse`). | | `centerAffix` | `boolean \| undefined` | `true` | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `clearable` | `boolean \| undefined` | — | no | Allows removing the chosen files from the list. | | `color` | `string \| undefined` | — | no | Component color | | `description` | `string \| undefined` | — | no | Description of the component, shown under the label | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `dividerText` | `string \| undefined` | `'$cds.fileUpload.divider'` | no | Text of the divider between the icon and the file browse button. | | `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. | | `filterByType` | `string \| undefined` | — | no | Filtering of files by MIME type or extension (`image/*,.pdf`, for example). The rejected files do not get into the model. | | `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. | | `hideBrowse` | `boolean \| undefined` | — | no | Hides the file browse button — the whole upload zone becomes clickable. | | `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 | | `icon` | `IconValue \| undefined` | `'upload'` | no | Icon in the center of the upload zone. | | `iconColor` | `string \| boolean \| undefined` | — | no | Icon color. Accepts a boolean or a color string | | `id` | `string \| undefined` | — | no | Unique identifier of the component | | `insetFileList` | `boolean \| undefined` | — | no | Shows the list of the chosen files inside the upload zone instead of under it. | | `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 | | `modelValue` | `File \| File[] \| null \| undefined` | `null` | no | The chosen files. An array with `multiple`, a single `File` otherwise. | | `multiple` | `boolean \| undefined` | — | no | Allows choosing several files. | | `name` | `string \| undefined` | — | no | Name of the input | | `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. | | `scrim` | `string \| boolean \| undefined` | `true` | no | Dimming of the upload zone while files are being dragged over it. | | `showSize` | `ShowSize \| undefined` | `false` | no | Shows the size of the file. A number sets the base for the human-readable conversion. | | `size` | `"sm" \| "md" \| "lg" \| undefined` | `'md'` | no | Size of the upload zone. With `sm` the zone is shown as a compact row without the browse button and the divider. | | `subtitle` | `string \| undefined` | — | no | Subtitle under the file browse button. Shown with `size` `md` and `lg` only. | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `title` | `string \| undefined` | `'$cds.fileUpload.title'` | no | Title of the upload zone. | | `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 | | --- | --- | --- | | `rejected` | `[files: File[]]` | The files did not pass the `filterByType` filtering. | | `update:focused` | `[focused: boolean]` | The focus state changed. | | `update:modelValue` | `[files: File[]]` | The list of the chosen files changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `browse` | `CdsFileUploadBrowseSlot` | The file browse button. | | `default` | `any` | Fully replaces the upload zone with your own markup. | | `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` | `any` | Divider between the title and the file browse button. | | `icon` | `any` | Icon in the center of the upload zone. | | `input` | `{ inputNode: VNode; }` | The native `input[type=file]`, given out for manual placement in the markup. | | `item` | `CdsFileUploadFileSlot` | An item of the list of the chosen files. | | `label` | `{ label: string \| undefined; props: Record; }` | Default slot of the CdsLabel component | | `loader` | `LoaderSlotProps` | The 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 | | `single` | `CdsFileUploadFileSlot` | The only chosen file with `insetFileList` and without `multiple`. | | `title` | `any` | Title of the upload zone. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `controlRef` | `HTMLInputElement \| undefined` | Ref to the native `input[type=file]` element — for opening the file dialog programmatically. | | `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 | ### CdsFileUploadDropzone **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `browseText` | `string \| undefined` | `'$cds.fileUpload.browse'` | no | Text of the file browse button. Supports localization keys (`$cds.fileUpload.browse`). | | `clearable` | `boolean \| undefined` | — | no | Allows removing the chosen files from the list. | | `color` | `string \| undefined` | — | no | Background color of the surface | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `dividerText` | `string \| undefined` | `'$cds.fileUpload.divider'` | no | Text of the divider between the icon and the file browse button. | | `error` | `boolean \| undefined` | — | no | Shows the upload zone in the error state. | | `height` | `string \| number \| undefined` | — | no | Component height | | `hideBrowse` | `boolean \| undefined` | — | no | Hides the file browse button — the whole upload zone becomes clickable. | | `icon` | `IconValue \| undefined` | `'upload'` | no | Icon in the center of the upload zone. | | `insetFileList` | `boolean \| undefined` | — | no | Shows the list of the chosen files inside the upload zone instead of under it. | | `length` | `string \| number \| undefined` | `150` | no | Length of the divider. Defaults to pixels. | | `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 | | `modelValue` | `File[] \| undefined` | `[]` | no | The list of the chosen files. Used when `CdsFileUploadDropzone` is applied on its own. | | `multiple` | `boolean \| undefined` | — | no | Allows choosing several files. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the divider. | | `position` | `"absolute" \| "static" \| "fixed" \| "relative" \| "sticky" \| undefined` | — | no | CSS positioning of the component — the value of the `position` property | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `scrim` | `string \| boolean \| undefined` | `true` | no | Dimming of the upload zone while files are being dragged over it. | | `showSize` | `ShowSize \| undefined` | `false` | no | Shows the size of the file. A number sets the base for the human-readable conversion. | | `size` | `"sm" \| "md" \| "lg" \| undefined` | `'md'` | no | Size of the upload zone. With `sm` the zone is shown as a compact row without the browse button and the divider. | | `subtitle` | `string \| undefined` | — | no | Subtitle under the file browse button. Shown with `size` `md` and `lg` only. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `thickness` | `string \| number \| undefined` | — | no | Thickness of the divider. Defaults to pixels. | | `title` | `string \| undefined` | `'$cds.fileUpload.title'` | no | Title of the upload zone. | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click:browse` | `[]` | The file browse button was pressed. | | `click:remove` | `[index: number]` | Removal of a file by its index was requested. | | `drop` | `[files: File[]]` | Files were dropped into the upload zone. | **Slots** | Name | Type | Description | | --- | --- | --- | | `browse` | `CdsFileUploadBrowseSlot` | The file browse button. | | `default` | `{ isDragging: boolean; hasFiles: boolean; files: readonly File[]; props: { onClick: () => void; }; }` | Fully replaces the content of the upload zone. | | `divider` | `any` | Divider between the title and the file browse button. | | `icon` | `any` | Icon in the center of the upload zone. | | `input` | `any` | The native `input[type=file]`. | | `item` | `CdsFileUploadFileSlot` | An item of the list of the chosen files inside the upload zone. | | `loader` | `any` | The loading indicator. | | `single` | `CdsFileUploadFileSlot` | The only chosen file with `insetFileList` and without `multiple`. | | `title` | `any` | Title of the upload zone. | ### CdsFileUploadItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Forces the active state of the item | | `activeClass` | `string \| undefined` | — | no | Class applied to list items when they are in the active state | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendAvatar` | `string \| undefined` | — | no | Avatar (image URL) shown after the item content | | `appendIcon` | `IconValue \| undefined` | — | no | Icon shown after the item content | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `clearable` | `boolean \| undefined` | — | no | Allows removing the file from the list. | | `color` | `string \| undefined` | — | no | Component color | | `description` | `string \| number \| boolean \| undefined` | — | no | Description of the list item shown below the title and the subtitle | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `file` | `File \| undefined` | `null` | no | The file shown by the list item. | | `fileIcon` | `IconValue \| undefined` | `'file'` | no | Fallback icon for the files that have no preview. | | `height` | `string \| number \| undefined` | — | no | Component height | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `index` | `number \| undefined` | — | no | Index of the item; used for keyboard navigation | | `lines` | `false \| "one" \| "two" \| "three" \| undefined` | `'two'` | no | Number of lines in the list items; affects their height. `false` turns off the fixed height | | `link` | `boolean \| undefined` | — | no | Turns the item into a clickable link. Detected automatically when `href` or `to` is set | | `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 | | `nav` | `boolean \| undefined` | — | no | Applies navigation list styles (rounded active items) | | `prependAvatar` | `string \| undefined` | — | no | Avatar (image URL) shown before the item content | | `prependGap` | `string \| number \| undefined` | — | no | Indent before the item content (reserves space for the prepend icon or avatar) | | `prependIcon` | `IconValue \| undefined` | — | no | Icon shown before the item content | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `showSize` | `ShowSize \| undefined` | `false` | no | Shows the size of the file instead of its MIME type. | | `slim` | `boolean \| undefined` | — | no | Removes the inner paddings of the list and of the menu container: the list fills the available area completely | | `subtitle` | `string \| number \| boolean \| undefined` | — | no | Subtitle of the item shown below the title | | `tabindex` | `string \| number \| undefined` | — | no | Value of the element `tabindex` attribute | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `title` | `string \| number \| boolean \| undefined` | — | no | Title of the item shown in the component | | `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 item used for selection and activation in the list | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click` | `[event: MouseEvent \| KeyboardEvent]` | A click on the list item. | | `click:remove` | `[]` | Removal of the file was requested. | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `ListItemSlot` | Content after the item text (in place of the append icon or avatar) | | `clear` | `{ props: { onClick: () => void; }; }` | The file removal button. | | `default` | `ListItemSlot` | Default content inside the item | | `description` | `ListItemDescriptionSlot` | Content of the item description (shown below the title and the subtitle) | | `prepend` | `ListItemSlot` | Content before the item text (in place of the prepend icon or avatar) | | `subtitle` | `ListItemSubtitleSlot` | Content of the item subtitle | | `title` | `ListItemTitleSlot` | Content of the item title | ### CdsFileUploadList **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activatable` | `boolean \| undefined` | — | no | Allows items to be activated (highlighting the current item without selection mode) | | `activated` | `any` | — | no | Identifiers of the active items (supports v-model through `update:activated`) | | `activeClass` | `string \| undefined` | — | no | Class applied to list items when they are in the active state | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `activeStrategy` | `ActiveStrategyProp \| undefined` | — | no | Activation strategy for items (single, multiple, and so on) | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `clearable` | `boolean \| undefined` | — | no | Allows removing files from the list. | | `collapseIcon` | `IconValue \| undefined` | — | no | Icon shown on a collapsed group | | `color` | `string \| undefined` | — | no | Component color | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `expandIcon` | `IconValue \| undefined` | — | no | Icon shown on an expanded group | | `files` | `File[] \| undefined` | — | no | The list of files. Taken from the `CdsFileUpload` context by default. | | `filterable` | `boolean \| undefined` | — | no | **FOR INTERNAL USE ONLY** Turns on filtering mode: the space key does not select an item but is used for typing. Applies to the CdsCombobox and CdsAutocomplete components | | `height` | `string \| number \| undefined` | — | no | Component height | | `indent` | `string \| number \| undefined` | — | no | Indent size for nested item groups | | `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 | | `itemsRegistration` | `ItemsRegistrationType \| undefined` | `'render'` | no | Item registration strategy: `render` — as they are rendered, otherwise all at once | | `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 | | `lines` | `false \| "one" \| "two" \| "three" \| undefined` | `false` | no | Number of lines in the list items; affects their height. `false` turns off the fixed height | | `mandatory` | `boolean \| undefined` | — | no | Makes the selection mandatory: forbids clearing the selection of the last item | | `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 | | `nav` | `boolean \| undefined` | — | no | Applies navigation list styles (rounded active items) | | `navigationIndex` | `number \| undefined` | — | no | Index of the current item during keyboard navigation (supports v-model) | | `navigationStrategy` | `"focus" \| "track" \| undefined` | `'focus'` | no | Keyboard navigation strategy: `focus` — moves the focus, `track` — a virtual cursor | | `opened` | `any` | — | no | Identifiers of the expanded groups (supports v-model through `update:opened`) | | `openStrategy` | `OpenStrategyProp \| undefined` | `'list'` | no | Expansion strategy for groups (`list`, `single`, `multiple`) | | `prependGap` | `string \| number \| undefined` | — | no | Indent before the item content (reserves space for the prepend icon or avatar) | | `required` | `boolean \| undefined` | — | no | Makes the selection mandatory: forbids clearing the selection of the last item | | `returnObject` | `boolean \| undefined` | — | no | Return an object in the model value instead of an array | | `selectable` | `boolean \| undefined` | — | no | Allows items to be selected | | `selected` | `any` | — | no | Identifiers of the selected items (supports v-model through `update:selected`) | | `selectStrategy` | `SelectStrategyProp \| undefined` | `'single-leaf'` | no | Selection strategy for items (`single-leaf`, `leaf`, `independent`, `classic`, and so on) | | `showSize` | `ShowSize \| undefined` | `false` | no | Shows the size of every file. | | `slim` | `boolean \| undefined` | — | no | Removes the inner paddings of the list and of the menu container: the list fills the available area completely | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `valueComparator` | `ValueComparator \| undefined` | — | no | Function that compares item values to determine the selected state | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ files: readonly File[]; onClickRemove: (index: number) => void; }` | Fully replaces the content of the list. | | `item` | `CdsFileUploadFileSlot` | An item of the list. | --- # CdsFooter _Category: Layouts · since 4.0.0_ _Tests: API 12/12 · 21 unit · 1 known bug · lines 96.7% (v4.0.0-alpha.13) · a11y: 6 axe recommendations (v4.0.0-alpha.11)_ The footer of the application: a copyright notice and utility links on regular pages, an action bar on forms. The layout measures the height of the footer and reserves the space, so it never covers the last line of the content. **See also:** The footer works only inside CdsLayout — outside the layout it renders nothing and warns about it in the console. The top bar of the application is built by CdsHeader, and the content of both by CdsToolbar. ## Variations ### Separator The footer is pinned to the bottom edge and overlaps the content, so its border is worth marking: `bordered` draws a line, `elevated` casts a shadow upwards. The shadow matters more when a long list continues under the footer. **Example — `Separators.vue`:** ```vue ``` ### Color The `bg-color` prop paints the background of the footer with a palette alias, `color` paints the text and the icons inside. If only the background is set, the text color is picked to be contrasting automatically. **Example — `Colors.vue`:** ```vue ``` ### Floating mode The `reveal` prop hides the footer when scrolling down and brings it back when scrolling up. The `@reveal` event reports the change of visibility — to adjust a selection counter, for example. **Example — `Reveal.vue`:** ```vue ``` ### Visibility The `model-value` prop removes the footer entirely: the layout stops reserving space for it, and the content takes the full height. This is how you hide an action bar until the form has changed. **Example — `Visibility.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The footer is pinned to the bottom and keeps the form actions at hand at any scroll position. | Actions at the end of a long page have to be found by scrolling. | | The footer holds the utility links and the copyright: that is where people look for them. | Section navigation in the footer duplicates the side drawer and confuses the reader. | ## Scenarios ### Site footer The copyright on the left, the utility links on the right — the familiar layout people look for at the bottom of a page. The height comes from the content, and `height` tells the layout the expected value before the first measurement. **Example — `PageFooter.vue`:** ```vue ``` ### Form action bar On a long form the "Cancel" and "Publish" buttons live in the footer: they are visible at any scroll position and need no reaching for. `CdsToolbarTitle` stretches and pushes the buttons to the right edge, and `elevated` separates the bar from the fields. **Example — `FormActions.vue`:** ```vue ``` ## API ### CdsFooter **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `bordered` | `boolean \| undefined` | `false` | no | Shows the border. | | `color` | `string \| undefined` | — | no | Component color | | `elevated` | `boolean \| undefined` | `false` | no | Shows the shadow. | | `height` | `string \| number \| undefined` | `50` | no | Height of the element. | | `modelValue` | `boolean \| undefined` | `true` | no | Visibility of the element in the layout. | | `reveal` | `boolean \| undefined` | `false` | no | Floating mode: the element appears/hides on scroll. | | `revealOffset` | `number \| undefined` | `250` | no | Scroll threshold (px) up to which the floating element stays visible. | | `theme` | `string \| undefined` | — | no | Component theme | **Events** | Name | Type | Description | | --- | --- | --- | | `focusin` | `[event: FocusEvent]` | Focus moved inside the footer. | | `reveal` | `[value: boolean]` | Visibility of the floating footer has changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the footer (`CdsToolbar` and others). | --- # CdsForm _Category: Controls · since 4.0.0_ _Tests: API 20/20 · 36 unit · 2 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 10 axe recommendations (v4.0.0-alpha.11)_ A form joins fields into one group: it collects their validation into a common status, intercepts the submission and can reset the values. CDS fields with the `rules` prop connect to the form automatically — with no registration and no extra code. **See also:** The form does not render the fields itself — build them out of CdsTextInput, CdsSelect, CdsCheckbox and other controls. The validation rules are declared on the fields themselves through the `rules` prop. ## Anatomy The form is a native `form` with an optional header: the heading and the description are rendered above the content, and the fields from the default slot stay as they are. The heading is bound to the form through `aria-labelledby`, the description — through `aria-describedby`. ## Variations ### Heading and description The `label` prop names the form, `description` adds an explanation under the heading. The slots of the same name accept arbitrary markup. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Validity status The `v-model` of the form is the common status of its fields: `null` while the form has not been checked, `false` on errors and `true` when all the fields are valid. The status is updated on the fly — it is handy for blocking the submit button, for example. **Example — `ValidStatus.vue`:** ```vue ``` ### The moment of validation The `validate-on` prop sets the moment the check runs for all the fields of the form; the field's own `validate-on` takes precedence. Switch the mode and try it out: with `input` (the default) the error appears as you type, with `blur` — after leaving the field, with `submit` — only when the form is submitted. **Example — `ValidateOn.vue`:** ```vue ``` ### Fast validation The `first-fail` prop stops the check at the first invalid field. Submit the form: the error is shown only for "Имя", although "Фамилия" is invalid too. **Example — `FastValidation.vue`:** ```vue ``` ### States `disabled` blocks all the fields of the form at once, `readonly` keeps the values visible and copyable but forbids changing them. There is no need to configure the individual fields — the state is inherited. **Example — `DisabledAndReadonly.vue`:** ```vue ``` ### Hiding the details The bottom block with the messages is controlled by the `hide-details` prop on the fields themselves: `true` always hides the block — errors included, `false` always reserves space for it, `auto` shows the block only when there is something to show. In dense forms use `auto`: the fields sit right next to each other, but the validation errors are not lost. Switch the value and submit an empty form. **Example — `HideDetails.vue`:** ```vue ``` ### Slots The default slot receives the state of the form and the control methods — the "Check" and "Reset" buttons are built without a ref to the component. | Slot name | Description | | :------------ | :---------------------------------------------------------------------------------------------------- | | `label` | Heading content (replaces `label`) | | `description` | Description content (replaces `description`) | | `default` | Form content; slot props: `isValid`, `errors`, `isValidating`, `validate`, `reset`, `resetValidation` | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The heading and the description explain what the form is and what happens after submission. | A set of fields without context makes the user guess why they are filling them in. | | Show an error after the input or on submission — while a field is untouched the form stays silent. | A form that complains before the user's first action looks broken. | | The submit button names the action — it is clear what happens after the click. | A faceless “OK” says nothing about what the form will do. | ## Scenarios ### Submitting a form The `submit` event is a Promise: `await event` returns the validation result, and the handler decides on its own whether to send the data. The `.prevent` modifier turns off the native page submission. The request here is simulated with `setTimeout`, and the button shows `loading` for the duration of the "request". **Example — `SubmitForm.vue`:** ```vue ``` ### Control from outside The `validate`, `reset` and `resetValidation` methods are also available through a ref to the form. That is how the form is driven from outside — from the footer of a modal or a wizard panel, where the buttons live outside the form markup. **Example — `RefControl.vue`:** ```vue ``` ### Vee-validate The form gets along with external validation libraries. With [vee-validate](https://vee-validate.logaretm.com/v4/) the schema is set in `useForm`, and the error messages of the fields are passed into `error-messages`. **Example — `VeeValidate.vue`:** ```vue ``` ### Vuelidate With [vuelidate](https://vuelidate-next.netlify.app/) the rules are declared declaratively, and the field errors are passed into `error-messages` in the same way. **Example — `Vuelidate.vue`:** ```vue ``` ## API ### CdsForm **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `description` | `string \| undefined` | — | no | Description of the form. Rendered under the heading through `CdsDescription`. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `firstFail` | `boolean \| undefined` | — | no | Stops the validation at the very first invalid field — the remaining fields are not checked | | `label` | `string \| undefined` | — | no | Heading of the form. Rendered above the content through `CdsDescription`. | | `modelValue` | `boolean \| null \| undefined` | `null` | no | Resulting validity of the form: `true` — every field passed the check, `false` — there are errors, `null` — the form has not been validated yet | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `validateOn` | `ValidateOn \| undefined` | `'input'` | no | When to run the validation of the form fields: on input, on blur or manually only | **Events** | Name | Type | Description | | --- | --- | --- | | `submit` | `[payload: SubmitEventPromise]` | Submission of the form. The event is a Promise with the validation result. | | `update:modelValue` | `[value: boolean \| null]` | The overall validity status of the form changed (v-model). | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ errors: FieldValidationResult[]; isDisabled: boolean \| null \| undefined; isReadonly: boolean \| null \| undefined; isValidating: boolean; isValid: boolean \| null \| undefined; items: FormField[]; validate: () => Promise; reset: () => void; resetValidation: () => void; }` | Main content of the form. Receives the current state and the validation methods. | | `description` | `any` | Description of the form (overrides the `description` prop). | | `label` | `any` | Heading of the form (overrides the `label` prop). | **Exposed** | Name | Type | Description | | --- | --- | --- | | `errors` | `{ id: string \| number; errorMessages: string[]; }[]` | Validation errors of the form fields: the identifier of a field and its error messages. | | `isDisabled` | `boolean \| null \| undefined` | Whether all the fields of the form are blocked. | | `isReadonly` | `boolean \| null \| undefined` | Whether the fields of the form are read-only. | | `isValid` | `boolean \| null \| undefined` | Validity of the form: `true` — every field passed the check, `false` — there are errors, `null` — the form has not been validated yet. | | `isValidating` | `boolean` | Whether the form is being validated right now. | | `items` | `{ id: string \| number; validate: () => Promise; reset: () => Promise; resetValidation: () => Promise; vm: Raw; isValid: boolean \| null; errorMessages: string[]; }[]` | The fields registered in the form together with their validation state. | | `resetValidation` | `() => void` | Resets the validation state only, keeping the entered values. | | `validate` | `() => Promise<{ valid: boolean; errors: FieldValidationResult[] \| { id: string \| number; errorMessages: string[]; }[]; }>` | Runs the validation of all the form fields and returns the result together with the list of errors. | --- # CdsFunctionalButton _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 15/15 · 6 unit · lines 100% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ A functional button is a utility action next to the content: download a file in a row of a list, reveal a password in a field, collapse a block, open the menu of a record. It is a CdsButton with `size="sm"`, `variant="soft"` and `color="neutral"` fixed in place: the background is transparent and appears only on hover, so the button does not compete for attention with the content it stands next to. **See also:** Style the primary action of the screen — "Save", "Submit the request" — with CdsButton, and a navigation inside a paragraph with CdsLink. If the icon triggers nothing and only explains the content, leave it as CdsIcon. ## Variations ### Icon The `icon` prop sets the icon — the usual look of a functional button. Such a button has no text, so add an `aria-label`: it stays the only name of the action. **Example — `Icons.vue`:** ```vue ``` ### Content The `default` slot replaces the icon with your own content — a short label for an action that an icon cannot explain, for example. **Example — `Content.vue`:** ```vue ``` ### States The `loading` prop shows the progress of an operation instead of the icon, `disabled` dims the button and forbids pressing it, and `readonly` keeps the button looking regular but takes it out of the focus order and blocks the click. **Example — `States.vue`:** ```vue ``` ### Button as a link Pass `href` (or `to` with a `RouteLocationRaw` object from vue-router) — the button renders as an `a` tag with all the link attributes, keeping its look. **Example — `Link.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The primary action of the screen is a regular button: it is visible and hard to miss. | A functional button blends into the text and does not read as the primary action. | | Два-три частых действия рядом, остальные — под кнопкой «Ещё». | A row of identical icons takes long to read, and the right one has to be found by trial. | | A button without text has an aria-label — the screen reader names the action. | Без подписи кнопка звучит как «кнопка», а редкое действие не угадать и по иконке. | ## Scenarios ### Actions in a row of a list Download and delete are actions on a particular record, not on the screen. The buttons stand at the right edge of the row, and an `aria-label` with the name of the document tells the buttons of the neighboring rows apart. **Example — `RowActions.vue`:** ```vue ``` ### A button inside an input In the `append-inner` and `prepend-inner` slots of the inputs a functional button fits the size of the field exactly. Here it toggles `type` between `password` and `text`, and the `aria-label` changes together with the icon. **Example — `PasswordToggle.vue`:** ```vue ``` ### Copying a value A button next to a value copies it into the clipboard: `loading` shows the short operation, and the `check` icon confirms the result and turns back into `copy` a couple of seconds later. **Example — `CopyValue.vue`:** ```vue ``` ### Collapsing a block A chevron expands and collapses a section: the icon changes together with the state, and `aria-expanded` reports it to the screen reader. **Example — `Collapsible.vue`:** ```vue ``` ## API ### CdsFunctionalButton **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 | | `color` | `string \| undefined` | — | no | Component color | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `icon` | `IconValue \| undefined` | — | no | Icon | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `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 | | `tag` | `string \| JSXComponent \| undefined` | `'button'` | no | Custom HTML tag or component to render | | `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 | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content inside the button | | `loader` | `any` | Loading indicator | --- # CdsGrid _Category: Layouts · since 4.0.0_ _Tests: API 18/18 · 29 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A responsive modular grid: `CdsGrid`, `CdsRow` and `CdsCol` lay the content out in columns — from 4 on a phone to 16 on wide screens. The grid works in two modes — Flexbox (the default) and CSS Grid — and the whole markup is also available as ready-made CSS classes, without a single component. **See also:** The grid lays out the content inside a page. Build the frame of the application — the header, the drawers and the footer — from CdsLayout. ## Anatomy Every layout starts with `CdsGrid` — the container can sit at any nesting level as long as it takes the full width of its parent. Inside a Flexbox grid the `CdsCol` columns are grouped into `CdsRow` rows; in CSS Grid mode the rows are not needed — the columns wrap on their own. ## Variations ### Flexbox or CSS Grid By default the grid is built on Flexbox. The second mode — CSS Grid — is turned on once for the whole application by the `cssGrid` option and adds capabilities Flexbox does not have: nested `subgrid` grids and explicit positioning of the columns through `span`, `start` and `end`. In exchange, the Flexbox mode can change the order of the columns through `order`. ```ts import { createCds } from '@central-design-system/components'; const cds = createCds({ cssGrid: true }); ``` The components and the props are the same in both modes, only the generated markup differs. In the examples below the CSS Grid mode is turned on locally — through `provide(CssGridSymbol, true)`; in an application the `cssGrid` option is enough. ### Columns and breakpoints The width of a column is set by the `xs`–`xl` breakpoint props: the number says how many grid columns `CdsCol` takes starting from that breakpoint. The values work "bottom-up": `md="4"` applies to `md` and wider. **Example — `Basic.vue`:** ```vue ``` The number of columns in the grid depends on the width of the screen, so the same number takes a different share of the row on different breakpoints: | Breakpoint | Screen width | Columns in the grid | | ---------- | ------------ | ------------------- | | `xs` | ≥ 320px | 4 | | `sm` | ≥ 672px | 8 | | `md` | ≥ 1056px | 16 | | `lg` | ≥ 1312px | 16 | | `xl` | ≥ 1584px | 16 | Combine the breakpoints to describe the behavior of the layout on every screen: here each column takes half of the row on a phone and a quarter starting from a tablet. The value `0` hides the column on a breakpoint. **Example — `Responsive.vue`:** ```vue ``` ### Automatic columns A `CdsCol` without breakpoint props splits the row evenly with its neighbors: one column takes the whole width, four take a quarter each. Handy when the shares are equal and there is no point in recalculating them per breakpoint. Works in Flexbox mode only. **Example — `AutoColumns.vue`:** ```vue ``` ### Grid modes The `narrow` and `condensed` props shrink the gap between the columns from 32px to 16px and 1px respectively. `CdsRow` has the same props — that is how the modes are mixed inside one grid. The `wide` prop removes the maximum width limit (1584px) and stretches the grid across the whole container. **Example — `Modes.vue`:** ```vue ``` ### Offset and order Instead of a number, a breakpoint prop can take an object. The `span` key sets the width, `offset` shifts the column to the right by the given number of columns. **Example — `Offset.vue`:** ```vue ``` The `order` key changes the visual order of the columns without touching the markup — to show the columns on a desktop in a different sequence than in the DOM, for example. Works in Flexbox mode only. **Example — `Order.vue`:** ```vue ``` ### CSS Grid mode In CSS Grid mode the columns go straight into `CdsGrid` — without `CdsRow`: the grid wraps them onto a new line itself when the row is full. **Example — `CssGrid.vue`:** ```vue ``` A nested grid with the `subgrid` prop inherits the columns of its parent: put it inside a `CdsCol` and its columns line up exactly with the lines of the outer grid. The `narrow` and `condensed` modes of a nested grid work independently from the root one. **Example — `Subgrid.vue`:** ```vue ``` A column can be positioned explicitly: in a breakpoint object `start` and `end` set the starting and the ending grid line, and the `span` prop fixes the range for all breakpoints at once — as a number or as a share: `'25%'`, `'50%'`, `'75%'`, `'100%'`. **Example — `SpanStartEnd.vue`:** ```vue ``` ### CSS classes The whole grid is duplicated with utility classes — lay a layout out without Vue components: in emails, on static pages or inside somebody else's code. The components generate the same classes, so both ways mix freely. **Example — `Classes.vue`:** ```vue ``` Classes of the Flexbox grid: | Class | Purpose | | -------------------------------------------- | -------------------------------------------------- | | `cds-grid` | Grid container | | `cds-grid-narrow` / `cds-grid-condensed` | Narrow (16px) and condensed (1px) gap | | `cds-grid--wide` | No maximum width limit | | `cds-row` | Row; `cds-row-narrow`, `cds-row-condensed` — modes | | `cds-col-{bp}-{n}` | Column `n` wide on the `bp` breakpoint and wider | | `cds-col-{bp}` / `cds-col-{bp}-auto` | Automatic column / width by content | | `cds-offset-{bp}-{n}` | Shift to the right by `n` columns | | `cds-order-{bp}-{n}` | Visual order of the column | | `cds-row-padding` / `cds-col-padding` | Vertical paddings equal to half of the gutter | | `cds-aspect-ratio cds-aspect-ratio--{w}x{h}` | Aspect ratio of a block: `16x9`, `4x3`, `1x1`, … | Classes of the CSS Grid mode: | Class | Purpose | | ----------------------------------------- | ---------------------------------------------- | | `cds--css-grid` | Container; `--narrow`, `--condensed`, `--wide` | | `cds--css-grid-column` | Column | | `cds--col-span-{n}` | Range of `n` columns on all breakpoints | | `cds--{bp}:col-span-{n}` | Range starting from the `bp` breakpoint | | `cds--col-span-{25\|50\|75\|100}` | Range as a share of the grid | | `cds--col-start-{n}` / `cds--col-end-{n}` | Starting and ending line | | `cds--subgrid` | Nested grid; modes — `--narrow` and so on | The `cds-no-gutter` and `cds-no-gutter--start` / `cds-no-gutter--end` classes remove the paddings of the columns — for the whole row or on one side. Their counterparts `cds-hang--start` / `cds-hang--end` give the padding back to the content when it has to be aligned to the modular grid. **Example — `NoGutter.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The spans of a row add up to the full width of the grid — 16 columns. | Spans adding up to more than 16 wrap a column onto a new line and break the row. | | The content stretches together with the column and survives a change of breakpoint. | A fixed width argues with the grid and overflows the column on narrow screens. | ## Scenarios ### Card tiles A showcase of reports: on a phone the cards go in a column, on a tablet two per row, on a wide screen four in a row. The `cds-row-padding` class gives the vertical gap between the rows of the tiles. **Example — `Cards.vue`:** ```vue ``` ### Two-column form The grid lays out the fields of a form: the paired fields (`sm="4" md="8"`) split the row in half starting from a tablet, while the comment and the buttons take the whole row. On a phone everything folds into a single column with no extra conditions. The vertical rhythm comes from the `py-1` utility classes on the columns — tighter than `cds-row-padding` — and `hide-details` on the controls removes the reserved area for messages. **Example — `FormLayout.vue`:** ```vue ``` ### List with filters The classic "filters on the left, results on the right" proportion: the panel takes 4 columns, the list takes 12. On a phone and a tablet the filters stand above the list — that is what the full-width `xs` and `sm` values are for. **Example — `SidebarFilters.vue`:** ```vue ``` ## API ### CdsGrid **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `condensed` | `boolean \| undefined` | — | no | Condensed grid. The gap is reduced to 1px on both sides | | `narrow` | `boolean \| undefined` | — | no | Narrow grid | | `subgrid` | `boolean \| undefined` | — | no | Only CSS Grid supported. A nested grid | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `wide` | `boolean \| undefined` | — | no | Removes the default max-width and stretches the grid across the whole width of the container | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Rows of the grid — `CdsRow` | ### CdsCol **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `lg` | `ColumnBreakpoint` | — | no | >1312px | | `md` | `ColumnBreakpoint` | — | no | >1056px | | `sm` | `ColumnBreakpoint` | — | no | >672px | | `span` | `string \| number \| ColumnSpanType \| undefined` | — | no | Only CSS Grid supported. A permanent column range, start or end values that never change. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `xl` | `ColumnBreakpoint` | — | no | >1584px | | `xs` | `ColumnBreakpoint` | — | no | >320px | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the column | ### CdsRow **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `condensed` | `boolean \| undefined` | — | no | Condensed grid. The gap is reduced to 1px on both sides | | `narrow` | `boolean \| undefined` | — | no | Narrow grid | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Columns of the row — `CdsCol` | --- # CdsHeader _Category: Layouts · since 4.0.0_ _Tests: API 12/12 · 21 unit · lines 100% (v4.0.0-alpha.13) · a11y: 6 axe recommendations (v4.0.0-alpha.11)_ The header of the application: the title, the global search, notifications, the profile — everything that has to be at hand on any screen. The layout measures its height itself and reserves the space, so the content never ends up under the header. **See also:** The header works only inside CdsLayout — outside the layout it renders nothing and warns about it in the console. The content of the header is laid out by CdsToolbar, and the bottom bar of the application is built by CdsFooter. ## Variations ### Separator The header overlaps the scrollable content, so its edge is worth marking: `bordered` draws a border, `elevated` casts a shadow. The shadow is more noticeable and suits long lists better, the border suits calm pages. **Example — `Separators.vue`:** ```vue ``` ### Height The height comes from the content: the layout measures the header and reserves exactly as much space as it takes. The `height` prop is an initial estimate before the first measurement: set the expected height so the content does not jump on mount. **Example — `Height.vue`:** ```vue ``` ### Color The `bg-color` prop paints the background of the header with a palette alias, `color` paints the text and the icons inside. If only the background is set, the text color is picked to be contrasting automatically. **Example — `Colors.vue`:** ```vue ``` ### Floating mode The `reveal` prop hides the header when scrolling down and brings it back when scrolling up — on long lists this gives the screen to the content. The `reveal-offset` prop sets the zone near the top of the page where the header stays in place. The `@reveal` event reports the change of visibility, and moving the keyboard focus inside a hidden header brings it back. **Example — `Reveal.vue`:** ```vue ``` ### Visibility The `model-value` prop removes the header entirely: the layout stops reserving space for it and the content takes the freed height. This is a handy way to hide the header in full-screen modes — document viewing, a presentation. **Example — `Visibility.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A border or a shadow separates the header from the content — while scrolling you can see where it ends. | Without a separator the content slides under the header and blends into it. | | The header holds the title and one or two constantly needed actions. | A header crammed with buttons stops being an anchor and squeezes out the title. | ## Scenarios ### Application header The basic set: a menu button, a logo, the title in `CdsToolbarTitle` and the actions on the right. `CdsToolbarTitle` stretches and pushes the left and the right groups to the edges, so no extra spacers are needed. **Example — `AppBar.vue`:** ```vue ``` ### Header with tabs Two `CdsToolbar` components in a row turn the header into a two-level one: the name of the section on top, CdsTabs with the subsections below. The tabs stay on the screen together with the header, so you can switch from any point of the list. **Example — `HeaderTabs.vue`:** ```vue ``` ## API ### CdsHeader **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `bordered` | `boolean \| undefined` | `false` | no | Shows the border. | | `color` | `string \| undefined` | — | no | Component color | | `elevated` | `boolean \| undefined` | `false` | no | Shows the shadow. | | `height` | `string \| number \| undefined` | `50` | no | Height of the element. | | `modelValue` | `boolean \| undefined` | `true` | no | Visibility of the element in the layout. | | `reveal` | `boolean \| undefined` | `false` | no | Floating mode: the element appears/hides on scroll. | | `revealOffset` | `number \| undefined` | `250` | no | Scroll threshold (px) up to which the floating element stays visible. | | `theme` | `string \| undefined` | — | no | Component theme | **Events** | Name | Type | Description | | --- | --- | --- | | `focusin` | `[event: FocusEvent]` | Focus moved inside the header. | | `reveal` | `[value: boolean]` | Visibility of the floating header has changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the header (`CdsToolbar` and others). | --- # CdsHighlight _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 9/9 · 16 unit · lines 100% (v4.0.0-alpha.13) · a11y: 2 axe recommendations (v4.0.0-alpha.11)_ Highlighting explains why a row made it into the results: the component finds the matches with the query (`query`) or with ready ranges (`matches`) in the text and wraps them into `mark`. Take it for search results, autocomplete suggestions and filtered lists. **See also:** In CdsAutocomplete, CdsCombobox and CdsSelect the highlighting of the matches is already built in — a standalone `CdsHighlight` is not needed there. For a permanent label next to the text take CdsTag, for a counter take CdsBadge. ## Variations ### Search query The `text` prop takes the source string, `query` takes what the user was looking for. The query can be a string or an array of terms: all of them get highlighted. **Example — `Query.vue`:** ```vue ``` ### All occurrences By default the first occurrence of every term is highlighted. The `match-all` prop highlights all of them — in a long text this shows the full picture. **Example — `MatchAll.vue`:** ```vue ``` ### Case The `ignore-case` prop looks for matches regardless of the case. You need it almost always when the query is typed by the user. **Example — `IgnoreCase.vue`:** ```vue ``` ### Ready ranges When the matches are found by the server rather than by the browser, pass them into `matches` — an array of `[start, end]` pairs by the indexes of the source string. The ranges take precedence over `query`, and overlapping ones are merged automatically. **Example — `Matches.vue`:** ```vue ``` ### Color and density The `color` prop sets the color of the highlighting — the background is tinted with it too, so a single value is enough. `opacity` changes the density of the background. **Example — `Colors.vue`:** ```vue ``` ### Markup The `tag` prop sets the tag of the wrapper (`span` by default), `mark-class` adds your own class to every match. **Example — `Tag.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Only what the user searched for is highlighted — it is clear why the row made it into the results. | The whole row is highlighted: the highlighting stops highlighting anything. | | In a long text turn on match-all: the user sees every match at once. | Only the first occurrence is highlighted — it looks like there are no matches further on. | | For a query typed by the user turn on ignore-case — they do not double-check the case. | Без ignore-case запрос «инн» не находит «ИНН», и совпадение теряется. | ## Scenarios ### Searching through a list The same query filters the list and highlights the matches in the found rows. `match-all` and `ignore-case` keep the highlighting and the filter consistent: once a row made it into the results, the match inside it is visible. **Example — `SearchResults.vue`:** ```vue ``` ### A query of several words Split the typed phrase into words and pass them as an array into `query` — the component highlights every word separately, even if they stand far apart in the text. **Example — `WordSearch.vue`:** ```vue ``` ### Matches from the server The full-text search on the backend already knows which fragments count as matches: it accounts for morphology, synonyms and typos. Give those ranges to `matches` — the client will not search anything again. **Example — `ServerRanges.vue`:** ```vue ``` ## API ### CdsHighlight **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the highlighted text. | | `ignoreCase` | `boolean \| undefined` | — | no | Ignores the case when searching by `query`. | | `markClass` | `string \| undefined` | — | no | Extra CSS class for the `` element. | | `matchAll` | `boolean \| undefined` | — | no | Highlights every occurrence, not just the first one. | | `matches` | `readonly MatchRange[] \| undefined` | — | no | Ready match ranges `[start, end]`. They take precedence over `query`. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the highlight background (the `--cds-highlight-opacity` CSS variable). | | `query` | `string \| string[] \| undefined` | — | no | Search query: a string or an array of term strings. | | `tag` | `string \| JSXComponent \| undefined` | `'span'` | no | Custom HTML tag or component to render | | `text` | `string \| undefined` | `''` | no | The text the highlighting is performed in. | --- # CdsIcon _Category: Content · since 4.0.0_ _Tests: API 15/15 · 24 unit · 4 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ An icon is a short visual mark next to the text: the status of a record, the type of a file, the direction of a transition. The component takes an icon by name from a connected pack and subordinates its size, color and spacing to the design system tokens. **See also:** Inside other components you do not assemble an icon separately: CdsButton, CdsTextInput, CdsList and others have the `icon`, `prepend-icon` and `append-icon` props. For a standalone action take CdsFunctionalButton — an icon button with a label and states. All the available icons are in the gallery, and connecting your own pack is described in the guide. ## Variations ### Icon The `icon` prop takes the name of an icon from the default pack — `add` or `search`, for example. The `name` prop does the same and reads more naturally when the icon is set by a string. Besides a name, `icon` also accepts an icon component and an array of SVG paths, so you can pass your own graphics into it. **Example — `Default.vue`:** ```vue ``` An icon from another connected pack is written with the prefix of that pack — `i-ri:settings-3-line`. How to connect a pack is described in the icons guide. ### Sizes The `size` prop takes one of the scale values — from `xs` to `xl` — or a number in pixels when the icon works as an illustration. The default is `md`, level with the body text. **Example — `Sizes.vue`:** ```vue ``` ### Color Without `color` the icon inherits the text color of its parent — this is the default behavior and the right one in most cases. The `color` prop takes a palette token (`content-secondary`, `brand-primary`), a status color alias (`green`, `red`, `lemon`) or a `hex/rgb` value. The `opacity` prop mutes the icon without changing its color. **Example — `Colors.vue`:** ```vue ``` ### Spacing from the text The `start` and `end` props add spacing on the side of the text: `start` for an icon before the label, `end` for one after it. This saves you from picking margins by hand. **Example — `Spacing.vue`:** ```vue ``` ### Reacting to a click If you attach a `@click` handler to an icon, it gets `role="button"`, joins the Tab order and changes the cursor; `disabled` removes it from the order and stops it from accepting clicks. This is handy for small toggles inside your own components — for a full-fledged action CdsFunctionalButton fits better. **Example — `Clickable.vue`:** ```vue ``` ### Slot The name of the icon can be passed as text into the default slot — the result is the same as with `icon`. Useful when the name comes from an expression in the template. **Example — `WithSlot.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The icon stands next to a label and speeds up reading the line. | Without a label the icon has to be decoded: does a check mark mean «paid» or «verified»? | | The color comes from the palette — the icon follows the theme and stays readable. | An arbitrary color falls out of the theme: on a dark background such an icon gets lost. | | A clickable icon is a button: it has a name, hover states and keyboard focus. | A handler on an icon gives you a pointer cursor, but no name for a screen reader and no visible hover response. | ## Scenarios ### Statuses in a list An icon to the left of a label sets the status by color and shape, while the text names it in words. The colors come from the status aliases, `size="sm"` fits the icon to small text, and `start` adds the spacing before the label. **Example — `StatusList.vue`:** ```vue ``` ### List of attachments The icon shows the type of a file and keeps the eye on the left edge of the list. The `lg` size makes it more noticeable than the label, and the `content-secondary` color keeps it from competing with the file name. The action next to it is already a button: `CdsFunctionalButton` with an `aria-label`. **Example — `FileList.vue`:** ```vue ``` ### Progress of an operation The icon reflects the state of a process: the request is ready, is being sent, has been sent. Only `icon` and `color` change — the component repaints in place and the status line does not jump. **Example — `SubmitFlow.vue`:** ```vue ``` ### A note inside text Inside a paragraph the icon aligns to the middle of the line, so you can put it right into the text. The `sm` size and `start` keep it from breaking the line. **Example — `InlineNote.vue`:** ```vue ``` ## API ### CdsIcon **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 | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `end` | `boolean \| undefined` | — | no | Adds spacing to the left of the icon — for an icon after the text | | `icon` | `IconValue \| undefined` | — | no | Name of the icon or the icon component to render | | `name` | `string \| undefined` | — | no | String name of an icon from a registered pack (an alias for icon) | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the icon — a number between 0 and 1 | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `start` | `boolean \| undefined` | — | no | Adds spacing to the right of the icon — for an icon before the text | | `tag` | `string \| JSXComponent \| undefined` | `'i'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Name of the icon as text — an alternative to the `icon` prop | --- # CdsImage _Category: Content · since 4.0.0_ _Tests: API 39/39 · 51 unit · 1 known bug · lines 95.3% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ An image that knows how to wait. The component reserves space in the layout according to the given proportions, loads the file when the picture enters the viewport, and shows a placeholder while it is on its way. Over the image you can lay a gradient and any content — a caption, a tag, a button. **See also:** For a photo of a person or a company logo in a round frame take CdsAvatar, for interface pictograms — CdsIcon. If the proportions have to be set not for a picture but for an arbitrary block — a video, a map, an iframe — use CdsResponsive, and a slideshow of several images is assembled by CdsCarousel. ## Anatomy The first diagram is a loaded image: the container holds the size and the proportions, the `img` tag sits inside, and an optional gradient lies on top. The second one is the same place while the file has not arrived yet: a blurred placeholder from `lazy-src` and the content of the `placeholder` slot. ## Variations ### Size and proportions The minimum needed to show a picture is `src` and one size constraint: `width`, `height`, `max-width` or `max-height`. The `alt` prop describes the image for readers with screen readers and goes into the `aria-label` of the container. **Example — `Default.vue`:** ```vue ``` The `aspect-ratio` prop reserves the space for the image before it loads — the neighboring content will not jump. The value is accepted both as the fraction `16/9` and as the number `1.7778`. Without it the component waits for the file and takes the proportions from its own dimensions — and if the file fails to open, the space for the picture collapses. **Example — `AspectRatio.vue`:** ```vue ``` ### Filling the container By default the image fits into the container as a whole (`object-fit: contain`) and leaves margins when the proportions do not match. The `cover` prop does the opposite: it fills the frame and crops the excess — this way photos of different sizes line up into an even grid. **Example — `Cover.vue`:** ```vue ``` The `position` prop sets which part of the frame stays visible when cropping. It accepts any `object-position` value, including pairs like `left top` and percentages. **Example — `Position.vue`:** ```vue ``` ### Loading The image starts loading when it enters the viewport — markup below the fold does not drag dozens of files along with it. The observation thresholds are configured by the `options` prop (the `IntersectionObserver` options), and `eager` turns the waiting off and loads the picture right away — which is what you should do with the images of the first screen. While the file is on its way, the component shows `lazy-src` — a thumbnail of the same frame, stretched and blurred — and the content of the `placeholder` slot. The `color` prop sets the color of the backdrop under them. The `loadstart` and `load` events report the progress of the loading. **Example — `Loading.vue`:** ```vue ``` ### Loading error If the file failed to open, the component shows the `error` slot and reports it with the `error` event. Without that slot the `placeholder` stays in place of the picture — so for an error it is better to give your own fallback with a clear text. **Example — `Error.vue`:** ```vue ``` ### Gradient The `gradient` prop lays a CSS gradient over the image — the value is passed as the arguments of `linear-gradient()`. Usually you need it to keep the text over a photo readable on any frame. **Example — `Gradient.vue`:** ```vue ``` ### Content over the image The default slot renders above the image and stretches over the whole container: you can put a caption, a tag or a button inside. Set the layout with utilities on the component itself (`items-end`, `justify-center`) or through `content-class`. **Example — `Overlay.vue`:** ```vue ``` ### Responsive sources The `srcset` and `sizes` props go straight into the `img` tag — the browser picks the file for the pixel density and the width of the place itself. When a narrow screen needs not just a smaller file but a different frame, add `` elements into the `sources` slot: the component wraps the image into ``. Narrow the window — in the example the wide panorama gives way to a vertical frame. **Example — `Sources.vue`:** ```vue ``` ### Slots | Slot | Description | | :------------ | :---------------------------------------------------- | | `default` | Content over the image | | `placeholder` | What to show while the image is loading | | `error` | What to show when the image failed to load | | `sources` | `` elements; wraps the image into `` | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The same aspect-ratio and cover keep the row even, even when the sources differ in size. | Without set proportions every picture pulls its own height and the row falls apart. | | Show diagrams, plans and logos in full — without cover. | cover crops the edges and part of the diagram is lost. | | A gradient under the text holds the contrast on any picture. | Text placed straight on a photo blends into the light areas. | ## Scenarios ### Catalog cards Listing covers come from different sources and almost never match in size. A shared `aspect-ratio` and `cover` bring them to one frame, `color` holds a neutral backdrop while the file is loading, and the default slot leaves a tag in the corner of the cover. **Example — `ListingCards.vue`:** ```vue ``` ### Page cover A wide header with text over a photo: `height` sets the height of the band, `cover` and `position` crop the shot to fit it, and `gradient` darkens the bottom so that the title and the button stay readable. Such a picture needs `eager` — it is on the first screen and has no reason to wait for the viewport. **Example — `HeroBanner.vue`:** ```vue ``` ### Gallery with previews A click on a thumbnail changes the `src` of the large image. The thumbnails get a shared `aspect-ratio` and `cover`, so the row stays even, and `color` holds the backdrop of the large frame while the new file is loading. If the frames also have to be flipped — with arrows or a swipe — take the ready-made “Gallery with thumbnails” scenario of CdsCarousel. **Example — `Gallery.vue`:** ```vue ``` ## API ### CdsImage **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `absolute` | `boolean \| undefined` | — | no | Positions the image with `position: absolute`, filling its parent. | | `alt` | `string \| undefined` | — | no | Alternative text of the image (the `alt` attribute). | | `aspectRatio` | `string \| number \| undefined` | — | no | Aspect ratio of the content. For example `1.7778` (16/9) or `'4/3'`. | | `color` | `string \| undefined` | — | no | Background color of the placeholder shown while loading. | | `contentClass` | `any` | — | no | CSS class applied to the content wrapper. | | `cover` | `boolean \| undefined` | — | no | Scales the image so that it covers the whole container (`object-fit: cover`). | | `crossorigin` | `"" \| "anonymous" \| "use-credentials" \| undefined` | — | no | Value of the `crossorigin` attribute. | | `draggable` | `boolean \| "true" \| "false" \| undefined` | — | no | Controls whether the image can be dragged (the `draggable` attribute). | | `eager` | `boolean \| undefined` | — | no | Loads the image immediately instead of waiting for it to enter the viewport. | | `gradient` | `string \| undefined` | — | no | CSS gradient laid over the image. For example `'to top, rgba(0,0,0,.4), transparent'`. | | `height` | `string \| number \| undefined` | — | no | Component height | | `imageClass` | `any` | — | no | CSS class applied to the inner `` element. | | `inline` | `boolean \| undefined` | — | no | Renders the component as an inline block (`inline-flex`) instead of a block one. | | `lazySrc` | `string \| undefined` | — | no | Source of the low-quality placeholder image shown until the main one loads. | | `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 | | `options` | `IntersectionObserverInit \| undefined` | `{}` | no | `IntersectionObserver` options for lazy loading. | | `position` | `string \| undefined` | — | no | Value of `object-position` that places the image inside the container. | | `referrerpolicy` | `"origin" \| "no-referrer" \| "no-referrer-when-downgrade" \| "origin-when-cross-origin" \| "same-origin" \| "strict-origin" \| "strict-origin-when-cross-origin" \| "unsafe-url" \| undefined` | — | no | Value of the `referrerpolicy` attribute. | | `sizes` | `string \| undefined` | — | no | Value of the `sizes` attribute for responsive images. | | `src` | `string \| CdsImageSrcObject \| undefined` | `''` | no | Image source. A string or an object with `src`/`srcset`/`lazySrc`/`aspect`. | | `srcset` | `string \| undefined` | — | no | Set of image sources for different resolutions (the `srcset` attribute). | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'fade-transition'` | no | Transition animation | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `error` | `[value: string \| undefined]` | Fires when the image fails to load. | | `load` | `[value: string \| undefined]` | Fires after the image has loaded successfully. | | `loadstart` | `[value: string \| undefined]` | Fires when the image starts loading. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content shown over the image. | | `error` | `any` | Content shown when the image fails to load. | | `placeholder` | `any` | Content shown while the image is loading. | | `sources` | `any` | Extra `` elements for the `` tag. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `currentSrc` | `string` | Actual address of the loaded image — taking `srcset` and the density chosen by the browser into account. | | `image` | `HTMLImageElement \| undefined` | Reference to the `img` DOM element. | | `naturalHeight` | `number \| undefined` | Natural height of the loaded image in pixels. | | `naturalWidth` | `number \| undefined` | Natural width of the loaded image in pixels. | | `state` | `"error" \| "loading" \| "idle" \| "loaded"` | Loading state of the image: idle, loading, success or error. | --- # CdsInput _Category: Atoms · since 4.0.0_ _Tests: API 52/52 · 59 unit · 5 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ The wrapper of an input: the label, the description, the outer icons, the block of messages and the validation by rules. You put the control itself into the `default` slot — usually a CdsField with your `input` inside. **See also:** For regular input take the ready-made fields — CdsTextInput, CdsSelect, CdsTextArea: they are already assembled from `CdsInput` and `CdsField`. `CdsInput` is needed when your control is not in the library. ## Anatomy `CdsInput` lays out on a grid the label (CdsLabel), the description (CdsDescription), the outer icons, your control and the block of messages (CdsMessages). The `default` slot gives out `id`, `messagesId` and the validation states — all of them are refs, so reach for `id.value` in the template. ## Variations ### Label and description The `label` prop names the field, `description` adds an explanation under the label. The slots of the same names accept arbitrary markup. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Messages and hints There is a single line of text under the field, and the props split it by states: `messages` is visible at rest, `hint` while `focused`, and `error-messages` on top of the rest. `CdsInput` does not track the focus state itself: pass it with the `focused` prop. **Example — `Messages.vue`:** ```vue ``` ### Hiding the details The `hide-details` prop removes the bottom block entirely — the fields can be placed tight against each other. The `auto` value hides the block only while there is nothing to show. **Example — `HideDetails.vue`:** ```vue ``` ### Icons The `prepend-icon` and `append-icon` props put an icon outside the control. Clicks on them are caught by `@click:prepend` and `@click:append`. **Example — `Icons.vue`:** ```vue ``` ### Direction The `direction` prop changes the grid: `horizontal` puts the icons on the sides of the control, `vertical` puts them above and below it. **Example — `Direction.vue`:** ```vue ``` ## Scenarios ### Validating your own field The `rules` prop accepts validation functions, `validation-value` accepts the value to pass to them. The result arrives in the slot through `isValid`: bind it to the `error` prop of `CdsField` and the frame turns red together with the message. **Example — `CustomControl.vue`:** ```vue ``` ## API ### CdsInput **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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 | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `centerAffix` | `boolean \| undefined` | `true` | no | Vertically center the appendInner, prependInner, clearIcon and label elements. | | `color` | `string \| undefined` | — | no | Component color | | `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 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 | | `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 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 | | `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 | | `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 | | --- | --- | --- | | `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` | `CdsInputSlot` | 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 | | `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 | **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 | --- # CdsLabel _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 7/7 · 10 unit · 2 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A label names a field — it says what is expected from the user. It renders as a `label` tag and binds to the control through `for`, so a click on the label moves the focus into the field. **See also:** The ready-made fields already have the label built in — the `label` prop of CdsTextInput and the other controls. A standalone `CdsLabel` is needed for groups of fields and for your own controls. The explanation under the label is added by CdsDescription. ## Variations ### Text The `text` prop sets the caption. The `default` slot accepts arbitrary markup — an icon with an explanation next to the text, for example. **Example — `Text.vue`:** ```vue ``` ### States The `disabled` and `readonly` props mute the label together with the field: both stop reacting to a click, and `disabled` also changes the color. **Example — `States.vue`:** ```vue ``` ## Scenarios ### A label for your own control The `for` prop takes the `id` of the control — the browser binds them itself: a click on the label sets the focus, and the screen reader reads the caption together with the field. **Example — `CustomControl.vue`:** ```vue ``` ## API ### CdsLabel **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `for` | `string \| undefined` | — | no | Identifier of the field the label belongs to — the value of the `for` HTML attribute | | `readonly` | `boolean \| null \| undefined` | `null` | no | Read-only state | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `text` | `string \| number \| undefined` | — | no | Text displayed in the component. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text of the label for the field | --- # CdsLayout _Category: Layouts · since 4.0.0_ _Tests: API 22/22 · 31 unit · 1 known bug · lines 85.6% (v4.0.0-alpha.13) · a11y: 13 axe recommendations (v4.0.0-alpha.11)_ The frame of the application: `CdsLayout` places the header, the side drawers, the content and the footer, measures their sizes and takes the scrolling over. The parts of the layout know about each other — the content never slides under the header and never hides behind a drawer. **See also:** The parts of the layout are described on their own pages: CdsHeader, CdsDrawer, CdsMain, CdsPage, CdsFooter and CdsToolbar. You can assemble the frame with the mouse and copy the ready code in the layout builder. ## Anatomy `CdsLayout` is the root element of the application. The parts of the layout go inside it: the header, the drawers, `CdsMain` with `CdsPage` and the footer. The order in the template does not matter — the layout calculates the positions itself. ## Variations ### The view scheme The `view` prop describes the layout with three strings: top, middle, bottom. The letters are the parts of the layout: `h` — the header, `f` — the footer, `l` and `r` — the left and the right drawer, `p` — the page. The corner letters of the top and the bottom string settle the argument over the corners: `hhh` gives the whole width to the header, `lhh` gives the top left corner to the drawer. **Example — `View.vue`:** ```vue ``` An uppercase letter gives the part `position: fixed`: `HHH lpr fff` nails the header to the window, `hhh LPR fff` nails both drawers. The default value is `hhh lpr fff`. ### Container mode By default the layout takes the whole page and controls its scrolling. The `container` prop locks it inside its parent: the layout gets its own scroll area, and the header and the footer keep their places inside it. This is a handy way to show the application in a preview, to embed it into somebody else's page or to build a working area of a fixed height. **Example — `ContainerMode.vue`:** ```vue ``` ### Events The layout watches its scroll area and shares what it sees: `@scroll` gives the position, the direction and the turning point, `@resize` gives the new sizes, `@scroll-height` gives the height of the content. The floating header and footer are built on these events, but you can use them for your own logic too — to load the next page of a list, for example. **Example — `Events.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The content lives in CdsMain → CdsPage: the layout reserves the space for the header and the drawers itself. | Content placed directly inside CdsLayout slides under the header — nobody calculates the paddings. | | The sections of the application belong in the side drawer: the list grows downwards and stays readable. | With every section in the header, they shrink as their number grows and stop fitting. | ## Scenarios ### Application shell The typical set: a header with `CdsToolbar`, permanent navigation in `CdsDrawer`, `CdsMain` → `CdsPage` with the content and a footer. A button in the header toggles `minified` — the drawer shrinks to icons and gives the width to the content, and on hover it expands back. **Example — `AppShell.vue`:** ```vue ``` ### A header that hides on scroll On long lists the space is worth more than the navigation. The `reveal` prop of the header and the footer hides them when scrolling down and brings them back when scrolling up; `reveal-offset` sets the zone near the top of the list where the header stays in place. **Example — `RevealOnScroll.vue`:** ```vue ``` ### Working area with filters The `lhh lpr fff` scheme gives the top left corner to the navigation — it starts from the very top, and the header takes the remaining width. The right drawer with `temporary` slides over the content on a button click and closes on a click on the overlay, so it takes no place in the layout. **Example — `WorkArea.vue`:** ```vue ``` ## API ### CdsLayout **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `container` | `boolean \| undefined` | `false` | no | Container mode: the layout scrolls inside itself instead of scrolling the page. | | `theme` | `string \| undefined` | — | no | Component theme | | `view` | `string \| undefined` | `'hhh lpr fff'` | no | Layout scheme of three strings: top (header), middle (left-page-right), bottom (footer). For example `'hhh lpr fff'`. | **Events** | Name | Type | Description | | --- | --- | --- | | `resize` | `[contentRect: Pick]` | The size of the layout area has changed. | | `scroll` | `[info: ScrollObserver]` | The layout area has been scrolled. | | `scrollHeight` | `[height: number]` | The height of the scrollable content has changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the layout: `CdsHeader`, `CdsDrawer`, `CdsMain`, `CdsFooter`. | **Exposed** | Name | Type | Description | | --- | --- | --- | | `animate` | `() => void` | Turns on the rebuild animation of the layout for the duration of the next size update. | | `containerHeight` | `number` | Height of the content area without the header and the footer, in pixels. | | `footer` | `LayoutPart` | Size and offset of the layout footer. | | `header` | `LayoutPart` | Size and offset of the layout header. | | `height` | `number` | Full height of the layout in pixels. | | `instances` | `Record` | Components registered in the layout by their identifiers — the header, the footer, the drawers, the content. | | `isContainer` | `boolean` | Whether the layout is limited in width by a container (`container`) instead of stretching across the whole screen. | | `left` | `LayoutPart` | Size and offset of the left drawer of the layout. | | `right` | `LayoutPart` | Size and offset of the right drawer of the layout. | | `rootRef` | `HTMLElement \| undefined` | Ref to the root DOM element of the layout. | | `rows` | `{ top: string[]; middle: string[]; bottom: string[]; }` | Identifiers of the components distributed across the rows of the layout: top, middle and bottom. | | `scroll` | `ScrollObserver` | Scroll state of the layout: position, direction and delta. | | `scrollbarWidth` | `number` | Width of the system scrollbar in pixels — taken into account when the scroll is locked. | | `totalWidth` | `number` | Full width of the layout in pixels. | | `update` | `(part: "left" \| "right" \| "footer" \| "header", prop: keyof LayoutPart, value: number \| boolean) => void` | Updates the size, the offset or the space reservation for a part of the layout. | --- # CdsLink _Category: Navigation · since 4.0.0_ _Tests: API 10/10 · 19 unit · 2 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 7 axe recommendations (v4.0.0-alpha.11)_ A link sends the user somewhere else: to a neighboring page of the application, to an external service or to an email address. Inside the application the path comes from the `to` prop and vue-router takes over the navigation; for outside destinations the address goes into `href`. **See also:** If the element triggers an action instead of a navigation — saves, deletes, opens a modal — take CdsButton. A button also accepts `href` or `to` when a navigation has to look like a button. The path through the hierarchy of sections is built by CdsBreadcrumbs, and sections of equal weight are switched by CdsTabs. ## Variations ### Link text The `text` prop sets the label as a string, the `default` slot as arbitrary markup — text with an icon, for example. The slot wins over the prop. **Example — `Content.vue`:** ```vue ``` ### Address The `href` prop renders a regular link. Attributes are written on the component just like on an `a` tag: `target="_blank"` opens the page in a new tab — mark such a link with an icon so that leaving the application does not come as a surprise. Visited links change color; anchors like `#section` stay as they are. **Example — `Href.vue`:** ```vue ``` ### Application route The `to` prop accepts a path or a vue-router route object: the navigation runs without a page reload, and on the active route the link gets `aria-current="page"`. The `replace` prop replaces the current history entry instead of adding a new one — so going "back" skips the intermediate screen. The `exact` prop treats the route as active only on a full match, not by prefix. ```vue ``` ### Disabled link The `disabled` prop dims the color and removes the navigation: the component cancels the click, sets `aria-disabled` and takes the link out of the Tab order. Explain nearby why the navigation is unavailable — the gray state alone does not name the reason. **Example — `Disabled.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The link text names where it leads — clear even outside the paragraph. | «Здесь» и «подробнее» ничего не обещают: цель перехода приходится угадывать. | | A link leads to a page, a button triggers an action. | A link that deletes data betrays the expectation of a navigation. | | The link is a short phrase inside the sentence; the rest of the text stays text. | A whole paragraph inside a link is hard to read, and the destination gets lost in the details. | ## Scenarios ### A link inside text Inside a paragraph the link covers exactly the phrase that names the destination. A `@click.prevent` handler keeps the user on the page and reveals the details in place, while `href="mailto:…"` opens the mail client. **Example — `InlineText.vue`:** ```vue ``` ### Result list The titles of the found documents are links: the user scans the list and opens the one they need. The text comes from the `text` prop, and the `click` handler shows the selected document without leaving the page. **Example — `SearchResults.vue`:** ```vue ``` ### Documents with restricted access The list shows all the documents of a procedure, but some of them are closed: `disabled` keeps their titles visible and blocks the navigation. The request access button lifts the restriction — the links come alive without reloading the list. **Example — `Restricted.vue`:** ```vue ``` ## API ### CdsLink **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `disabled` | `boolean \| undefined` | — | no | Disables the link: no navigation happens, aria-disabled and tabindex=-1 are set | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `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 | **Events** | Name | Type | Description | | --- | --- | --- | | `click` | `[e: MouseEvent]` | Click on the link | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Link content. Takes precedence over the text prop. | --- # CdsList _Category: Content · since 4.0.0_ _Tests: API 164/164 · 190 unit · 5 e2e · 15 known bugs · lines 98.3% (v4.0.0-alpha.13) · a11y: 35 axe recommendations (v4.0.0-alpha.11)_ A list shows a set of records of the same kind — menu sections, documents, employees, settings — so that the one you need is easy to find and pick. Build it from an `items` array in a single line, or from `CdsListItem` components when a row is more than a title with an icon. **See also:** To pick a value in a form, take CdsSelect; for a tree with checkboxes, async loading and drag and drop — CdsTree; for tabular data with columns — CdsTable. Inside CdsMenu, CdsSelect and CdsAutocomplete the list is already in use — there is no need to assemble it by hand. ## Anatomy The first diagram is the skeleton of a list: subheaders split it into sections, dividers separate blocks, groups reveal nested items. The second one is the structure of an item: the `prepend` and `append` areas on the sides and three text blocks between them. Every area is available both as a prop (`prepend-icon`, `title`) and as a slot of the same name. ## Variations ### List data The `items` prop takes an array of objects and builds the whole list out of it. The `title` field gives the heading, `value` — the value of the item (this is how the list knows what is selected), `props` — any props of `CdsListItem`. **Example — `Items.vue`:** ```vue ``` When the data arrives from the server in its own format, do not reshape it: `item-title`, `item-value` and `item-children` tell the list which fields to take. Each of them accepts both a field name and a function — that way, for example, `item-props` assembles the props of an item from several fields of the object. **Example — `CustomItems.vue`:** ```vue ``` The `props` field configures a single item: adds icons, turns on the active state or disables the row. **Example — `ItemProps.vue`:** ```vue ``` ### Item content An item has three text blocks: `title` names the record, `subtitle` refines it, `description` adds an explanation. On the sides stand an icon (`prepend-icon`, `append-icon`) or an avatar (`prepend-avatar`, `append-avatar`). **Example — `ItemContent.vue`:** ```vue ``` The `lines` prop limits the subtitle and the description to one, two or three lines — the rest of the text is truncated with an ellipsis, and records with text of different length keep a common rhythm. With `three`, the icons in the `prepend` and `append` areas align to the top of the record instead of its center. `:lines="false"` removes the limit — the text takes as many lines as it needs. **Example — `Lines.vue`:** ```vue ``` ### Structure Items with `type: 'subheader'` and `type: 'divider'` split the list into sections: a subheader names a group of records, a divider separates blocks without a heading. **Example — `SubheaderAndDivider.vue`:** ```vue ``` A `children` array inside an item turns it into an expandable group — the list manages its state on its own, and `v-model:opened` lets you manage it from the outside. Nesting is not limited to a single level. **Example — `Nested.vue`:** ```vue ``` ### Selection and activation The `activatable` prop highlights one item as the current one — this is about navigation: "you are here". `selectable` turns on picking records — this is about data: "send these ones". Both states are read through `v-model:activated` and `v-model:selected`, and `select-strategy` sets how many items can be picked at once: `single-leaf` (the default) — one, `independent` — as many as you like. **Example — `Selection.vue`:** ```vue ``` ### Appearance `nav` rounds the corners of active items — the look of a side menu. `slim` removes the inner paddings when the list sits in a narrow panel or a dropdown. `color` sets the color of active items, `bg-color` — the background of the list. **Example — `Appearance.vue`:** ```vue ``` ### Assembling from components When a row is more than a title with an icon, assemble it from `CdsListItem` by hand — the slots accept any components: tags, badges, avatars, buttons. | Slot name | Description | | :------------ | :-------------------------------------------------- | | `prepend` | Content of the area before the text | | `title` | Content of the heading (replaces `title`) | | `subtitle` | Content of the subtitle (replaces `subtitle`) | | `description` | Content of the description (replaces `description`) | | `append` | Content of the area after the text | | `default` | Arbitrary markup inside the item, below the text | **Example — `Slots.vue`:** ```vue ``` Nesting in this mode is assembled with `CdsListGroup`: the `activator` slot gives the heading of the group, the default content — the nested items. The `subgroup` prop marks a group of the third level and deeper — the expand arrow moves to the start of the row. The group passes the arrow to the activator as the default value for `append-icon`, and the `append` slot replaces that area entirely — so with your own content the arrow disappears. Bring it back with an empty `` next to it: the icon picks up the direction of the arrow from the defaults of the group and keeps toggling on expand. **Example — `NestedSlots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A short title names the record — the eye compares items along a single trait. | A paragraph of text in a row turns the list into an article: scanning no longer finds anything. | | A long enumeration is split by subheaders — it is clear where to look for the record you need. | A solid list with no grouping has to be read in full. | | One action per row, the rest in a menu: the item as a whole stays clickable. | A row of buttons in every line overloads the list and makes the item itself hard to hit. | ## Scenarios ### Section menu A side menu is `activatable` plus `nav`: exactly one entry is active, `mandatory` forbids clearing the selection, and `v-model:activated` keeps the current section in the application state. Subheaders split the entries into meaningful blocks. **Example — `NavigationMenu.vue`:** ```vue ``` ### Document list with actions The whole row stays clickable, and the action in the `append` area works on top of it — that is why the button has `@click.stop`, otherwise the click would reach the item and select it. The status next to the button is a regular CdsTag. **Example — `DocumentsList.vue`:** ```vue ``` ### Picking recipients The `prepend` slot receives `isSelected` and `select` — the selection state and the function that changes it. This lets you show a checkbox while keeping the click on the whole row: `CdsListItemAction` aligns it to the grid of the item, and `CdsAvatar` stands next to it. **Example — `Recipients.vue`:** ```vue ``` ### Searching through a list The list is rebuilt from the filtered array — it needs no logic of its own. When there are no matches, a CdsEmptyState is shown instead of an empty list: the user understands that the reason is the query, not the loading. **Example — `SearchableList.vue`:** ```vue ``` ## API ### CdsList **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activatable` | `boolean \| undefined` | — | no | Allows items to be activated (highlighting the current item without selection mode) | | `activated` | `any` | — | no | Identifiers of the active items (supports v-model through `update:activated`) | | `activeClass` | `string \| undefined` | — | no | Class applied to list items when they are in the active state | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `activeStrategy` | `ActiveStrategyProp \| undefined` | — | no | Activation strategy for items (single, multiple, and so on) | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `collapseIcon` | `IconValue \| undefined` | — | no | Icon shown on a collapsed group | | `color` | `string \| undefined` | — | no | Component color | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `expandIcon` | `IconValue \| undefined` | — | no | Icon shown on an expanded group | | `filterable` | `boolean \| undefined` | — | no | **FOR INTERNAL USE ONLY** Turns on filtering mode: the space key does not select an item but is used for typing. Applies to the CdsCombobox and CdsAutocomplete components | | `height` | `string \| number \| undefined` | — | no | Component height | | `indent` | `string \| number \| undefined` | — | no | Indent size for nested item groups | | `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 | | `itemsRegistration` | `ItemsRegistrationType \| undefined` | `'render'` | no | Item registration strategy: `render` — as they are rendered, otherwise all at once | | `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 | | `lines` | `false \| "one" \| "two" \| "three" \| undefined` | `'one'` | no | Number of lines in the list items; affects their height. `false` turns off the fixed height | | `mandatory` | `boolean \| undefined` | — | no | Makes the selection mandatory: forbids clearing the selection of the last item | | `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 | | `nav` | `boolean \| undefined` | — | no | Applies navigation list styles (rounded active items) | | `navigationIndex` | `number \| undefined` | — | no | Index of the current item during keyboard navigation (supports v-model) | | `navigationStrategy` | `"focus" \| "track" \| undefined` | `'focus'` | no | Keyboard navigation strategy: `focus` — moves the focus, `track` — a virtual cursor | | `opened` | `any` | — | no | Identifiers of the expanded groups (supports v-model through `update:opened`) | | `openStrategy` | `OpenStrategyProp \| undefined` | `'list'` | no | Expansion strategy for groups (`list`, `single`, `multiple`) | | `prependGap` | `string \| number \| undefined` | — | no | Indent before the item content (reserves space for the prepend icon or avatar) | | `required` | `boolean \| undefined` | — | no | Makes the selection mandatory: forbids clearing the selection of the last item | | `returnObject` | `boolean \| undefined` | — | no | Return an object in the model value instead of an array | | `selectable` | `boolean \| undefined` | — | no | Allows items to be selected | | `selected` | `any` | — | no | Identifiers of the selected items (supports v-model through `update:selected`) | | `selectStrategy` | `SelectStrategyProp \| undefined` | `'single-leaf'` | no | Selection strategy for items (`single-leaf`, `leaf`, `independent`, `classic`, and so on) | | `slim` | `boolean \| undefined` | — | no | Removes the inner paddings of the list and of the menu container: the list fills the available area completely | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `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 | | --- | --- | --- | | `click:activate` | `[value: { id: unknown; value: boolean; path: unknown[]; }]` | Fires when an item is activated. `value` — the id of the item, its new state and its path | | `click:open` | `[value: { id: unknown; value: boolean; path: unknown[]; }]` | Fires on a click on the group activator. `value` — the id of the group, its new state and its path | | `click:select` | `[value: { id: unknown; value: boolean; path: unknown[]; }]` | Fires when an item is selected. `value` — the id of the item, its new state and its path | | `update:activated` | `[value: unknown]` | Fires when the set of active items changes. `value` — identifiers of the active items | | `update:navigationIndex` | `[value: unknown]` | Fires when the keyboard navigation index changes. `value` — the new index | | `update:opened` | `[value: unknown]` | Fires when the set of expanded groups changes. `value` — identifiers of the expanded groups | | `update:selected` | `[value: unknown]` | Fires when the set of selected items changes. `value` — identifiers of the selected items | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `ListItemSlot & { item: unknown; }` | Content after the item text (in place of the append icon or avatar) | | `default` | `ListItemSlot & { item: unknown; }` | Default content. Overrides the automatic rendering of items from `items` | | `description` | `ListItemDescriptionSlot & { item: unknown; }` | Content of the item description (shown below the title and the subtitle) | | `divider` | `{ props: { [key: string]: any; title: string; value: any; }; }` | Custom rendering of a divider when `items` is used | | `header` | `{ props: { [key: string]: any; title: string; value: any; }; }` | Custom rendering of the group activator (its heading) when `items` is used | | `item` | `{ props: { [key: string]: any; title: string; value: any; } & { index: number; }; }` | Custom rendering of a list item when `items` is used | | `prepend` | `ListItemSlot & { item: unknown; }` | Content before the item text (in place of the prepend icon or avatar) | | `subheader` | `{ props: { [key: string]: any; title: string; value: any; }; }` | Custom rendering of a subheader when `items` is used | | `subtitle` | `ListItemSubtitleSlot & { item: unknown; }` | Content of the item subtitle | | `title` | `ListItemTitleSlot & { item: unknown; }` | Content of the item title | **Exposed** | Name | Type | Description | | --- | --- | --- | | `children` | `Map` | Map of child items keyed by the identifiers of their parents | | `focus` | `(location?: number \| "next" \| "prev" \| "first" \| "last" \| undefined) => void` | Moves the focus to a list item (by index or by a keyword: `next`, `prev`, `first`, `last`) | | `getPath` | `(id: unknown) => unknown[]` | Returns the path (an array of identifiers) to an item by its id | | `open` | `(id: unknown, value: boolean, event?: Event \| undefined) => void` | Expands or collapses a group by its identifier | | `parents` | `Map` | Map of parent items keyed by the identifiers of their children | | `select` | `(id: unknown, value: boolean, event?: Event \| undefined) => void` | Selects or deselects an item by its identifier | ### CdsListGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendIcon` | `IconValue \| undefined` | — | no | Icon shown after the group title | | `baseColor` | `string \| undefined` | — | no | Color of the component in its inactive state | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `collapseIcon` | `IconValue \| undefined` | `'chevron-up'` | no | Icon shown when the group is collapsed | | `color` | `string \| undefined` | — | no | Component color | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `expandIcon` | `IconValue \| undefined` | `'chevron-down'` | no | Icon shown when the group is expanded | | `fluid` | `boolean \| undefined` | — | no | Removes the indent of the group activator, aligning it to the edge of the list | | `prependIcon` | `IconValue \| undefined` | — | no | Icon shown before the group title | | `rawId` | `string \| number \| undefined` | — | no | Original identifier of the group; used to build the id of the DOM element | | `subgroup` | `boolean \| undefined` | — | no | Marks the component as a group of nested lists (a subgroup) | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `title` | `string \| undefined` | — | no | Title of the group shown in the default activator | | `value` | `any` | — | no | Value of the group used in the expansion and selection logic | **Slots** | Name | Type | Description | | --- | --- | --- | | `activator` | `CdsListGroupActivatorSlot` | Activator of the group — the heading that expands and collapses the group on click | | `default` | `any` | Content of the group (the nested list items) | **Exposed** | Name | Type | Description | | --- | --- | --- | | `isOpen` | `boolean` | Whether the group is expanded | ### CdsListItem **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Forces the active state of the item | | `activeClass` | `string \| undefined` | — | no | Class applied to list items when they are in the active state | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `appendAvatar` | `string \| undefined` | — | no | Avatar (image URL) shown after the item content | | `appendIcon` | `IconValue \| undefined` | — | no | Icon shown after the item content | | `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 | | `description` | `string \| number \| boolean \| undefined` | — | no | Description of the list item shown below the title and the subtitle | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `exact` | `boolean \| undefined` | — | no | If true, the active state applies only on an exact route match | | `height` | `string \| number \| undefined` | — | no | Component height | | `href` | `string \| undefined` | — | no | The `href` attribute of the link. When set, the component behaves as a regular link | | `index` | `number \| undefined` | — | no | Index of the item; used for keyboard navigation | | `lines` | `false \| "one" \| "two" \| "three" \| undefined` | `'one'` | no | Number of lines in the list items; affects their height. `false` turns off the fixed height | | `link` | `boolean \| undefined` | — | no | Turns the item into a clickable link. Detected automatically when `href` or `to` is set | | `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 | | `nav` | `boolean \| undefined` | — | no | Applies navigation list styles (rounded active items) | | `prependAvatar` | `string \| undefined` | — | no | Avatar (image URL) shown before the item content | | `prependGap` | `string \| number \| undefined` | — | no | Indent before the item content (reserves space for the prepend icon or avatar) | | `prependIcon` | `IconValue \| undefined` | — | no | Icon shown before the item content | | `replace` | `boolean \| undefined` | — | no | If true, navigation replaces the current history entry instead of pushing a new one | | `slim` | `boolean \| undefined` | — | no | Removes the inner paddings of the list and of the menu container: the list fills the available area completely | | `subtitle` | `string \| number \| boolean \| undefined` | — | no | Subtitle of the item shown below the title | | `tabindex` | `string \| number \| undefined` | — | no | Value of the element `tabindex` attribute | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `title` | `string \| number \| boolean \| undefined` | — | no | Title of the item shown in the component | | `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 item used for selection and activation in the list | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `click` | `[value: MouseEvent \| KeyboardEvent]` | Fires on a click on the list item | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `ListItemSlot` | Content after the item text (in place of the append icon or avatar) | | `default` | `ListItemSlot` | Default content inside the item | | `description` | `ListItemDescriptionSlot` | Content of the item description (shown below the title and the subtitle) | | `prepend` | `ListItemSlot` | Content before the item text (in place of the prepend icon or avatar) | | `subtitle` | `ListItemSubtitleSlot` | Content of the item subtitle | | `title` | `ListItemTitleSlot` | Content of the item title | **Exposed** | Name | Type | Description | | --- | --- | --- | | `activate` | `(activated: boolean, e?: Event \| undefined) => void` | Activates or deactivates the item | | `isActivated` | `boolean` | Whether the item is in the active state | | `isGroupActivator` | `boolean \| undefined` | Whether the item is a group activator | | `isSelected` | `boolean` | Whether the item is selected | | `list` | `{ filterable: MaybeRefOrGetter; hasPrepend: Ref; updateHasPrepend: (value: boolean) => void; trackingIndex: Ref; navigationStrategy: Ref<"focus" \| "track", "focus" \| "track">; uid: string; } \| null` | Context of the parent list (CdsList) | | `root` | `NestedRoot` | Root nesting context of the parent list | | `select` | `(selected: boolean, e?: Event \| undefined) => void` | Selects or deselects the item | ### CdsListItemAction **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `end` | `boolean \| undefined` | — | no | Places the action at the end of the list item (after the content) | | `start` | `boolean \| undefined` | — | no | Places the action at the start of the list item (before the content) | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content of the action | ### CdsListItemDescription **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | ### CdsListItemDivider **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the divider. | | `contentOffset` | `string \| number \| (string \| number)[] \| undefined` | — | no | Increases the spacing between the content and the lines. When passed as an array, the second value shifts the slot content down (or right when vertical = true). | | `gradient` | `boolean \| undefined` | — | no | Adds a fade-out effect on both ends. | | `inset` | `boolean \| undefined` | — | no | Adds an indent to horizontal dividers and reduces the maximum height of vertical ones. | | `length` | `string \| number \| undefined` | — | no | Length of the divider. Defaults to pixels. | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the divider. | | `theme` | `string \| undefined` | — | no | Component theme | | `thickness` | `string \| number \| undefined` | — | no | Thickness of the divider. Defaults to pixels. | | `variant` | `"solid" \| "dotted" \| "dashed" \| "double" \| undefined` | `'solid'` | no | Visual variant of the divider | | `vertical` | `boolean \| undefined` | — | no | Renders the divider vertically | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Text or content placed in the gap of the divider | ### CdsListItemImage **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | ### CdsListItemMedia **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `end` | `boolean \| undefined` | — | no | Places the media at the end of the list item (after the content) | | `start` | `boolean \| undefined` | — | no | Places the media at the start of the list item (before the content) | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content of the media | ### CdsListItemSubtitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | ### CdsListItemTitle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | ### CdsListSubheader **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `color` | `string \| undefined` | — | no | Color of the subheader text | | `inset` | `boolean \| undefined` | — | no | Adds a left indent, aligning the text with the content of the list items | | `sticky` | `boolean \| undefined` | — | no | Pins the subheader to the top while the list scrolls | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `title` | `string \| undefined` | — | no | Text of the subheader | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Default content of the subheader (overrides the `title` prop) | --- # CdsLoader _Category: Feedback · since 4.0.0 · status: deprecated_ _Tests: API 5/5 · 8 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A circular indeterminate loading indicator — a spinning ring without progress. It shows that the data is still loading: as an inline element, as an overlay above a container or above the whole page. **See also:** The component is deprecated and will be removed in future versions. Use CdsProgressCircle: it covers both indeterminate loading and progress. ## Variations ### Sizes The `size` prop sets the diameter of the indicator: from `xs` to `xl` or a number in pixels. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### Overlay The `overlay` prop expands the indicator to the full screen and dims the content underneath. Add `fixed` so that the overlay takes the nearest container with `position: relative` instead of the whole page. The `description` prop describes what is going on for screen readers (aria-label). **Example — `Overlay.vue`:** ```vue ``` ## API ### CdsLoader **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `description` | `string \| undefined` | — | no | Description that best explains the loading state (aria-label) | | `fixed` | `boolean \| undefined` | — | no | Pins the loader to the current container | | `overlay` | `boolean \| undefined` | — | no | Renders a fixed full-screen loader | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `theme` | `string \| undefined` | — | no | Component theme | --- # CdsMain _Category: Layouts · since 4.0.0_ _Tests: API 1/1 · 4 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ The main area of the application: `CdsMain` is the place where the content of the page lands. Inside `CdsLayout` it indents itself by the height of the header and the footer and by the width of the side drawers, so the content never has to be moved by hand. **See also:** Put the content into CdsPage — it calculates the minimum height of the page. `CdsMain` works only inside CdsLayout: outside the layout it renders nothing and warns about it in the console. ## Scenarios ### The main area of the application `CdsMain` renders as a `main` tag — one semantic content area per page. The paddings are recalculated on the fly: minify a drawer, hide the header — and the content immediately takes the freed space. **Example — `Offsets.vue`:** ```vue ``` ## API ### CdsMain **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Main content of the application (`CdsPage`). | --- # CdsMenu _Category: Content · since 4.0.0_ _Tests: API 56/56 · 51 unit · 8 e2e · 5 known bugs · lines 87% (v4.0.0-alpha.13) · a11y: 7 axe recommendations (v4.0.0-alpha.11)_ A menu pops up next to an activator element and shows a list of actions or sections: the "more" button in a table row, the user menu in the header, a context menu on right click. It positions itself — it opens towards the free space and sticks to the activator while the page scrolls. **See also:** To pick a value in a form, take CdsSelect — it stays visible and gets submitted. For a short hint on hover use CdsTooltip, and for a dialog that demands an answer use CdsModal. The content of a menu is usually built from CdsList. ## Variations ### Activators A menu is opened by an activator element — you can set it in three ways: 1. **Through the `activator` slot** — the props from the slot (`v-bind="props"`) attach the handlers and the aria attributes to the element. This is the default way: the activator sits next to the menu. 2. **Through the parent** — `activator="parent"` takes the element that contains the `CdsMenu`. Handy when the activator is already built and you do not want to wrap it. 3. **Through a selector** — `activator="#id"` links the menu to any element on the page, even a distant one in the markup. **Example — `Activators.vue`:** ```vue ``` ### Opening By default the menu opens on click. The `open-on-hover` prop switches it to hover — this is how navigation menus behave; a click then does not open the panel. The `open-delay` and `close-delay` delays (300 and 250 ms) keep the menu from flickering when the cursor just passes by. Together with `open-on-hover`, opening on focus is enabled as well — turn it off with `:open-on-focus="false"` if the menu should react to the mouse only. **Example — `OpenOnHover.vue`:** ```vue ``` ### Position The `location` prop sets the side of the activator the menu appears on: `bottom` by default, `top`, `end`, `bottom end` — the side and the alignment. If there is not enough room, the menu flips to the opposite edge on its own. The `offset` prop tunes the distance to the activator, and `viewport-margin` sets the minimum gap to the edge of the screen. **Example — `Location.vue`:** ```vue ``` ### Sizes The width of the menu equals the width of its content. The `min-width`, `max-width` and `max-height` props set the bounds: the minimum width keeps the panel from collapsing on short items, and a limited height turns on scrolling instead of a full-screen menu. **Example — `MenuSize.vue`:** ```vue ``` ### Closing The menu closes on a click inside the content, on a click outside and on `Esc`. The `:close-on-content-click="false"` prop keeps the panel open — you need that when it holds checkboxes, fields or several steps in a row. The `persistent` prop ignores the outside click and `Esc`: then the menu can only be closed by your own button through `v-model`. **Example — `CloseBehavior.vue`:** ```vue ``` ### Nested menus Menus can be nested into each other: every list item becomes an activator (`activator="parent"`) for a child `CdsMenu` with the `submenu` prop — it shifts the panel sideways and moves the navigation to the left and right arrow keys. The `open-on-hover` prop opens the submenu on hover, and `:open-on-focus="false"` keeps it from opening while tabbing through. **Example — `NestedMenu.vue`:** ```vue ``` ### Animation The `transition` prop changes the animation the panel appears with. **Example — `Transition.vue`:** ```vue ``` ### Slots | Slot | Description | | ----------- | ----------------------------------------------------------------------------------- | | `activator` | The element that opens the menu. The slot props (`props`) attach the handlers to it | | `default` | The content of the panel. Usually `CdsList`, `CdsCard` or `CdsSurface` | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The activator names what is inside the menu: a label or the well-known «⋮» icon makes it clear that a list of actions will open. | An icon with no label and no aria-label promises nothing — the menu gets opened at random. | | A menu triggers actions. A field value is picked in a select — it stays visible and takes part in the form submission. | A menu used instead of a field hides the selected value and drops out of the form validation. | | Rare actions on a record are collected in a single menu behind the «⋮» button — press it to see the list. The row stays readable. | A row of equally weighted buttons in every line overloads the table and hides the main action. | ## Scenarios ### Actions on a record Rare actions on a table row or a card are collected in a menu behind the "⋮" button: the row stays clean, and the actions do not compete with the main button. `location="bottom end"` pins the panel to the right edge of the activator, `slim` on the list removes the extra paddings, and `aria-label` names the record the menu belongs to. **Example — `RowActions.vue`:** ```vue ``` ### Context menu A menu can open at the point of the click: the `contextmenu` handler puts the cursor coordinates into `target`, and `v-model` controls the visibility — no activator is needed here. A new click moves the open panel to the new spot. The default animation is meant for an element activator, so for a menu placed by coordinates set a CSS animation — for example, `transition="scale-transition"`. **Example — `ContextMenu.vue`:** ```vue ``` ### Menu in the header In the application header a menu solves two tasks: it expands the navigation sections and collects everything about the account behind the avatar. The activator of the user menu is a `CdsAvatar` inside a button with an `aria-label`, `location="bottom end"` pins the panel to the right edge, and `min-width` keeps it from jumping in width. The first list item shows whose account it is, and `CdsListItemDivider` separates the sections from signing out. **Example — `UserMenu.vue`:** ```vue ``` ### Filter with several values When several values are picked inside a menu, the panel must not close on the very first click: `:close-on-content-click="false"` keeps it open, and `v-model` lets the "Apply" button close the menu. The selection piles up in a draft and is applied as a whole — until the button is pressed, the list of records does not change. **Example — `FilterMenu.vue`:** ```vue ``` ## API ### CdsMenu **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. | | `captureFocus` | `boolean \| undefined` | `true` | no | Returns the focus back into the content if it has left it — for example on Tab from the end of the page. A mouse click does not steal the focus. | | `closeDelay` | `string \| number \| undefined` | `250` | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `true` | 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` | `true` | no | Hide the component on a click on the content | | `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` | — | 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 | | `id` | `string \| undefined` | — | no | Unique identifier that links the menu to its activator. If it is not set, it is generated automatically. | | `location` | `Anchor \| undefined` | `'bottom'` | 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` | — | 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` | `4` | 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` | `300` | 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. | | `persistent` | `boolean \| undefined` | — | no | A click outside the element or the Esc key does not close it. | | `retainFocus` | `boolean \| undefined` | — | no | Traps Tab navigation inside the content: from the last focusable element the focus moves to the first one and back. | | `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` | `'none'` | 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. | | `submenu` | `boolean \| undefined` | — | no | Opens and closes the menu with the left/right arrow keys instead of up/down (for nested menus). | | `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. | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| { component: Component; } \| null \| undefined` | `{ component: CdsModalTransition }` | 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 | | --- | --- | --- | | `afterEnter` | `[]` | Fired after the opening animation of the menu has finished | | `afterLeave` | `[]` | Fired after the closing animation of the menu has finished | | `update:modelValue` | `[value: boolean]` | Fired when the menu is opened or closed. 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. | --- # CdsMessages _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 11/11 · 18 unit · 7 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 0 axe recommendations (v4.0.0-alpha.11)_ The block of messages under an input: a hint, an explanation or a validation error. The messages appear and disappear with an animation, so the line under the field does not jerk the layout. **See also:** The ready-made fields already have the block of messages built in — the `messages`, `hint` and `error-messages` props of CdsTextInput and the other controls. A standalone `CdsMessages` is needed for groups of fields and for your own controls. For a noticeable notification on the page take CdsNotification. ## Variations ### Messages The `messages` prop accepts a string or an array of strings — every string becomes a separate line, they are not glued together. **Example — `Messages.vue`:** ```vue ``` ### Color The `color` prop sets the color of the text — take the status tokens (`status-danger-content` for an error, `status-success-content` for a confirmation). Without a color the messages are muted, like supporting text. **Example — `Colors.vue`:** ```vue ``` ### Appearance The messages are visible only with `active`. Showing and hiding are animated, and the animation is set by the `transition` prop. **Example — `Active.vue`:** ```vue ``` ### Slot The `message` slot overrides a single message and receives its text — you can add an icon or a link. The `default` slot adds content after all the messages. **Example — `Slot.vue`:** ```vue ``` ## Scenarios ### An error for a group of fields A group of checkboxes has no validation of its own: assemble it yourself and show the result through `active`. While the selection is empty, the red message hangs under the group and disappears with the very first checkbox. **Example — `GroupValidation.vue`:** ```vue ``` ## API ### CdsMessages **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `active` | `boolean \| undefined` | — | no | Active state | | `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 | | `hideMessages` | `boolean \| undefined` | — | no | Hide the messages under the input | | `messages` | `string \| readonly string[] \| undefined` | `[]` | no | Messages shown under the input | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| { component: Component; leaveAbsolute: boolean; group: boolean; } \| null \| undefined` | `{ component: slide-transition-y, leaveAbsolute: true, group: true }` | no | Transition animation | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Your own look for the whole list of messages instead of the default one | | `message` | `CdsMessageSlot` | Template for a single message. The slot props carry the text of the message | --- # CdsModal _Category: Content · since 4.0.0_ _Tests: API 58/58 · 45 unit · 4 e2e · 2 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 9 axe recommendations (v4.0.0-alpha.11)_ A modal opens on top of the page and keeps the focus on a single task: confirm an action, fill in a short form, look at the details — without taking you away from the current screen. While the modal is open, the page behind it is dimmed, does not scroll and does not accept clicks. **See also:** For a list of actions on an element take CdsMenu, for a short hint — CdsTooltip, for a notification about the result — CdsToast. Complex modal content — a header, scrollable text and a row of buttons — is assembled from CdsCard. ## Variations ### Activators The modal is opened by an activator element — you can set it in three ways: 1. **Through the `activator` slot** — the props from the slot (`v-bind="props"`) attach the handlers and the aria attributes to the element. The default way. 2. **Through the parent** — `activator="parent"` takes the element that `CdsModal` is placed inside of. 3. **Through a selector** — `activator="#id"` links the modal to any element on the page, even a distant one in the markup. **Example — `Activators.vue`:** ```vue ``` ### Using v-model The state of the modal can be controlled directly through `v-model` — without an activator. This is how you open a modal from code: on a server response, from a handler in a table, from a store. **Example — `VModel.vue`:** ```vue ``` ### Sizes The `size` prop sets the width of the modal: `xs` (250), `sm` (350), `md` (500, the default), `lg` (700), `xl` — almost the full width of the screen. A number instead of an alias is an exact width in pixels. The height always adapts to the content, and `width` and `max-width` override the size when you need a non-standard grid. **Example — `Sizes.vue`:** ```vue ``` ### Persistent modals The `persistent` prop turns off closing by a click outside the modal and by the `Esc` key — the modal can only be closed with the buttons inside it. A click outside shakes the modal, hinting that an answer is still required; the animation is removed by `no-click-animation`. Take `persistent` when closing would lose data or when the user has to make a choice. **Example — `Persistent.vue`:** ```vue ``` ### Scrolling inside the modal By default long content scrolls together with the whole modal. The `scrollable` prop pins the header and the buttons and scrolls only the middle — for that the content is assembled from CdsCard: the card becomes the surface of the modal, and the scrolling area is its `CdsCardText`. **Example — `Scrollable.vue`:** ```vue ``` ### Fullscreen The `fullscreen` prop expands the modal to the whole screen: the size props are ignored, the paddings and the rounded corners are removed. It fits document viewing and complex forms on small screens. **Example — `Fullscreen.vue`:** ```vue ``` ### Animations By default the modal grows out of the activator and shrinks back — so you can see where it came from. The `transition` prop changes the animation: the ready `modal-transition-top` and `modal-transition-bottom` slide the modal in from the edge of the screen, and any custom CSS animation works too. **Example — `Transition.vue`:** ```vue ``` ### Slots | Slot | Description | | ----------- | -------------------------------------------------------------------------------------------------------------- | | `activator` | The element that opens the modal. The slot props (`props`) attach the handlers to it | | `default` | The content of the modal. The slot exposes `isActive` — use it to close the modal without an external variable | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The title names the action and the buttons answer it — you decide without rereading the text. | “Are you sure?” with “Yes / No” forces you to read the text closely to understand what will happen. | | There is always a way back from the modal: a cancel button next to the main action and a close icon in the corner. | A single “Accept” button leaves no choice — the user is locked inside the modal. | | The size of the modal matches its content: a short confirmation lives in a compact modal. | In a wide modal a single line of text gets lost and the eye wanders between the text and the buttons. | ## Scenarios ### Delete confirmation An irreversible action is confirmed with a compact `size="sm"` modal: the title names the action, the text specifies what exactly will be deleted, the main button repeats the verb from the title. One modal serves the whole list — the selected record is put into it right before opening. **Example — `ConfirmDelete.vue`:** ```vue ``` ### A form in a modal A short form is opened on top of the list so that the user is not taken away to a separate page. `persistent` protects what has been typed from an accidental click outside, the submit button shows `loading`, and "Cancel" is blocked while the request is running. The fields are reset in the `after-leave` event — after the closing animation, so that the values do not flash in a still visible modal. **Example — `FormModal.vue`:** ```vue ``` ### An agreement with scrolling A document that requires an explicit answer is shown in a modal with `persistent` and `scrollable`: the text scrolls, and the "Accept" and "Decline" buttons are always in sight. Closing the modal without answering is not possible — the decision is recorded only with the buttons. **Example — `TermsAgreement.vue`:** ```vue ``` ## API ### CdsModal **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. | | `captureFocus` | `boolean \| undefined` | `true` | no | Returns the focus back into the content if it has left it — for example on Tab from the end of the page. A mouse click does not steal the focus. | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `true` | 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 | | `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` | — | 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. | | `fullscreen` | `boolean \| undefined` | — | no | Expands the modal to the whole screen. | | `height` | `string \| number \| undefined` | — | no | Component height | | `location` | `Anchor \| undefined` | `'center center'` | no | Sets the anchor point used to position the component, aligning it horizontally, vertically or in both directions | | `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. | | `noClickAnimation` | `boolean \| undefined` | — | no | Disables the bounce effect on a click outside the content element when `persistent` is set. | | `offset` | `string \| number \| number[] \| undefined` | — | 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` | — | 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` | `'center center'` | 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. | | `retainFocus` | `boolean \| undefined` | `true` | no | Traps Tab navigation inside the content: from the last focusable element the focus moves to the first one and back. | | `scrim` | `string \| boolean \| undefined` | `true` | no | Backdrop shown while the overlay is active. Accepts true/false to toggle the backdrop and a string to set its color. | | `scrollable` | `boolean \| undefined` | — | no | Enables scrolling of the content inside the modal. | | `scrollStrategy` | `"none" \| "close" \| "block" \| "reposition" \| ScrollStrategyFunction \| undefined` | `'block'` | no | Strategy applied when the component is active and the user scrolls the page. | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `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. | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| { component: Component; } \| null \| undefined` | `{ component: CdsModalTransition }` | 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` | `2400` | no | The z-index value of the component. | **Events** | Name | Type | Description | | --- | --- | --- | | `afterEnter` | `[]` | Fired after the opening animation of the modal has finished. | | `afterLeave` | `[]` | Fired after the closing animation of the modal has finished. | | `update:modelValue` | `[value: boolean]` | Fired when the state of the modal changes. | **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. | --- # CdsNotification _Category: Feedback · since 4.0.0_ _Tests: API 23/23 · 49 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ A notification is a block with a message about an event or a state: a successful save, a warning about a limit, a loading error. The semantic status sets the color and the icon, and the display modes let you embed the message into a form, a card or a list. **See also:** For pop-up messages above the page that disappear on their own take CdsToast. For a short status label in a row or a card — CdsTag. ## Anatomy A notification consists of a status icon, a content column — heading, text and actions — and a close button. Every part can be replaced by the slot of the same name. ## Variations ### Statuses The `status` prop sets the semantics of the message — its color and its icon. The default status is `info`. **Example — `Statuses.vue`:** ```vue ``` ### Display modes The `variant` prop changes the styling: `default` — with a border, `flat` — without a border, `compact` — a single line, `important` — a neutral background and a shadow for showing above the content. **Example — `Variants.vue`:** ```vue ``` `variant="compact"` puts the icon, the text and the actions on one line and hides the heading. It fits tight places: a filter panel, a table row, the footer of a card. **Example — `Compact.vue`:** ```vue ``` ### Icons By default the icon matches the status. The `icon` prop replaces it with any icon from the pack, and the value `false` removes it altogether. **Example — `Icons.vue`:** ```vue ``` ### Closing The `closable` prop adds a close button; the visibility of the notification is controlled through `v-model`. A click on the button also emits `click:close`. The notification appears and leaves smoothly: it fades out first, then collapses in height, so neighbouring blocks slide without a jump. `click:close` is emitted right at the click, while `update:modelValue` arrives after the leave has finished, so you can remove the item from a list in the handler without cutting the animation short. Set the spacing between notifications in a list with `margin`: it collapses together with the block, unlike `gap`, which makes a jump on leave. Under `prefers-reduced-motion` only opacity changes. **Example — `Closable.vue`:** ```vue ``` ### Slots Slots replace the content coming from props when you need your own markup. | Slot | Description | | --------- | ---------------------------------------------------------- | | `prepend` | Content before the text. Replaces the status icon | | `title` | Heading. Replaces the text from `title` | | `text` | Message text. Replaces the text from `text` | | `default` | Arbitrary content after the text | | `actions` | Actions (buttons, links) below the text | | `append` | Content after the content column | | `close` | Close button. Receives `props` to bind to your own element | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The status matches the meaning of the message: success — the action went through. | Danger for neutral news is alarming: the reader looks for an error that is not there. | | The heading names the event briefly, the details go into the text. | A long heading with no text is hard to read, and the event gets lost. | | One or two secondary actions help the user react to the event. | Primary buttons inside a notification compete with the main action of the screen. | ## Scenarios ### Form submission result After a successful request a notification with the `success` status appears through `v-model` and confirms the result. The `closable` prop lets the user dismiss the message once it is read. **Example — `FormResult.vue`:** ```vue ``` ### A warning with an action A `warning` notification does not just report a problem — it offers a solution right away with a button in the `actions` slot. On click the status changes to `progress`, and after the server responds — to `success`: the user sees the whole course of the operation in a single block. **Example — `EmailConfirmation.vue`:** ```vue ``` ### Loading error with a retry If the data failed to load, a `danger` notification explains what happened and offers to repeat the request. The `progress` status shows that the retry is already running. **Example — `LoadError.vue`:** ```vue ``` ## API ### CdsNotification **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `closable` | `boolean \| undefined` | — | no | Adds a close button that hides the notification. | | `closeIcon` | `IconValue \| undefined` | `'close'` | no | Icon of the close button. | | `closeLabel` | `string \| undefined` | `'$cds.close'` | no | Accessible label (aria-label) for the close button. | | `content` | `string \| number \| undefined` | — | no | Content displayed in the component. | | `icon` | `false \| IconValue \| undefined` | `null` | no | Icon before the content. Taken from `status` by default; `false` hides the icon. | | `modelValue` | `boolean \| undefined` | `true` | no | Visibility of the notification (v-model). When `false`, the notification is not rendered. | | `status` | `"progress" \| "danger" \| "success" \| "warning" \| "info" \| undefined` | `'info'` | no | Semantic status — drives the color and the default icon. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | 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 | | `title` | `string \| undefined` | — | no | Notification heading. | | `variant` | `"default" \| "flat" \| "compact" \| "important" \| undefined` | `'default'` | no | Display mode: `default` — regular; `flat` — borderless; `compact` — single line without a heading; `important` — neutral background and a shadow, where the status only drives the content colors. | **Events** | Name | Type | Description | | --- | --- | --- | | `click:close` | `[event: MouseEvent]` | Click on the close button. | | `update:modelValue` | `[value: boolean]` | The visibility of the notification changed. On close by the button it arrives after the leave animation ends, not at the click. | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `any` | Slot for actions (buttons, links) below the text. | | `append` | `any` | Slot after the content. | | `close` | `{ props: Record; }` | Close button slot; receives `props` to bind to your own element. | | `default` | `any` | Main content of the notification (complements `text`). | | `prepend` | `any` | Slot before the content (the status icon by default). | | `text` | `any` | Text slot (instead of the `text` prop). | | `title` | `any` | Heading slot (instead of the `title` prop). | --- # CdsNotificationAlert _Category: Feedback · since 4.0.0 · status: deprecated_ _Tests: API 65/65 · 46 unit · 1 e2e · 6 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ A pop-up notification above the page — the counterpart of `CdsNotificationAlert` from CDS 3. It is assembled from CdsOverlay and CdsNotification in the `important` variant; it hides automatically after `timeout`, while hovering the cursor or focusing inside pauses the timer. **See also:** The component exists only for a smooth migration from CDS 3 and will be removed. For new scenarios use CdsToast. ## Variations ### Controlling the display Visibility is controlled through `v-model` or the `activator` slot — the element inside the slot opens the notification on click. The text comes from the `text` prop. **Example — `Default.vue`:** ```vue ``` ### Statuses The `status` prop sets the color of the content and the icon: `info`, `success`, `warning`, `danger`, `progress`. The icon can be replaced by the `icon` prop or hidden with the value `false`. **Example — `Statuses.vue`:** ```vue ``` ### Positions The `location` prop sets the position on the screen: the side (`top`, `bottom`) and the alignment (`left`, `center`, `right`). **Example — `Positions.vue`:** ```vue ``` ### Auto-closing The `timeout` prop controls the auto-close delay in milliseconds, 5000 by default. The values `-1` and `0` turn auto-closing off — the notification stays until the user closes it (`closable`). Hovering the cursor and focusing inside pause the countdown. **Example — `Timeout.vue`:** ```vue ``` ## Scenarios ### Undoing an action After an irreversible operation the notification gives a short window to undo it: the button in the `actions` slot closes it through `v-model`, and an increased `timeout` leaves time to change one's mind. **Example — `WithActions.vue`:** ```vue ``` ### A stack of notifications Every instance is an independent overlay: notifications sharing a position pile up into a vertical stack. On close (`update:model-value` → `false`) remove the item from the list. **Example — `Cascade.vue`:** ```vue ``` ## API ### CdsNotificationAlert **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` | `boolean \| undefined` | — | no | Adds a close button that hides the notification. | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeIcon` | `IconValue \| undefined` | `'close'` | no | Icon of the close button. | | `closeLabel` | `string \| undefined` | `'$cds.close'` | no | Accessible label (aria-label) for the close button. | | `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 | | `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. | | `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 | | `status` | `"progress" \| "danger" \| "success" \| "warning" \| "info" \| undefined` | `'info'` | no | Semantic status — drives the color and the default icon. | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `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 notification hides automatically. The values `-1` and `0` turn auto-closing off. | | `title` | `string \| undefined` | — | no | Notification heading. | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'notification-transition'` | no | Transition animation | | `variant` | `"default" \| "flat" \| "compact" \| "important" \| undefined` | `'important'` | no | Appearance of the notification. `important` by default — an elevated surface with a shadow (the CdsNotificationAlert look). | | `width` | `string \| number \| undefined` | — | no | Component width | | `zIndex` | `string \| number \| undefined` | `2000` | no | The z-index value of the component. | **Events** | Name | Type | Description | | --- | --- | --- | | `click:close` | `[event: MouseEvent]` | Click on the close button. | | `update:modelValue` | `[value: boolean]` | The visibility of the notification changed. | **Slots** | Name | Type | Description | | --- | --- | --- | | `actions` | `any` | Slot for actions (buttons, links) below the text. | | `activator` | `{ isActive: boolean; props: Record; }` | Activator slot that controls the display of the notification. | | `append` | `any` | Slot after the content. | | `close` | `{ props: Record; }` | Close button slot; receives `props` to bind to your own element. | | `default` | `any` | Main content of the notification (complements `text`). | | `prepend` | `any` | Slot before the content (the status icon by default). | | `text` | `any` | Text slot (instead of the `text` prop). | | `title` | `any` | Heading slot (instead of the `title` prop). | **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. | --- # CdsOtpInput _Category: Controls · since 4.0.0 · status: new_ _Tests: API 44/44 · 78 unit · 3 e2e · 5 known bugs · lines 93.4% (v4.0.0-alpha.13) · a11y: 3 axe recommendations (v4.0.0-alpha.11)_ A field for entering a one-time code — from an SMS, an email or an authenticator app. It looks like a row of separate cells, but the input is taken by a single hidden `input`: that is why the SMS autofill, pasting a whole string from the clipboard, selection and the arrow keys all work, and the focus does not have to be jumped between the cells by hand. **See also:** For an ordinary short text or number take CdsTextInput: `CdsOtpInput` is needed where the length of the input is known upfront and every character is shown in its own cell. ## Anatomy The cells (`CdsOtpField`) only draw the code — the entered character, the placeholder or the blinking caret. The real input is taken by a hidden `input`: it is pressed to the bottom edge of the component, so the SMS autofill suggestion appears under the cells and covers nothing. A separator (`CdsOtpSeparator`) may stand between the cells, and in the merged look the cells are gathered into a group (`CdsOtpGroup`). ## Variations ### Length and type of the code The `length` prop sets the number of cells, `type` — what may be entered: `number` (the default) accepts digits only and opens the numeric keyboard on mobile, `text` — any characters, `password` additionally hides what is entered behind dots. The same effect without changing the type is given by `masked`. **Example — `LengthAndType.vue`:** ```vue ``` ### Allowed characters The `pattern` prop narrows the set of characters: the name of a ready set (`numeric`, `alpha`, `alphanumeric`, `unicode-alpha`, `unicode-alphanumeric`) or your own regular expression. The check goes character by character — the extra ones will not get into the field, neither from the keyboard nor from the clipboard. **Example — `Pattern.vue`:** ```vue ``` ### Separator The `divider` prop puts a character between the cells — a hyphen in a code like `123-456`, for example. The `divider` slot gives full freedom of markup and receives `index` — the number of the cell to the left of the separator, so the separator can be placed only where it is needed. **Example — `Divider.vue`:** ```vue ``` ### Merged look The `merged` prop removes the gaps: the cells become a single field with a common border. This look is more compact and breaks the form up less. **Example — `Merged.vue`:** ```vue ``` ### Placeholder The `placeholder` prop shows a character in the empty cells — a hint about the format or simply a dot, so that the row does not look empty. **Example — `Placeholder.vue`:** ```vue ``` ### Sizes The `size` prop changes the height of the cells and the font size. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### States `disabled` blocks the input, `error` highlights the whole row with the error color, `loading` shows an indicator on top of the cells and does not erase the entered code. `focus-all` highlights the whole row while the field is focused, not just the active cell. **Example — `States.vue`:** ```vue ``` ### Slots | Slot | Description | | :-------- | :--------------------------------------------------------------------------------------------- | | `fields` | The whole row of cells — your own markup of `CdsOtpGroup`, `CdsOtpField` and `CdsOtpSeparator` | | `divider` | The separator between the cells, `index` is the number of the cell to its left | | `loader` | Your own loading indicator (with `loading`) | | `default` | Arbitrary content on top of the cells | The `fields` slot is needed when the cells are gathered into groups: every `CdsOtpField` receives its own `index`, and `CdsOtpGroup` joins the neighboring cells into a common border. **Example — `CustomFields.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The number of cells equals the length of the code — the user sees at once how many characters to enter. | Extra cells make the user guess whether the whole code has been entered. | | The whole code is entered in one field: pasting from the clipboard and SMS autofill both work. | Separate text fields break code pasting and force the user to move the focus by hand. | | On an error the field stays available, and the text next to it says what to do next. | A blocked field with no explanation makes it impossible to fix the code. | ## Scenarios ### Confirmation by SMS The `finish` event fires as soon as the whole code is entered — send the request on it, a separate button is not needed. Turn on `loading` for the duration of the check: the code stays on the screen and the field does not look broken. If the server did not accept the code, `error` highlights the row, and the `reset()` and `focus()` methods called through a ref clear the field and bring the cursor back into it. **Example — `SmsConfirmation.vue`:** ```vue ``` ### Resending the code The "Send again" button opens on a timer — that way the user does not flood the gateway with requests. Reset the field together with the new code: `reset()` clears the cells, `focus()` puts the cursor into the first one, and the old code does not mix with the new one. **Example — `ResendCode.vue`:** ```vue ``` ### A code inside a form When the code is a part of the sign-in form, keep the confirmation button: it gives an explicit moment of submission. The button waits until all the characters are entered — the length of the code is visible from `v-model`, and `disabled` on the field freezes the code that has already been confirmed. **Example — `TwoFactorForm.vue`:** ```vue ``` ## API ### CdsOtpInput **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the component in its active state | | `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 | | `color` | `string \| undefined` | — | no | Component color | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `divider` | `string \| undefined` | — | no | Separator character placed between the code cells | | `error` | `boolean \| undefined` | — | no | Error state | | `focusAll` | `boolean \| undefined` | — | no | Highlight all the cells while the field is focused, not only the active one | | `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. | | `height` | `string \| number \| undefined` | — | no | Component height | | `label` | `string \| undefined` | `'$cds.input.otp'` | no | Accessible name of the field (`aria-label`). Accepts a localization key such as `$cds.input.otp` | | `length` | `string \| number \| undefined` | `6` | no | Number of code cells | | `loading` | `string \| boolean \| undefined` | — | no | Loading indicator for the component | | `masked` | `boolean \| undefined` | — | no | Hide the entered characters behind dots | | `maxHeight` | `string \| number \| undefined` | — | no | Maximum component height | | `maxWidth` | `string \| number \| undefined` | — | no | Maximum component width | | `merged` | `boolean \| undefined` | — | no | Merged look: the cells are joined into a single field with no gaps between them | | `minHeight` | `string \| number \| undefined` | — | no | Minimum component height | | `minWidth` | `string \| number \| undefined` | — | no | Minimum component width | | `modelValue` | `string \| number \| undefined` | — | no | Value of the component (v-model) | | `pattern` | `RegExp \| "numeric" \| "alpha" \| "alphanumeric" \| "unicode-alpha" \| "unicode-alphanumeric" \| undefined` | — | no | Allowed characters: the name of a ready pattern (`numeric`, `alpha`, `alphanumeric`, `unicode-alpha`, `unicode-alphanumeric`) or your own regular expression | | `placeholder` | `string \| undefined` | — | no | Placeholder character shown in an empty cell | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `type` | `CdsOtpInputType \| undefined` | `'number'` | no | Type of the code being entered. `number` limits the input to digits, `password` hides the characters | | `width` | `string \| number \| undefined` | — | no | Component width | **Events** | Name | Type | Description | | --- | --- | --- | | `finish` | `[value: string]` | Fires when the whole code has been entered | | `update:focused` | `[focused: boolean]` | Fires when the field gains or loses focus | | `update:modelValue` | `[value: string]` | Fires when the value of the component changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Arbitrary content on top of the code cells | | `divider` | `{ index: number; }` | Separator between the cells. `index` is the number of the cell to the left of it | | `fields` | `any` | Fully replaces the row of cells with your own markup made of `CdsOtpGroup`, `CdsOtpField` and `CdsOtpSeparator` | | `loader` | `any` | Custom loading indicator | **Exposed** | Name | Type | Description | | --- | --- | --- | | `blur` | `() => void` | Remove the focus from the field | | `focus` | `() => void` | Set the focus on the field | | `inputRef` | `HTMLInputElement \| undefined` | Ref to the hidden input that receives the code | | `isFocused` | `boolean \| undefined` | Focus state of the field | | `reset` | `() => void` | Clear the entered code | ### CdsOtpField **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `index` | `number` | — | yes | Zero-based index of the cell | ### CdsOtpGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `merged` | `boolean \| null \| undefined` | `null` | no | Merged look of the group. Inherited from the parent `CdsOtpInput` by default | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | The code cells of the group | ### CdsOtpSeparator **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the separator | --- # CdsOverlay _Category: Content · since 4.0.0_ _Tests: API 57/57 · 96 unit · 10 e2e · 4 known bugs · lines 83.5% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ An overlay shows content on top of the page: it dims the page with a scrim, computes the position relative to an activator and manages the stacking order of the open layers. It is the base mechanism behind CdsModal, CdsMenu and CdsTooltip — take it when you need a popup of your own that is not among the ready-made ones. **See also:** For common tasks there are ready-made components built on the overlay: a dialog — CdsModal, a list of actions next to an activator — CdsMenu, a hint on hover — CdsTooltip, notifications — CdsToast. CdsOverlay is for when none of them fits. ## Anatomy An overlay consists of two parts: the scrim, which dims the page and intercepts clicks, and the content — the contents of the `default` slot. The content is moved to the end of `body`, so the overlay does not depend on the `overflow` and `z-index` of the parent blocks. ## Variations ### Opening and closing `v-model` controls the visibility. An open overlay closes on a click outside the content and on the `Esc` key. **Example — `Default.vue`:** ```vue ``` The `persistent` prop turns both ways off: the overlay closes only through `v-model` — for example, by a button inside the content. On a click outside, the content answers with a light "shake"; remove it with the `no-click-animation` prop if you do not need the animation. **Example — `Persistent.vue`:** ```vue ``` ### Activator The `activator` slot saves you from a manual `v-model`: pass the slot props (`v-bind="props"`) to an element — and a click on it will open the overlay. The `open-on-hover` and `open-on-focus` props switch the opening to hover or focus, and `activator="parent"` makes the parent element the activator. **Example — `Activator.vue`:** ```vue ``` ### Scrim The scrim is on by default: it dims the page and shows that the interface under the overlay is unavailable. The `:scrim="false"` prop removes it — a click outside still closes the overlay. The `opacity` prop tunes the dimming density, and a string in `scrim` sets a custom color for the scrim. **Example — `Scrim.vue`:** ```vue ``` ### Limiting to a container The `contained` prop locks the overlay inside the parent block: the scrim and the content do not leave its bounds, and the rest of the page keeps working. The parent must have `position: relative`. To center the content inside the block rather than relative to the screen, pass the container to `target` and turn on `location-strategy="connected"`. **Example — `Contained.vue`:** ```vue ``` ### Positioning By default the content is centered relative to the screen — this is what the `static` strategy and the `location` prop are responsible for. The `location-strategy="connected"` strategy attaches the content to the activator: `location` sets the side, `offset` — the distance to it. If there is not enough room near the screen edge, the content flips to the opposite side — that is how CdsMenu works. **Example — `Connected.vue`:** ```vue ``` ### Behavior on scroll The `scroll-strategy` prop decides what happens to the page and the overlay on scroll: `block` (the default) blocks the page scroll, `close` closes the overlay, `reposition` recomputes the position of the content following the target, `none` does nothing. **Example — `ScrollStrategies.vue`:** ```vue ``` ### Animation The `transition` prop changes the animation of showing and hiding the content. **Example — `Transition.vue`:** ```vue ``` ### Slots | Slot | Description | | ----------- | ---------------------------------------------------------------------------------- | | `activator` | The element that opens the overlay. Bind the slot props (`props`) to it | | `default` | The overlay content. Receives `isActive` — use it to close the overlay from inside | ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A persistent overlay has an explicit button — the user can always close it. | The overlay closes neither by a click outside, nor by Esc, nor by a button — the user is trapped. | | The loading state covers only the block being updated — the rest of the interface keeps working. | An overlay over the whole area for the sake of a single block stops work with the entire page. | ## Scenarios ### Loading on top of a block While the data of a block is being updated, a `contained` overlay with CdsProgressCircle covers only that block: the user sees that loading is in progress and keeps working with the rest of the page. `persistent` prevents closing the overlay by an accidental click, and `scroll-strategy="none"` does not block the page scroll. **Example — `LoadingBlock.vue`:** ```vue ``` ### Image preview A click on a thumbnail opens the image at full size on top of the dimmed page. A dense scrim (`opacity="0.85"`) removes the visual noise, and the preview closes the usual way — by a click outside or the `Esc` key, no separate button needed. **Example — `ImagePreview.vue`:** ```vue ``` ### Onboarding hint A hint about a new feature is a panel attached to an element by the `connected` strategy; in a real interface you open it programmatically, for example by a first-visit flag, here — by a click on a button. Without a scrim (`:scrim="false"`) the hint does not get in the way of working with the page, `persistent` protects it from an accidental close — it disappears only by the "Понятно" button, and `scroll-strategy="reposition"` keeps it next to the activator on scroll. **Example — `OnboardingHint.vue`:** ```vue ``` ## API ### CdsOverlay **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. | | `captureFocus` | `boolean \| undefined` | — | no | Returns the focus back into the content if it has left it — for example on Tab from the end of the page. A mouse click does not steal the focus. | | `closeDelay` | `string \| number \| undefined` | — | no | Delay in milliseconds before the component closes. Works only together with open-on-hover. | | `closeOnBack` | `boolean \| undefined` | `true` | 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 | | `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` | — | 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 | | `location` | `Anchor \| undefined` | `'bottom'` | no | Sets the anchor point used to position the component, aligning it horizontally, vertically or in both directions | | `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. | | `noClickAnimation` | `boolean \| undefined` | — | no | Disables the bounce effect on a click outside the content element when `persistent` is set. | | `offset` | `string \| number \| number[] \| undefined` | — | 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` | — | 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. | | `persistent` | `boolean \| undefined` | — | no | A click outside the element or the Esc key does not close it. | | `retainFocus` | `boolean \| undefined` | — | no | Traps Tab navigation inside the content: from the last focusable element the focus moves to the first one and back. | | `scrim` | `string \| boolean \| undefined` | `true` | 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` | `'block'` | 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. | | `theme` | `string \| undefined` | — | no | Component theme | | `transition` | `string \| boolean \| (TransitionProps & { component?: Component \| undefined; }) \| null \| undefined` | `'fade-transition'` | 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 | | --- | --- | --- | | `afterEnter` | `[]` | Fires after the opening animation has finished. | | `afterLeave` | `[]` | Fires after the closing animation has finished. | | `click:outside` | `[value: MouseEvent]` | Fires on a click outside the overlay. | | `keydown` | `[value: KeyboardEvent]` | Fires on a key press while the overlay is open. | | `update:modelValue` | `[value: boolean]` | Fires when the overlay opens or closes. 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. | --- # CdsPage _Category: Layouts · since 4.0.0_ _Tests: API 3/3 · 10 unit · 1 known bug · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A page inside the layout: `CdsPage` gives the content a minimum height that accounts for the header and the footer, so a short page fills the whole screen instead of hanging as a narrow strip at the top. **See also:** `CdsPage` lives inside CdsMain — outside it renders nothing and warns about it in the console. The paddings around the whole content area are calculated by CdsLayout. ## Variations ### Paddings The `padding` prop adds inner paddings to the page — the usual layout for content screens. Without it the content sticks to the edges: that is how tables and maps that need the full width are laid out. **Example — `Padding.vue`:** ```vue ``` ### Custom height The `style-fn` prop replaces the minimum height calculation with your own. The function receives the total height of the header and the footer and the height of the layout area, and returns a style string. This is how a page can be fixed in height and give the scrolling to an inner list or table. **Example — `StyleFn.vue`:** ```vue ``` ## Scenarios ### A full-screen empty state The minimum height accounts for the header and the footer, so the centering works against the real height of the page — the placeholder ends up exactly in the middle instead of right under the header. **Example — `FullHeight.vue`:** ```vue ``` ## API ### CdsPage **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `padding` | `boolean \| undefined` | `false` | no | Adds paddings to the page. | | `styleFn` | `((offset: number, height: number) => string) \| undefined` | — | no | Function that computes the styles of the page. It receives the total offset (header + footer) and the height of the area, and returns a style string. | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `any` | Content of the page. | --- # CdsPagination _Category: Navigation · since 4.0.0_ _Tests: API 39/39 · 54 unit · 5 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 8 axe recommendations (v4.0.0-alpha.11)_ Pagination splits a large data set into pages and helps you jump to the one you need: numbered buttons, "back" and "forward" arrows, jumps to the first and the last page, and a quick jump field. Extra numbers collapse into an ellipsis, and without an explicit limit the number of buttons adapts to the width of the container. **See also:** Pagination pages through homogeneous data — a list or a table. To switch between sections of the interface use CdsTabs, and to navigate the hierarchy of pages use CdsBreadcrumbs. ## Anatomy Pagination is a row of page buttons with arrows on the sides. The first and last page buttons appear with `show-first-last-page`, the quick jump field with `quick-jumper`, and the pages between the edges and the neighbors of the current one collapse into an ellipsis. ## Variations ### Number of pages The `length` prop sets the number of pages, `v-model` holds the number of the current one. While the focus is inside the pagination, the ← and → keys page through. **Example — `Default.vue`:** ```vue ``` ### Visible buttons The `total-visible` prop limits how many buttons are visible at once — the remaining pages collapse into an ellipsis (its text is changed by the `ellipsis` prop). Without `total-visible` the component counts how many buttons fit into the container itself and collapses the extra ones. **Example — `TotalVisible.vue`:** ```vue ``` ### Edge pages The `show-first-last-page` prop adds buttons that jump to the first and the last page. The `only-first` value keeps just the first page button — handy when the total number of pages is unknown or only approximate. **Example — `FirstLastPage.vue`:** ```vue ``` ### Quick jump The `quick-jumper` prop adds a field where the user types a page number and gets there on Enter or on blur. The label before the field is changed by the `quick-jumper-label` prop. **Example — `QuickJumper.vue`:** ```vue ``` ### Disabled state The `disabled` prop blocks the whole navigation — while the current page is loading, for example. **Example — `Disabled.vue`:** ```vue ``` ### Slots Slots replace the default buttons while keeping the switching logic: every slot receives a ready `onClick` handler and the `disabled` state. | Slot | Description | | ------- | -------------------------------------------------------------- | | `item` | A single page button; `props` carries everything to pass to it | | `first` | Button that jumps to the first page | | `prev` | Button that jumps to the previous page | | `next` | Button that jumps to the next page | | `last` | Button that jumps to the last page | **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | A long list of pages is collapsed: the edge pages, the neighbors of the current one and an ellipsis stay visible. | A row with every page takes the full width and forces the reader to hunt for the right number. | | The quick jump field helps when there are dozens of pages and paging with arrows takes too long. | With three pages the field is redundant: every page is one click away. | | Pagination appears only when there is more than one page. | A single-page pagination offers no actions — hide it. | ## Scenarios ### Paged list The classic pairing: the list shows the slice of data for the current page, the "Показано 1–4 из 23" caption gives a sense of the total, and `total-visible="3"` keeps the pagination compact next to the counter. **Example — `PagedList.vue`:** ```vue ``` ### Loading pages from the server When the data comes from the server, watch `v-model` (or the `first` / `prev` / `next` / `last` / `quickJump` events) and fire the request on a page change. While the request is in flight, `disabled` blocks the pagination and guards against extra switches. **Example — `ServerLoading.vue`:** ```vue ``` ### Search with a page reset Filtering recalculates the number of pages and resets the current page to the first one — otherwise the user may end up on a page that no longer exists. When the results fit on a single page, the pagination hides. **Example — `SearchReset.vue`:** ```vue ``` ## API ### CdsPagination **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `activeColor` | `string \| undefined` | — | no | Color of the active page button | | `ariaLabel` | `string \| undefined` | `'Навигация по страницам'` | no | ARIA label of the root navigation element | | `color` | `string \| undefined` | — | no | Color of the page buttons | | `currentPageAriaLabel` | `string \| undefined` | `'Текущая страница, страница {0}'` | no | ARIA label of the current (active) page. `{0}` is replaced with the page number | | `disabled` | `boolean \| null \| undefined` | `null` | no | Disabled state | | `ellipsis` | `string \| undefined` | `'...'` | no | Text displayed between pages when they are collapsed | | `firstAriaLabel` | `string \| undefined` | `'Первая страница'` | no | ARIA label of the first page button | | `firstIcon` | `IconValue \| undefined` | `'first-page'` | no | Icon of the first page button | | `lastAriaLabel` | `string \| undefined` | `'Последняя страница'` | no | ARIA label of the last page button | | `lastIcon` | `IconValue \| undefined` | `'last-page'` | no | Icon of the last page button | | `length` | `string \| number \| undefined` | `1` | no | Number of pages | | `modelValue` | `number \| undefined` | `(props) => props.start` | no | The v-model value — the number of the current page | | `nextAriaLabel` | `string \| undefined` | `'Следующая страница'` | no | ARIA label of the next page button | | `nextIcon` | `IconValue \| undefined` | `'chevron-right'` | no | Icon of the next page button | | `pageAriaLabel` | `string \| undefined` | `'Перейти к странице {0}'` | no | ARIA label of a page button. `{0}` is replaced with the page number | | `prevIcon` | `IconValue \| undefined` | `'chevron-left'` | no | Icon of the previous page button | | `previousAriaLabel` | `string \| undefined` | `'Предыдущая страница'` | no | ARIA label of the previous page button | | `quickJumper` | `boolean \| undefined` | `false` | no | Shows the quick jump field | | `quickJumperLabel` | `string \| undefined` | `'Перейти к странице'` | no | Caption text before the quick jump field | | `showFirstLastPage` | `boolean \| "only-first" \| undefined` | `false` | no | Shows the first/last page buttons. `'only-first'` shows only the first page button | | `start` | `string \| number \| undefined` | `1` | no | Initial page | | `tag` | `string \| JSXComponent \| undefined` | `'nav'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `totalVisible` | `string \| number \| undefined` | — | no | Number of page buttons visible at once | **Events** | Name | Type | Description | | --- | --- | --- | | `first` | `[value: number]` | Fired on a jump to the first page | | `last` | `[value: number]` | Fired on a jump to the last page | | `next` | `[value: number]` | Fired on a jump to the next page | | `prev` | `[value: number]` | Fired on a jump to the previous page | | `quickJump` | `[value: number]` | Fired on a jump made through the quick jump field | | `update:modelValue` | `[value: number]` | Fired when the v-model value changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `first` | `CdsPaginationControlSlot` | Slot of the first page button | | `item` | `CdsPaginationItemSlot` | Slot of a single page button | | `last` | `CdsPaginationControlSlot` | Slot of the last page button | | `next` | `CdsPaginationControlSlot` | Slot of the next page button | | `prev` | `CdsPaginationControlSlot` | Slot of the previous page button | **Exposed** | Name | Type | Description | | --- | --- | --- | | `setFirst` | `() => void` | Jumps to the first page. | | `setLast` | `() => void` | Jumps to the last page. | | `setNext` | `() => void` | Jumps to the next page. | | `setPrev` | `() => void` | Jumps to the previous page. | --- # CdsProgressBar _Category: Feedback · since 4.0.0_ _Tests: API 30/30 · 53 unit · 4 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 19 axe recommendations (v4.0.0-alpha.11)_ A linear progress indicator — a horizontal bar for the course of an operation: a file upload, the steps of a wizard, media playback. The value comes from `model-value`, and when the course of the operation is unknown, the `indeterminate` mode turns on a running waiting animation. **See also:** For progress shown as a ring take CdsProgressCircle, and to dim a container while it loads — CdsOverlay. ## Anatomy The bar is built from three layers: the indicator of the current value, the buffer and the background. The content of the `default` slot is drawn on top of the layers. By default the background and the buffer are tinted with the color of the indicator at a high transparency — the intensity is tuned by the `bg-opacity` and `buffer-opacity` props. ## Variations ### Value The `model-value` prop is the current progress. The bar counts from 0 to `max` (100 by default), so you can pass raw values — seconds or megabytes — without converting them into percent. A change of the value is animated with a smooth transition, and `reverse` fills the bar from right to left. **Example — `Value.vue`:** ```vue ``` ### Indeterminate progress The `indeterminate` prop turns on the running animation — use it when the course of the operation is unknown and there is no percentage to show. **Example — `Indeterminate.vue`:** ```vue ``` ### Buffer The `buffer-value` prop is a second bar between the indicator and the background: the part that is already prepared but not passed yet — a preloaded fragment of a video, for example. To make the buffer readable against the bar, raise `buffer-opacity`; a separate color comes from `buffer-color`. **Example — `Buffer.vue`:** ```vue ``` The `stream` prop adds a dashed animation from the edge of the buffer to the end of the bar — a signal that the data keeps coming. The edge of the stream is set by `buffer-value`, and the background is hidden. **Example — `Stream.vue`:** ```vue ``` ### Height The `height` prop sets the height of the bar in pixels. The default is 4. **Example — `Height.vue`:** ```vue ``` ### Rounding The `rounded-bar` prop rounds the leading edge of the indicator. The start stays straight — the bar reads as continuous from the zero mark. **Example — `RoundedBar.vue`:** ```vue ``` ### Colors The `color` prop paints the indicator and — as long as separate colors are not set — the buffer and the background too. Your own background color comes from `bg-color`, and the transparency of the layers from `opacity` for the indicator and `bg-opacity` for the background. **Example — `Colors.vue`:** ```vue ``` ### Stripes The `striped` prop lays running diagonal stripes over the indicator — they bring long operations with a known course to life. **Example — `Striped.vue`:** ```vue ``` ### Segments The `chunk-count` prop splits the bar into equal segments — by the number of steps, for example — while `chunk-width` builds segments of a fixed width. The gap between them comes from `chunk-gap`. The indicator fills segments whole: the value snaps to the edge of the nearest segment. **Example — `Chunks.vue`:** ```vue ``` The `variant="split"` option does not cut the bar into pieces but separates the filled part from the rest with a single gap — the indicator and the background read as two independent segments. **Example — `Split.vue`:** ```vue ``` ### Content The `default` slot renders content in the center of the bar and receives the `value` and `buffer` slot props — normalized percentages. Increase `height` so that the content fits. **Example — `Content.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | When the course of the operation is known, show the value: the user sees how much is left. | An indeterminate animation over known progress hides how long the wait will be. | | A caption next to the bar explains what is happening and what to expect. | Шкала без подписи не отвечает на вопрос «что сейчас загружается?». | | Content inside the bar needs room — increase height so that the text fits. | At the default height the text does not fit and runs over the neighboring content. | ## Scenarios ### File upload The button starts the upload: the bar grows as the data arrives, and the caption above it shows the file and the percentage. The `green` color supports the positive scenario, and once it is done the button offers to upload again. **Example — `FileUpload.vue`:** ```vue ``` ### Wizard steps `chunk-count` set to the number of steps turns the bar into a wizard indicator: filled segments are the steps behind, semi-transparent ones are the steps ahead. The value is the share of the current step out of the total. **Example — `WizardSteps.vue`:** ```vue ``` ### Seeking a video The `clickable` prop turns the bar into a control: a click writes the new value into `v-model`. The buffer shows the preloaded fragment, `stream` shows that the loading continues, and the captions compute the time from the percentages. **Example — `VideoSeek.vue`:** ```vue ``` ### Refreshing the data in a card The `absolute` prop pins the bar to the top edge of a container with `position: relative` — the indicator does not push the content around. The `active` prop hides the bar by smoothly collapsing its height to zero, and `indeterminate` spares you from measuring the progress of a background operation. **Example — `CardRefresh.vue`:** ```vue ``` ## API ### CdsProgressBar **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `absolute` | `boolean \| undefined` | — | no | Absolute positioning of the component | | `active` | `boolean \| undefined` | `true` | no | Controls the active state of the progress bar | | `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 | | `bgOpacity` | `string \| number \| undefined` | — | no | Opacity of the progress bar background | | `bufferColor` | `string \| undefined` | — | no | Color of the buffer part of the progress bar | | `bufferOpacity` | `string \| number \| undefined` | — | no | Opacity of the buffer part of the progress bar | | `bufferValue` | `string \| number \| undefined` | `0` | no | Buffer value of the progress | | `chunkCount` | `string \| number \| undefined` | `null` | no | Number of segments the progress bar is split into | | `chunkGap` | `string \| number \| undefined` | `4` | no | Gap between the segments of the progress bar | | `chunkWidth` | `string \| number \| undefined` | `null` | no | Width of a single segment of the progress bar | | `clickable` | `boolean \| undefined` | — | no | Makes the progress bar clickable | | `color` | `string \| undefined` | — | no | Component color | | `height` | `string \| number \| undefined` | `4` | no | Height of the progress bar | | `indeterminate` | `boolean \| undefined` | — | no | Indeterminate progress state with no fixed value | | `location` | `Anchor \| null \| undefined` | `'top'` | no | Position of the element relative to its container, for example "top left", "center", "bottom right". | | `max` | `string \| number \| undefined` | `100` | no | Maximum progress value | | `modelValue` | `string \| number \| undefined` | `0` | no | Current progress value | | `opacity` | `string \| number \| undefined` | — | no | Opacity of the main progress indicator | | `reverse` | `boolean \| undefined` | — | no | Fills the progress bar in the opposite direction | | `roundedBar` | `boolean \| undefined` | — | no | Rounds the progress indicator | | `stream` | `boolean \| undefined` | — | no | Shows a streaming animation over the progress indicator | | `striped` | `boolean \| undefined` | — | no | Shows stripes on the progress indicator | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `variant` | `"split" \| undefined` | — | no | Display variant of the progress bar segments | **Events** | Name | Type | Description | | --- | --- | --- | | `update:modelValue` | `[value: number]` | Fires when the progress value changes — on a click on the bar in the `clickable` mode | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ value: number; buffer: number; }` | Content above the bar — a caption with the percentage, for example. The params carry the current value and the buffer value | --- # CdsProgressCircle _Category: Feedback · since 4.0.0 · status: new_ _Tests: API 12/12 · 27 unit · lines 100% (v4.0.0-alpha.13) · a11y: 14 axe recommendations (v4.0.0-alpha.11)_ A circular progress indicator shows the course of an operation: a file upload, data processing, a filling quota. The value is set in percent through `model-value`, and when the course of the operation is unknown, the `indeterminate` mode turns on an endless waiting animation. **See also:** For progress shown as a horizontal bar take CdsProgressBar, and to dim a container while it loads — CdsOverlay. ## Variations ### Value The `model-value` prop is the current progress in percent, from 0 to 100. A change of the value is animated with a smooth transition of the arc. **Example — `Value.vue`:** ```vue ``` The `rotate` prop turns the starting point of the arc by the given number of degrees. By default the progress grows clockwise from "12 o'clock". **Example — `Rotate.vue`:** ```vue ``` ### Indeterminate progress The `indeterminate` prop turns on an endless animation — use it when the course of the operation is unknown. The value `disable-shrink` leaves only the rotation without the pulsation of the arc: this animation is simpler and does not load the main thread. It is also enabled automatically for users with the `prefers-reduced-motion` setting. **Example — `Indeterminate.vue`:** ```vue ``` ### Sizes The `size` prop sets the diameter: from `xs` to `xl` or a number in pixels. The default size is `md`. **Example — `Sizes.vue`:** ```vue ``` ### Stroke The `width` prop sets the thickness of the stroke in pixels regardless of the diameter. **Example — `Width.vue`:** ```vue ``` The `rounded` prop rounds the ends of the arc. **Example — `Rounded.vue`:** ```vue ``` ### Colors The `color` prop paints the progress arc, `bg-color` paints the background ring underneath. Both accept color tokens of the design system. **Example — `Colors.vue`:** ```vue ``` ### Content The `default` slot renders content in the center of the ring and receives the current value through the `value` slot prop — a handy way to show the percentage next to the arc. **Example — `Content.vue`:** ```vue ``` ### Reveal animation The `reveal` prop animates the arc from zero to the current value when the component appears. The duration is configured with an object: `:reveal="{ duration: 1500 }"`. **Example — `Reveal.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | When the course of the operation is known, show the value: the user sees how much is left. | An indeterminate animation over known progress leaves the user guessing how long the wait will be. | | A caption next to the indicator explains what is happening and what to expect. | Кольцо без подписи не отвечает на вопрос «что сейчас загружается?». | | For waiting inside a line of text xs is enough — the indicator does not compete with the content. | A large indicator in a line pulls attention away and breaks the vertical rhythm. | ## Scenarios ### File upload The upload progress is visible in the center of the ring through the `default` slot, and once it is done the percentage turns into a success icon. The `rounded` prop softens the arc, and `color` supports the positive scenario. **Example — `FileUpload.vue`:** ```vue ``` ### A filling quota The ring shows not only a process but also a static value — the used storage space, for example. A computed `color` switches the indicator from green to yellow and red as the limit approaches. **Example — `StorageQuota.vue`:** ```vue ``` ### A background operation A compact `indeterminate` indicator of the `xs` size sits in a line with the text and reports that the operation that was started is still running. The caption next to it explains what to expect — without it a spinning ring says nothing. **Example — `ReportGeneration.vue`:** ```vue ``` ## API ### CdsProgressCircle **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `bgColor` | `string \| undefined` | — | no | Background color of the loader | | `color` | `string \| undefined` | — | no | Color of the loader | | `indeterminate` | `boolean \| "disable-shrink" \| undefined` | — | no | Shows the animation continuously; use it when the course of the loading is unknown. The string `disable-shrink` switches to a simpler animation that does not run on the main thread | | `modelValue` | `string \| number \| undefined` | `0` | no | Current loading progress in percent | | `reveal` | `boolean \| { duration?: number \| undefined; } \| undefined` | `false` | no | Animates the indicator from zero to the current value when the component appears. The `{ duration }` object sets the animation duration in milliseconds | | `rotate` | `string \| number \| undefined` | `0` | no | Turns the starting point of the circle by the given number of degrees | | `rounded` | `boolean \| undefined` | — | no | Rounds the ends of the progress arc | | `size` | `number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" \| undefined` | `'md'` | no | Size of the component | | `tag` | `string \| JSXComponent \| undefined` | `'div'` | no | Custom HTML tag or component to render | | `theme` | `string \| undefined` | — | no | Component theme | | `width` | `string \| number \| undefined` | `4` | no | Sets the thickness of the circle stroke in pixels | **Slots** | Name | Type | Description | | --- | --- | --- | | `default` | `{ value: number; }` | Default slot. Carries the progress value of the loading indicator. | --- # CdsRadio _Category: Controls · since 4.0.0_ _Tests: API 29/29 · 30 unit · 5 known bugs · lines 100% (v4.0.0-alpha.13)_ A radio button is one option of a mutually exclusive choice. It is not used on its own: the buttons are joined by CdsRadioGroup — it keeps the selected value, captions the set and shows the messages. The button is left with `value` — the value of the option, `label` and `description` — its caption and details. **See also:** Examples, guidelines and scenarios are on the CdsRadioGroup page. For an independent on/off option take CdsCheckbox. ## API ### CdsRadio **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` | `'radio-off'` | 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` | `'radio-on'` | 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 | **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 | --- # CdsRadioGroup _Category: Controls · since 4.0.0_ _Tests: API 59/59 · 60 unit · 9 known bugs · lines 100% (v4.0.0-alpha.13) · a11y: 4 axe recommendations (v4.0.0-alpha.11)_ A radio group is a choice of one option out of a short mutually exclusive set: a payment method, a plan, a report period. The group keeps the selected value, captions the set with a heading and a description, shows messages and errors; the options themselves are CdsRadio components with their own `value`. **See also:** For independent options that are turned on separately use CdsCheckbox, for an on/off setting that applies immediately — CdsToggle. If there are more than five options, fold the list into CdsSelect. ## Anatomy The heading and the description caption the whole set, below them are the radio buttons: each one has a control with a state icon, a label and an optional description. At the bottom is the common messages block of the group. A click on the label selects the button exactly like a click on the control. ## Variations ### Heading and description The `label` prop names the group, `description` explains the choice. Every button has its own `label` and `description`: name the option briefly in the label and move the details — the price, the deadlines, the limits — into the description. **Example — `LabelAndDescription.vue`:** ```vue ``` ### Direction By default the buttons are stacked in a column. `direction="horizontal"` puts them in a row — handy for short sets of two or three options such as a period or a sort order. **Example — `Direction.vue`:** ```vue ``` ### States `disabled` blocks the whole group and lowers the contrast, `readonly` forbids changing the choice but does not change the appearance. A single option is blocked by the `disabled` prop of the button itself. **Example — `States.vue`:** ```vue ``` ### Messages and errors `messages` shows a supporting text under the group, `error-messages` — a ready error message (the one coming from the server, for example) together with the error state on all the buttons. Validation rules through `rules` are in the "Submitting a form" scenario. `hide-details` removes the bottom block entirely. **Example — `Messages.vue`:** ```vue ``` ### Colors `color` sets the color of the selected button, `base-color` — of the unselected ones. The values apply to all the buttons of the group at once. **Example — `Colors.vue`:** ```vue ``` ### Slots When the text props are not enough, the content of the blocks is replaced by slots — both on the group and on every button. | Slot name | Description | | :------------ | :-------------------------------------------------------- | | `label` | Content of the group heading (replaces `label`) | | `description` | Content of the group description (replaces `description`) | | `prepend` | Element before the set of buttons | | `append` | Element after the set of buttons | | `messages` | Content of the messages block | | `details` | The whole bottom block | `CdsRadio` has its own `label` and `description` slots — to highlight a part of the text or add an icon, for example. **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | Radio buttons are for mutually exclusive options: exactly one can be selected. | Radio buttons do not fit independent options that are turned on together — use checkboxes. | | Preselect a default option — usually the most common or the safest one. | A group with no selected value makes the user guess what the form will submit if nothing is picked. | | Up to five options — radio buttons: the whole set is visible and the choice takes one click. | A long list bloats the form — fold it into CdsSelect. | ## Scenarios ### Submitting a form The choice is required: a rule in `rules` returns the error text while no value is selected. The button starts the check through the `validate()` of the CdsForm. **Example — `PaymentForm.vue`:** ```vue ``` ### Choosing a plan The descriptions of the buttons state the conditions, and the computed total under the group is updated on every choice — the user sees the consequences right away. **Example — `TariffChoice.vue`:** ```vue ``` ### Sorting a list A horizontal group with `hide-details` works as a sorting panel: the selected value rebuilds the list on the fly through a computed. **Example — `SortList.vue`:** ```vue ``` ## API ### CdsRadioGroup **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `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 | | `bgColor` | `string \| undefined` | — | no | Background color of the component | | `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` | `'vertical'` | 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` | `'radio-off'` | no | Icon of an unselected radio button | | `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. | | `height` | `string \| number \| undefined` | `'auto'` | no | Height of the component | | `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 | | `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 | | `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 | | `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 | | `textColor` | `string \| undefined` | — | no | Text color of the component | | `theme` | `string \| undefined` | — | no | Component theme | | `trueIcon` | `IconValue \| undefined` | `'radio-on'` | no | Icon of a selected radio button | | `type` | `string \| undefined` | `'radio'` | no | Type of the native input element of the group buttons | | `validateOn` | `ValidateOn \| undefined` | — | no | Changes the type of the event that triggers validation | | `validationValue` | `any` | — | no | Value used when applying the validation rules | | `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:modelValue` | `[value: any]` | Fires when the model of the component changes | **Slots** | Name | Type | Description | | --- | --- | --- | | `append` | `CdsInputSlot` | Adds an element after the input | | `default` | `any` | Default slot — the radio buttons of the group (`CdsRadio`) | | `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 | | `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 | **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 | --- # CdsResponsive _Category: Atoms · since 4.0.0 · status: new_ _Tests: API 11/11 · 11 unit · lines 100% (v4.0.0-alpha.13) · a11y: 1 axe recommendation (v4.0.0-alpha.11)_ A frame with constant proportions. Set `aspect-ratio` and the height of the block is calculated from its width on any screen. Anything that needs a fixed shape goes inside: a video, a map, an `iframe`, a category tile. The space for the content is taken right away, so the layout does not jump while it loads. **See also:** For photos take CdsImage — it is built on `CdsResponsive` and can also do lazy loading, a placeholder and cropping. If you need the columns of a page rather than the shape of a single block, take CdsGrid. ## Variations ### Aspect ratio The `aspect-ratio` prop accepts a fraction (`16/9`) or a number (`1.7778`). The width comes from the parent, the height is calculated by the component itself — and recalculated on every change of the width. The calculated height works as a minimum: content that does not fit into it stretches the frame and breaks the proportions. **Example — `AspectRatio.vue`:** ```vue ``` ### Sizes By default the frame takes the whole width of its parent. The `width`, `max-width` and `min-width` props limit it, and `height`, `max-height` and `min-height` limit its height; numbers turn into pixels, strings go into CSS as they are. **Example — `Sizes.vue`:** ```vue ``` ### Layout The `inline` prop turns the frame into `inline-flex` — it stops stretching and stands in a row with its neighbors. Set the width yourself in this case: it will not take it from the content. **Example — `Inline.vue`:** ```vue ``` ### Slots The height of the frame is held by an invisible spacer, and the content lies on top of it. Hence two slots with different jobs. | Slot | Description | | ------------ | ----------------------------------------------------------------------------------- | | `default` | The main content inside a wrapper — it takes the whole frame | | `additional` | Content without a wrapper, on top of the spacer — for backdrops and absolute layers | The `content-class` prop puts classes on the wrapper of the `default` slot — that is how the inner paddings and the layout are set. The root of the component is positioned (`position: relative`), so the elements from `additional` can be placed absolutely relative to the frame. **Example — `Slots.vue`:** ```vue ``` ## Guidelines | ✅ Do | ❌ Don't | | --- | --- | | The proportions are set in advance — the space for the widget is taken and the text below it is already in place. | A placeholder shorter than the future widget: when it arrives, everything below jumps down. | | For images take CdsImage — it can do proportions, lazy loading and a placeholder. | An img tag inside CdsResponsive repeats CdsImage by hand and stays without lazy loading. | | The content is stretched to the full height of the frame — the proportions hold. | Content taller than the frame stretches it: the set proportions are lost and the neighboring blocks stop lining up. | ## Scenarios ### An embedded map or video Maps and video players arrive in an `iframe` with proportions of their own. Wrap the `iframe` into a `CdsResponsive` with the right `aspect-ratio` and stretch it with the `h-full w-full` classes — the player will look the same on a wide monitor and on a phone. **Example — `EmbeddedMap.vue`:** ```vue ``` ### A grid of tiles In a grid of categories the tiles have to be square regardless of the length of the caption. The `aspect-ratio="1"` value gives a square, and the width of every tile comes from the grid column — the number of columns changes the size, not the shape. **Example — `TileGrid.vue`:** ```vue ``` ### Space for a widget while it loads A report, a chart or a map arrives from the server a second or two later. A frame with proportions takes their place right away: while the loader spins inside, the caption and the buttons below the widget stay exactly where they will end up after the loading. **Example — `LoadingPlaceholder.vue`:** ```vue ``` ### Switching the proportions The `aspect-ratio` value is reactive and the change of the height is animated — a crop switcher does not jerk the neighboring blocks. **Example — `RatioSwitch.vue`:** ```vue ``` ## API ### CdsResponsive **Props** | Prop | Type | Default | Required | Description | | --- | --- | --- | --- | --- | | `aspectRatio` | `string \| number \| undefined` | — | no | Aspect ratio of the content. For example `1.7778` (16/9) or `'4/3'`. | | `contentClass` | `any` | — | no | CSS class applied to the content wrapper. | | `height` | `string \| number \| undefined` | — | no | Component height | | `inline` | `boolean \| undefined` | — | no | Renders the component as an inline block (`inline-flex`) instead of a block one. | | `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 | | `width` | `string \| number \| undefined` | — | no | Component width | **Slots** | Name | Type | Description | | --- | --- | --- | | `additional` | `any` | Extra content rendered on top of the sizer, outside the content wrapper. | | `default` | `any` | The main content of the component, wrapped so the aspect ratio is kept. | --- # CdsSelect _Category: Controls · since 4.0.0_ _Tests: API 127/127 · 80 unit · 10 e2e · 11 known bugs · lines 64.1% (v4.0.0-alpha.13) · a11y: 5 axe recommendations (v4.0.0-alpha.11)_ A select opens a dropdown list and lets you pick one or several values from a known set: a country, a status, a category. The field is built on CdsTextInput, so the label, the description, the messages, validation and the states work exactly as in a text field. **See also:** For two or three options take CdsRadioGroup — the options are visible right away. If the list is long and the user searches by typing, use CdsAutocomplete, and if values outside the list are allowed — CdsCombobox. ## Anatomy The first diagram shows the frame of the component: the label, the description, the field and the messages block. The second one shows how the field itself is built: the zone of the selected values, the clear button and the menu indicator; the inner and outer icon zones are the same as in CdsTextInput. ## Variations ### List items The list is set by the `items` prop — an array of strings or of objects with the same interface as in CdsList. While no value is selected, the field shows the `placeholder`. **Example — `Default.vue`:** ```vue ``` ### Your own data fields When the objects come from the server as they are, use `item-title` and `item-value` to say which fields the title and the value are taken from. `return-object` puts the whole object into `v-model` instead of just the value. **Example — `CustomItems.vue`:** ```vue ``` ### Grouping Split a long list into meaningful blocks: an item with `type: 'subheader'` adds a subheader, one with `type: 'divider'` — a divider. Such items cannot be selected. **Example — `Grouping.vue`:** ```vue ``` ### Multiple selection The `multiple` prop allows selecting several values: the items get checkboxes and the field lists the selection separated by commas. `ellipsis` keeps the listing on a single line and cuts the rest off with an ellipsis. **Example — `Multiple.vue`:** ```vue ``` ### Selecting all the values The `is-select-all` prop adds a "select all" entry as the first item of the list (works together with `multiple`). The `true` value uses the default caption, a string sets your own. **Example — `SelectAll.vue`:** ```vue ``` ### Chips The `chips` prop shows the selected values as CdsTag tags, `closable-chips` adds a cross to them — a value is removed right in the field, without opening the menu. **Example — `Chips.vue`:** ```vue ``` ### Native list The `native-select` prop replaces the custom menu with a native `