Cycle Button

One compact native button that cycles an ordered set of named icon states without moving focus.

Cycling appearance

One native button cycles Automatic, Light and Dark while preserving keyboard focus.

Appearance

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-cluster/ui-cluster.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-cycle-button/ui-cycle-button.html"
>

<ui-cluster
  gap="s"
>
  <ui-text>Appearance</ui-text>
  <ui-cycle-button
    id="appearance-cycle"
    label="Appearance"
    items="[{&quot;value&quot;:&quot;automatic&quot;,&quot;label&quot;:&quot;Automatic&quot;,&quot;icon&quot;:&quot;monitor&quot;},{&quot;value&quot;:&quot;light&quot;,&quot;label&quot;:&quot;Light&quot;,&quot;icon&quot;:&quot;sun&quot;},{&quot;value&quot;:&quot;dark&quot;,&quot;label&quot;:&quot;Dark&quot;,&quot;icon&quot;:&quot;moon&quot;}]"
  ></ui-cycle-button>
</ui-cluster>
<script setup>
  import { UiCluster, UiCycleButton, UiText } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="s"
  >
    <UiText>Appearance</UiText>
    <UiCycleButton
      id="appearance-cycle"
      label="Appearance"
      :items="[{ value: 'automatic', label: 'Automatic', icon: 'monitor' }, { value: 'light', label: 'Light', icon: 'sun' }, { value: 'dark', label: 'Dark', icon: 'moon' }]"
    />
  </UiCluster>
</template>
import { UiCluster, UiCycleButton, UiText } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiText>Appearance</UiText>
    <UiCycleButton
      id="appearance-cycle"
      label="Appearance"
      items={[{"value":"automatic","label":"Automatic","icon":"monitor"},{"value":"light","label":"Light","icon":"sun"},{"value":"dark","label":"Dark","icon":"moon"}]}
    />
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiCluster, UiCycleButton, UiText } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiText>Appearance</UiText>
    <UiCycleButton
      id="appearance-cycle"
      label="Appearance"
      items={[{"value":"automatic","label":"Automatic","icon":"monitor"},{"value":"light","label":"Light","icon":"sun"},{"value":"dark","label":"Dark","icon":"moon"}]}
    />
  </UiCluster>;
}
<script>
  import { UiCluster, UiCycleButton, UiText } from "@threadlabs/looma";
</script>

<UiCluster
  gap="s"
>
  <UiText>Appearance</UiText>
  <UiCycleButton
    id="appearance-cycle"
    label="Appearance"
    items={[{"value":"automatic","label":"Automatic","icon":"monitor"},{"value":"light","label":"Light","icon":"sun"},{"value":"dark","label":"Dark","icon":"moon"}]}
  />
</UiCluster>
import { Component } from "@angular/core";
import { UiCluster, UiCycleButton, UiText } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiText, UiCycleButton],
  template: `
    <div
      ui-cluster
      [gap]="'s'"
    >
      <ng-template
        ui-text
      >Appearance</ng-template>
      <span
        ui-cycle-button
        id="appearance-cycle"
        [label]="'Appearance'"
        [items]="[{ value: 'automatic', label: 'Automatic', icon: 'monitor' }, { value: 'light', label: 'Light', icon: 'sun' }, { value: 'dark', label: 'Dark', icon: 'moon' }]"
      ></span>
    </div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: span

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
descriptionAccessible instruction for cycling; accepts localized reader text.descriptionstringActivate to choose the next state.—
disabledPrevents cycling while keeping the selected state visible.disabledbooleanfalse—
empty-labelSelected-state label while no choices are available.emptyLabelstringNo choices—
indexInitial or externally selected zero-based state. The first state is the default.indexnumber0—
itemsOrdered states with a value, readable label and Looma icon name. Activation advances to the next state and wraps.itemslist(object)
  • [].value: string (required)
  • [].label: string (required)
  • [].icon: string (required)
——
labelWhat the button changes, such as Appearance. The selected state is included in its accessible name.labelstringState—
sizeUses IconButton's compact visible sizes and adjustable invisible touch area.sizekeywordmdsm, md, lg
variantUses IconButton's standard emphasis.variantkeywordoutlineghost, outline, solid

Framework props

NameTypeDefaultAllowed values
descriptionstringActivate to choose the next state.—
disabledbooleanfalse—
emptyLabelstringNo choices—
indexnumber0—
itemsreadonly ({ readonly value: string; readonly label: string; readonly icon: string })[]
  • [].value: string (required)
  • [].label: string (required)
  • [].icon: string (required)
——
labelstringState—
size"sm" | "md" | "lg"mdsm, md, lg
variant"ghost" | "outline" | "solid"outlineghost, outline, solid

Events

NameDetailDescription
changeobject
  • value: string (required)
  • index: number (required)
Emitted when a toggleable control changes checked state.

Slots

No slots.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

No component tokens.

Shared tokens

No shared tokens.