--- title: Cycle Toggle description: Cycle through exclusive values with a single button press. category: Actions --- import { meta as CycleToggleMeta, Default, SortOrder } from '@/content/stories/cycle-toggle'; import Canvas from '@/components/component-docs/canvas'; import Demo from '@/components/component-docs/demo'; export const config = { dependencies: { components: [Canvas, Demo], scripts: [ '../../components/component-docs/demo.script.tsx', '../../components/component-docs/canvas.script.tsx', '../../components/component-docs/controls.script.tsx', ], }, }; # Cycle Toggle

Cycle toggles advance through a fixed set of values on each click, such as theme preference, sort order, or any small exclusive choice.

## Try it ## Usage Compose `RuiCycleToggleItem` children inside `RuiCycleToggle`. Only the active item is visible in the button. Listen for `rui-change` to react to the new `detail.value`. ```tsx import { RuiCycleToggle, RuiCycleToggleItem } from '@ecopages/radiant-ui/cycle-toggle'; System Light Dark ``` ## Custom markup `` coordinates any light-DOM tree that matches its query contract. The `Rui*` helpers stamp these targets; they are not required. ```tsx import '@ecopages/radiant-ui/cycle-toggle'; ``` BEM classes are presentation-only. Do not set `hidden` on items — the host owns visibility. ## Sort order ## Theming The cycle button reuses the **`rui-button` action roles**, never Tailwind palette steps. `variant` / `size` map straight to the button system: | Part | CSS roles | | --- | --- | | Button (`.rui-cycle-toggle__button`) | `rui-button` chrome, `primary` filled, `on-surface` ghost, `error` destructive | | Item (`.rui-cycle-toggle__item`) | `space-inline` gap | Button geometry (`--size-control-*`, `--radius-control`) is inherited from `rui-button` so the cycle control aligns with form rows. Override at the theme layer, not in component CSS. ## API `RuiCycleToggle` is a custom element (``); the view composes the inner `rui-button`. ### Attributes | Attribute | Type | Default | Description | | --- | --- | --- | --- | | `value` | `string` | `''` | Active item id. | | `variant` | `filled` · `outline` · `destructive` · `ghost` · `link` | `filled` | Button variant passed to the inner button. | | `size` | `none` · `sm` · `md` · `lg` | `md` | Button size passed to the inner button. | | `label` | `string` | `''` | Accessible name prefix for the cycle button. | | `disabled` | `boolean` | `false` | Disables the cycle button. | ### Light-DOM contract | Target | Required | Host writes | Author owns | | --- | --- | --- | --- | | `button[data-cycle-toggle-button]` | yes | `aria-label`, `disabled`, `rui-button--*` classes | the button element | | `[data-cycle-value]` | yes (per item) | `hidden` | `data-cycle-value`, `aria-disabled` | Do not set `hidden` on items. Nested hosts: none. ### Events | Event | Detail | Description | | --- | --- | --- | | `rui-change` | `{ value: string }` | Emitted after `value` advances; `detail.value` is the new id. | ### Methods | Method | Description | | --- | --- | | `resync()` | Re-apply button labeling and visible item from the current `value`. | ### View helpers | Component | Target stamped | Notes | | --- | --- | --- | | `RuiCycleToggle` | `` + `RuiCycleToggleButton` | Wraps items in the button. | | `RuiCycleToggleItem` | `[data-cycle-value]` | Pass `id`; maps to `data-cycle-value`. | | `RuiCycleToggleButton` | `button[data-cycle-toggle-button]` | Composes `rui-button` variant/size classes. | ### CSS classes Public BEM classes (documented via `@cssclass`): | Class | Description | | --- | --- | | `.rui-cycle-toggle__button` | Cycle toggle button root (adds `rui-button rui-button--*`). | | `.rui-cycle-toggle__item` | Cycle option row (icon + label). | ### Theme roles | Part | CSS variables consumed | | --- | --- | | Button chrome | `--primary`, `--on-primary`, `--size-control-*`, `--radius-control` (via `rui-button`) | | Item | `--space-inline` | ## Accessibility - The host `label` sets `aria-label` on the cycle button. - Item children can include visible text, icons, or screen-reader-only labels. - Space and Enter activate the native button.