Primitives
18

SegmentedControl

A row of mutually exclusive options — which is to say, a radiogroup, and built as one. The radios are hidden by paint only, never by display: none: that would take them out of the tab order and out of the group the arrow keys walk. The browser keeps giving exclusive selection and navigation; the label only draws.

plain markup — no library on the page
rendered by aura-react
rendered by aura-vue
rendered by aura-svelte
built from aura-angular's own class helpers

Code

index.html
<fieldset role="radiogroup" aria-label="Theme" class="aura-segmented">
  <label class="aura-segmented__option">
    <input type="radio" class="aura-segmented__input" name="theme" value="light" checked />Light
  </label>
  <label class="aura-segmented__option">
    <input type="radio" class="aura-segmented__input" name="theme" value="dark" />Dark
  </label>
  <label class="aura-segmented__option">
    <input type="radio" class="aura-segmented__input" name="theme" value="system" disabled />System
  </label>
</fieldset>
Demo.tsx
import { SegmentedControl } from '@ilomee/aura-react';

const OPTIONS = [
  { value: 'light', label: 'Light' },
  { value: 'dark', label: 'Dark' },
  { value: 'system', label: 'System', disabled: true },
];

export default function Demo() {
  return <SegmentedControl label="Theme" name="theme" options={OPTIONS} defaultValue="light" />;
}
Demo.vue
<script setup lang="ts">
import { ref } from 'vue';
import { SegmentedControl } from '@ilomee/aura-vue';

const theme = ref('light');
</script>

<template>
  <SegmentedControl
    v-model="theme"
    label="Theme"
    :options="[
      { value: 'light', label: 'Light' },
      { value: 'dark', label: 'Dark' },
    ]"
  />
</template>
Demo.svelte
<script lang="ts">
  import { SegmentedControl } from '@ilomee/aura-svelte';

  let theme = $state('light');
</script>

<SegmentedControl
  bind:value={theme}
  label="Theme"
  options={[
    { value: 'light', label: 'Light' },
    { value: 'dark', label: 'Dark' },
  ]}
/>

Used as aura-segmented-control.

demo.component.ts
import { AuraSegmentedControl } from '@ilomee/aura-angular';

@Component({
  standalone: true,
  imports: [AuraSegmentedControl],
  template: `<aura-segmented-control label="Theme" [options]="options" [(value)]="theme" />`,
})
export class DemoComponent {
  theme = 'light';
  options = [
    { value: 'light', label: 'Light' },
    { value: 'dark', label: 'Dark' },
  ];
}

Props

Plain markup has no props — the classes below are the whole API. The four packages do nothing more than set these same classes for you.
NameTypeDefaultNotes
labelstring
optionsAuraOption[] | null
valuestring
defaultValuestring''
onValueChange(value: string) => void
namestringThe generated id comes from the framework itself, so it is stable across SSR and hydration.
disabledboolean
NameTypeDefaultNotes
labelstring
optionsAuraOption[] | null
modelValuetwo-waystring
defaultValuestring''
namestringThe generated id comes from the framework itself, so it is stable across SSR and hydration.
disabledbooleanfalse
update:modelValueevent(value: string) => void
NameTypeDefaultNotes
labelstring
optionsAuraOption[] | null
valuetwo-waystring''
namestringThe generated id comes from the framework itself, so it is stable across SSR and hydration.
disabledbooleanfalse
onchange(value: string) => void
NameTypeDefaultNotes
labelstring
optionsAuraOption[] | null[]
valuestring''
namestring
disabledbooleanfalse
valueChangeeventEventEmitter<string>

Emitted classes

Every framework emits the same classes — that is what makes the four libraries look identical. You can use them directly, without any component library.

ClassRoleNotes
.aura-segmentedbaseRequired. A modifier does nothing without it.
.aura-segmented__optionelement
.aura-segmented__inputelement

Tokens and rules

components.css
track
var(--surface-2) · var(--r2)
selected
var(--surface) + var(--shadow-1), via :has(:checked)
keyboard
native — arrows move and select