Segmented

Pick one option from a row of buttons.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrSegmented } from 'ngwr/segmented';

@Component({ imports: [WrSegmented] })
export class MyComponent {}

Basic usage

Bind the picked value with [(value)] or any Angular form.

Value: week
<wr-segmented [options]="options" [(value)]="range" />

With icons

Give an option an icon; an icon-only one needs an ariaLabel.

Value: light
<wr-segmented
  [options]="[
    { value: 'light', label: 'Light', icon: 'sun' },
    { value: 'dark', label: 'Dark', icon: 'moon' },
  ]"
  [(value)]="mode"
/>

Signal Forms

Inside <wr-form-field>, [formField] binds the value and the field labels the strip and shows its errors.

import { Component, signal } from '@angular/core';
import { FormField, form, required } from '@angular/forms/signals';
import { WrFormField } from 'ngwr/form';
import { WrSegmented, type WrSegmentedOption } from 'ngwr/segmented';

@Component({
  selector: 'app-schedule',
  imports: [FormField, WrFormField, WrSegmented],
  template: `
    <wr-form-field label="Range">
      <wr-segmented [options]="ranges" [formField]="schedule.range" />
    </wr-form-field>
  `,
})
export class ScheduleComponent {
  protected readonly ranges: readonly WrSegmentedOption<string>[] = [
    { value: 'day', label: 'Day' },
    { value: 'week', label: 'Week' },
    { value: 'month', label: 'Month' },
  ];

  private readonly model = signal({ range: '' });
  protected readonly schedule = form(this.model, path => {
    required(path.range, { message: 'Pick a range.' });
  });
}

Keyboard

Tab moves between segments; Enter / Space picks one.

Types

interface WrSegmentedOption<T = unknown> {
  value: T;
  label?: string;
  icon?: WrIconName;
  disabled?: boolean;
  /** Accessible name for an icon-only segment, which has no text to read. */
  ariaLabel?: string;
}
NameDescriptionTypeDefault
ariaLabelAccessible name for an icon-only option. Falls back to value.string—
WrSegmentedOptionOne entry in the track.interface—
valuerequiredModel value when this segment is picked.T—
labelVisible text; omit for icon-only segments.string—
iconLeading icon.WrIconName—
disabledDisable this segment.booleanfalse

API

NameDescriptionTypeDefault
optionsrequiredThe segments to render.readonly WrSegmentedOption<T>[]—
valueThe picked segment's value, null when nothing is selected. Bound by [formField], or two-way via [(value)].T | nullnull
(touch)Emitted when focus leaves the strip, so a bound field can mark itself touched.void—
disabledDisable the whole control. Bound automatically from the field's disabled state when used with [formField].booleanfalse
readonlyRefuse changes while every segment stays focusable and the value still submits. Bound automatically from the field's readonly state when used with [formField]. NOTHING is mirrored into ARIA here, deliberately: the strip is a role="group" of aria-pressed buttons, and ARIA defines aria-readonly for neither role — it is a state of checkbox / radiogroup / textbox and their kin, and it is not global. aria-disabled is the only attribute that would apply to a button, and it says the wrong thing: these segments are still focusable and the value still submits. So the state is honest in the DOM (wr-segmented--readonly) and silent in the accessibility tree rather than announced with a word that means something else.booleanfalse
sizeControl size — shares the --wr-control-* contract.WrSegmentedSize'md'

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/segmented's own element.

VariableDefaultDeclared on
--wr-segmented-bgvar(--wr-color-fill).wr-segmented
--wr-segmented-colorvar(--wr-color-on-surface).wr-segmented
--wr-segmented-font-familyvar(--wr-font-family-base).wr-segmented
--wr-segmented-font-sizevar(--wr-text-sm).wr-segmented +2 variant overrides
--wr-segmented-line-heightvar(--wr-control-line-height-md).wr-segmented +2 variant overrides
--wr-segmented-option-gapvar(--wr-space-sm).wr-segmented
--wr-segmented-option-pxvar(--wr-control-padding-x-md).wr-segmented
--wr-segmented-option-py0.125rem.wr-segmented +2 variant overrides
--wr-segmented-padding0.1875rem.wr-segmented +2 variant overrides
--wr-segmented-radius0.5rem.wr-segmented +2 variant overrides
--wr-segmented-selected-bgvar(--wr-color-surface).wr-segmented
--wr-segmented-selected-colorvar(--wr-color-on-surface).wr-segmented
--wr-segmented-thumb-count1.wr-segmented
--wr-segmented-thumb-index0.wr-segmented
--wr-segmented-thumb-radiuscalc(var(--wr-segmented-radius) - var(--wr-segmented-padding)).wr-segmented

Dependencies

Built onForm, Icon
Used byColor Picker

See also