tai-ui TradeAIAlgo UI library
Theme LightDarkSystem

Component

Segmented control

Pick one value from a short set — an index, a market view, a timeframe. It looks like a row of buttons and behaves like a radio group, and it takes part in forms like a native input.

  • 2.1.1 Keyboard
  • 1.3.1 Info and relationships
  • 1.4.1 Use of colour
  • 2.4.7 Focus visible
  • 3.3.2 Labels or instructions
  • 4.1.2 Name, role, value

Examples

Index picker (the Trading Desk uses this)
Index NIFTY BANK NIFTY FINNIFTY SENSEX
HTML

<div class="row">
  <span id="index-label" class="muted">Index</span>
  <tai-segmented aria-labelledby="index-label" value="NIFTY" id="index-picker">
    <tai-option value="NIFTY">NIFTY</tai-option>
    <tai-option value="BANKNIFTY">BANK NIFTY</tai-option>
    <tai-option value="FINNIFTY">FINNIFTY</tai-option>
    <tai-option value="SENSEX" disabled>SENSEX</tai-option>
  </tai-segmented>
</div>
<div class="log" role="log" aria-label="Index picker events" id="log-index"></div>
In a form — submits, resets and validates like a native radio set
Market view (required) Bullish Bearish Non-directional

HTML

<form id="view-form" class="stretch">
  <fieldset style="border:0;padding:0;margin:0 0 1rem">
    <legend class="label" style="font-weight:500;margin-bottom:.4rem">Market view <span class="muted">(required)</span></legend>
    <tai-segmented name="view" required label="Market view">
      <tai-option value="bullish">Bullish</tai-option>
      <tai-option value="bearish">Bearish</tai-option>
      <tai-option value="neutral">Non-directional</tai-option>
    </tai-segmented>
  </fieldset>
  <div class="row">
    <button class="btn btn--primary" type="submit">Suggest strategies</button>
    <button class="btn" type="reset">Reset</button>
  </div>
  <p class="hint" id="form-result" role="status"></p>
</form>

API

NameKindDescription
valueattribute / propertySelected option's value. Reflects. Setting it doesn't fire events.
labelattributeAccessible name (or use aria-labelledby pointing at a visible label).
nameattributeForm field name; the value is submitted with the form.
requiredattributeThe form won't submit until something is chosen (valueMissing).
disabledattributeDisables the whole group (also follows a disabled <fieldset>).
form, validity, checkValidity(), reportValidity()properties / methodsForm-associated custom element API via ElementInternals.
changeeventThe user chose an option — like a native radio.
tai-changeeventSame moment, with detail: { value, previousValue }. Use this one from React.
tai-option → value, disabledchild attributesEach choice. The value defaults to its text.
checkpart (on tai-option)The check mark shown on the selected option.

Keyboard

KeyAction
TabInto the group lands on the selected option (or the first, if none). One Tab stop for the whole group.
→ ↓ / ← ↑Select the next / previous option, wrapping and skipping disabled ones.
SpaceSelects the focused option if it isn't already.

Accessibility notes

Why radio semantics for something that looks like buttons

Three toggle buttons would each be a Tab stop and say “pressed / not pressed”, which doesn't tell a screen reader user that exactly one can be on. A radio group says “1 of 4, selected” and moves with arrow keys. In the app, the Trading Desk index picker already had role="radio" but no arrow keys — every option was a Tab stop, which is the half-done version of this.

  • Form-associated through ElementInternals: name/value are submitted, form reset restores the initial value, required blocks submission with the browser's own validation message.
  • Selection isn't colour alone: the chosen option is raised, outlined and shows a check mark.
  • Forced colours: the selected option gets a system Highlight outline.

Usage guidance

Do

  • Use for 2–5 short, mutually exclusive options.
  • Give the group a visible label and point aria-labelledby at it.

Don't

  • Use it to switch between panels of content (that's tabs).
  • Use it for actions (“Run”, “Stop”) — those are buttons.
  • Let it wrap onto many lines; use a select instead.

Using it in React

Listen to ontai-change: React's own onChange is wired to its synthetic event system for native inputs, not to custom elements.

JS

<tai-segmented label="Index" value={symbol} ontai-change={e => setSymbol(e.detail.value)}>
  {INDICES.map(s => <tai-option key={s} value={s}>{s}</tai-option>)}
</tai-segmented>