Skip to content

OSegmented ​

OSegmented is a compact group of two to six mutually exclusive choices, such as a Monthly / Yearly billing toggle or a row of list filters. The active option has a filled background, and each option can show a counter.

Usage ​

Step by step ​

  1. Import OSegmented from the ooko-ui/segmented public subpath.
  2. Pass the choices through options and bind the selected value with v-model.
  3. Give the group an accessible name with aria-label or aria-labelledby; add count to an option to show its counter.

Example ​

The rendered example and its source come from the same Vue single-file component.

Interactive playground ​

Change the selected option, the number of options, the counters, and the disabled state. The preview updates immediately.

Props ​

PropTypeDefaultDescription
modelValueValueundefinedCurrently selected option value.
optionsreadonly OSegmentedOption<Value>[]undefinedMutually exclusive options, intended for two to six choices.
disabledbooleanfalsePrevents every selection change.
softbooleanfalseMarks the selected option with a primary tint and primary text instead of a solid fill, for busy filter bars.

Events ​

EventPayloadDescription
update:modelValueValueEmits the selected option value after a native selection change.

Slots ​

SlotPropsDescription
nonenoneNo slots are exposed.
TypeDefinition
OSegmentedOptioninterface OSegmentedOption<Value extends OSegmentedValue = OSegmentedValue> { /** Value emitted when this option is selected. */ value: Value; /** Visible option label. */ label: string; /** Optional counter displayed after the label. */ count?: number; }
OSegmentedValuetype OSegmentedValue = number | string;

CSS custom properties ​

Custom propertyDefaultDescription
--o-segmented-paddingvar(--o-space-0-5)Sets the space between the track edge and its options.
--o-segmented-option-paddingvar(--o-space-1) var(--o-space-3)Sets the inner spacing of each option.
--o-segmented-border-radiusvar(--o-radius-round)Sets the track corner radius; option corners derive from it.
--o-segmented-focus-width0.125remSets the focus outline width.
--o-segmented-disabled-opacity0.5Sets the opacity of a disabled control.
--o-segmented-scroll-fade-widthvar(--o-space-8)Sets the width of the fade on an edge that still hides options.

Override example ​

css
:root {
  --o-segmented-border-radius: var(--o-radius-round);
  --o-segmented-option-padding: var(--o-space-1-5) var(--o-space-4);
}

Accessibility ​

The root has the radiogroup role and receives native attributes such as aria-label or aria-labelledby, which name the group. Each option is a native radio inside its label, so the option text and its counter form the accessible name. The group is a single tab stop; arrow keys move the selection between options, and the focused option shows a visible outline. disabled disables every radio natively and sets aria-disabled on the group. The selected state does not rely on color alone in forced-colors mode, which uses system highlight colors.

Behavior and edge cases ​

modelValue is controlled: selecting an option emits update:modelValue with its value, and the parent updates the binding. Values are strings or numbers and are compared with Object.is; a value that matches no option leaves every option unselected. A counter of 0 is displayed, while an option without count shows none. The radios share an SSR-stable generated name, so several groups on a page stay independent. soft marks the selected option with a primary tint and primary text instead of a solid fill, which suits busy filter bars. When the options do not fit their container, such as on a narrow screen, the track scrolls horizontally instead of overflowing the page: an edge that still hides options fades out over --o-segmented-scroll-fade-width, and the selected option is scrolled into view on mount and whenever modelValue changes. OSegmented exposes no app defaults. The packer combines component CSS in style.css; component-level CSS isolation is not claimed.