segmented select

This is a fairly general-purpose segmented select control.

<div class="grid">
  <tosi-segmented value="yes" choices="yes, no, don't care">
    Should we?
  </tosi-segmented>

  <div>
    <b>Localized!</b><br>
    <tosi-segmented
      localized
      title="do you like?"
      choices="yes=Yes:thumbsUp, no=No:thumbsDown"
    ></tosi-segmented>
  </div>

  <tosi-segmented
    style="--segmented-direction: column; --segmented-align-items: stretch"
    choices="in a relationship, single"
    other="it's complicated..."
    placeholder="please elaborate"
    value="separated"
  >
    Relationship Status
  </tosi-segmented>

  <tosi-segmented
    multiple
    style="--segmented-direction: column; --segmented-align-items: start; --segmented-option-grid-columns: 24px 24px 100px; --segmented-input-visibility: visible;"
    choices="star=Star:star, game=Game:game, bug=Bug:bug, camera=Camera:camera"
    value="star,bug"
  >
    Pick all that apply
  </tosi-segmented>
</div>
.preview .grid {
  --segmented-option-current-background: var(--brand-color);
  --segmented-option-current-color: var(--brand-text-color);
  padding: 16px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
function logEvent(event) {
  const { target } = event
  if (target.matches('tosi-segmented')) {
    console.log((target.textContent || target.title).trim(), target.value)
  }
}
preview.addEventListener('change', logEvent, true)
const segmented = preview.querySelectorAll('tosi-segmented')
test('segmented controls render', () => {
  expect(segmented.length).toBe(4)
})
test('first segmented has value "yes"', () => {
  expect(segmented[0].value).toBe('yes')
})
test('multiple segmented has array value', () => {
  expect(segmented[3].value).toBe('star,bug')
})

Check the console to see the values being set.

Form Integration

<tosi-segmented> is form-associated, meaning it works directly in native <form> elements:

<form class="segmented-form">
  <tosi-segmented name="choice" choices="a,b,c" required></tosi-segmented>
  <button type="submit">Submit</button>
  <span class="output"></span>
</form>
const form = preview.querySelector('.segmented-form')
form.addEventListener('submit', (e) => {
  e.preventDefault()
  const data = new FormData(form)
  form.querySelector('.output').textContent = 'Submitted: ' + data.get('choice')
})

Properties

You can set choices programmatically to an array of Choice objects:

interface Choice {
  icon?: string | SVGElement
  value: string
  caption: string
}

Attributes

Styling

The following CSS variables can be used to control customize the <tosi-segmented> component.

--segmented-align-items
--segmented-direction
--segmented-option-color
--segmented-option-current-background
--segmented-option-current-color
--segmented-option-font
--segmented-option-gap
--segmented-option-grid-columns
--segmented-option-icon-color
--segmented-option-padding
--segmented-options-background
--segmented-options-border-radius
--segmented-placeholder-opacity