Icon Button

Icon-only button primitive with stable square sizing and variant tokens for shell controls, compact actions, and editor chrome.

Default

Label provides the accessible name while the default appearance is a medium ghost button.

Code

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

<ui-icon-button
  label="Search"
  variant="ghost"
  size="md"
>
  <svg
    aria-hidden="true"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    stroke-width="2"
  >
    <circle
      cx="11"
      cy="11"
      r="7"
    ></circle>
    <path
      d="m20 20-3.5-3.5"
    ></path>
  </svg>
</ui-icon-button>
<script setup>
  import { UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiIconButton
    label="Search"
    variant="ghost"
    size="md"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </UiIconButton>
</template>
import { UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiIconButton
    label="Search"
    variant="ghost"
    size="md"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      />
      <path
        d="m20 20-3.5-3.5"
      />
    </svg>
  </UiIconButton>;
}
/** @jsxImportSource preact */
import { UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiIconButton
    label="Search"
    variant="ghost"
    size="md"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      />
      <path
        d="m20 20-3.5-3.5"
      />
    </svg>
  </UiIconButton>;
}
<script>
  import { UiIconButton } from "@threadlabs/looma";
</script>

<UiIconButton
  label="Search"
  variant="ghost"
  size="md"
>
  <svg
    aria-hidden="true"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    stroke-width="2"
  >
    <circle
      cx="11"
      cy="11"
      r="7"
    ></circle>
    <path
      d="m20 20-3.5-3.5"
    ></path>
  </svg>
</UiIconButton>
import { Component } from "@angular/core";
import { UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiIconButton],
  template: `
    <button
      ui-icon-button
      [label]="'Search'"
      [variant]="'ghost'"
      [size]="'md'"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        ></circle>
        <path
          d="m20 20-3.5-3.5"
        ></path>
      </svg>
    </button>
  `,
})
export default class Example {}

Size and variant

Size controls density while variant controls visual emphasis.

Code

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

<ui-cluster
  gap="s"
  align="center"
>
  <ui-icon-button
    label="Compact inline action"
    size="xs"
    variant="ghost"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Small ghost"
    size="sm"
    variant="ghost"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Medium outline"
    size="md"
    variant="outline"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Large solid"
    size="lg"
    variant="solid"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Toggle panel"
    size="sm"
    variant="ghost"
    tone="neutral"
    anticipatory
    guide="bar"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <rect
        x="3"
        y="3"
        width="18"
        height="18"
        rx="2"
      ></rect>
      <path
        d="M9 3v18m7-9-3-3m0 6 3-3"
      ></path>
    </svg>
  </ui-icon-button>
</ui-cluster>
<script setup>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="s"
    align="center"
  >
    <UiIconButton
      label="Compact inline action"
      size="xs"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Small ghost"
      size="sm"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        ></circle>
        <path
          d="m20 20-3.5-3.5"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Medium outline"
      size="md"
      variant="outline"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Large solid"
      size="lg"
      variant="solid"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Toggle panel"
      size="sm"
      variant="ghost"
      tone="neutral"
      :anticipatory="true"
      guide="bar"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <rect
          x="3"
          y="3"
          width="18"
          height="18"
          rx="2"
        ></rect>
        <path
          d="M9 3v18m7-9-3-3m0 6 3-3"
        ></path>
      </svg>
    </UiIconButton>
  </UiCluster>
</template>
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
    align="center"
  >
    <UiIconButton
      label="Compact inline action"
      size="xs"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Small ghost"
      size="sm"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Medium outline"
      size="md"
      variant="outline"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Large solid"
      size="lg"
      variant="solid"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Toggle panel"
      size="sm"
      variant="ghost"
      tone="neutral"
      anticipatory
      guide="bar"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <rect
          x="3"
          y="3"
          width="18"
          height="18"
          rx="2"
        />
        <path
          d="M9 3v18m7-9-3-3m0 6 3-3"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
    align="center"
  >
    <UiIconButton
      label="Compact inline action"
      size="xs"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Small ghost"
      size="sm"
      variant="ghost"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Medium outline"
      size="md"
      variant="outline"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Large solid"
      size="lg"
      variant="solid"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Toggle panel"
      size="sm"
      variant="ghost"
      tone="neutral"
      anticipatory
      guide="bar"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <rect
          x="3"
          y="3"
          width="18"
          height="18"
          rx="2"
        />
        <path
          d="M9 3v18m7-9-3-3m0 6 3-3"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
<script>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<UiCluster
  gap="s"
  align="center"
>
  <UiIconButton
    label="Compact inline action"
    size="xs"
    variant="ghost"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Small ghost"
    size="sm"
    variant="ghost"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Medium outline"
    size="md"
    variant="outline"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Large solid"
    size="lg"
    variant="solid"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Toggle panel"
    size="sm"
    variant="ghost"
    tone="neutral"
    anticipatory
    guide="bar"
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <rect
        x="3"
        y="3"
        width="18"
        height="18"
        rx="2"
      ></rect>
      <path
        d="M9 3v18m7-9-3-3m0 6 3-3"
      ></path>
    </svg>
  </UiIconButton>
</UiCluster>
import { Component } from "@angular/core";
import { UiCluster, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiIconButton],
  template: `
    <div
      ui-cluster
      [gap]="'s'"
      [align]="'center'"
    >
      <button
        ui-icon-button
        [label]="'Compact inline action'"
        [size]="'xs'"
        [variant]="'ghost'"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Small ghost'"
        [size]="'sm'"
        [variant]="'ghost'"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <circle
            cx="11"
            cy="11"
            r="7"
          ></circle>
          <path
            d="m20 20-3.5-3.5"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Medium outline'"
        [size]="'md'"
        [variant]="'outline'"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Large solid'"
        [size]="'lg'"
        [variant]="'solid'"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Toggle panel'"
        [size]="'sm'"
        [variant]="'ghost'"
        [tone]="'neutral'"
        [anticipatory]="true"
        [guide]="'bar'"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <rect
            x="3"
            y="3"
            width="18"
            height="18"
            rx="2"
          ></rect>
          <path
            d="M9 3v18m7-9-3-3m0 6 3-3"
          ></path>
        </svg>
      </button>
    </div>
  `,
})
export default class Example {}

round

Round gives a fully circular shape, as used by compact close and dismiss controls.

Code

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

<ui-cluster
  gap="s"
>
  <ui-icon-button
    label="Add"
    variant="outline"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Add"
    variant="solid"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Search"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </ui-icon-button>
</ui-cluster>
<script setup>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      :round="true"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Add"
      variant="solid"
      :round="true"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      :round="true"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        ></circle>
        <path
          d="m20 20-3.5-3.5"
        ></path>
      </svg>
    </UiIconButton>
  </UiCluster>
</template>
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Add"
      variant="solid"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Add"
      variant="solid"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      round
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
<script>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<UiCluster
  gap="s"
>
  <UiIconButton
    label="Add"
    variant="outline"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Add"
    variant="solid"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Search"
    round
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </UiIconButton>
</UiCluster>
import { Component } from "@angular/core";
import { UiCluster, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiIconButton],
  template: `
    <div
      ui-cluster
      [gap]="'s'"
    >
      <button
        ui-icon-button
        [label]="'Add'"
        [variant]="'outline'"
        [round]="true"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Add'"
        [variant]="'solid'"
        [round]="true"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Search'"
        [round]="true"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <circle
            cx="11"
            cy="11"
            r="7"
          ></circle>
          <path
            d="m20 20-3.5-3.5"
          ></path>
        </svg>
      </button>
    </div>
  `,
})
export default class Example {}

disabled

Disabled icon buttons dim and ignore activation.

Code

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

<ui-cluster
  gap="s"
>
  <ui-icon-button
    label="Add"
    variant="outline"
    disabled
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </ui-icon-button>
  <ui-icon-button
    label="Search"
    disabled
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </ui-icon-button>
</ui-cluster>
<script setup>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      :disabled="true"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        ></path>
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      :disabled="true"
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        ></circle>
        <path
          d="m20 20-3.5-3.5"
        ></path>
      </svg>
    </UiIconButton>
  </UiCluster>
</template>
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      disabled
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      disabled
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiCluster, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="s"
  >
    <UiIconButton
      label="Add"
      variant="outline"
      disabled
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path
          d="M12 5v14M5 12h14"
        />
      </svg>
    </UiIconButton>
    <UiIconButton
      label="Search"
      disabled
    >
      <svg
        aria-hidden="true"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <circle
          cx="11"
          cy="11"
          r="7"
        />
        <path
          d="m20 20-3.5-3.5"
        />
      </svg>
    </UiIconButton>
  </UiCluster>;
}
<script>
  import { UiCluster, UiIconButton } from "@threadlabs/looma";
</script>

<UiCluster
  gap="s"
>
  <UiIconButton
    label="Add"
    variant="outline"
    disabled
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <path
        d="M12 5v14M5 12h14"
      ></path>
    </svg>
  </UiIconButton>
  <UiIconButton
    label="Search"
    disabled
  >
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
    >
      <circle
        cx="11"
        cy="11"
        r="7"
      ></circle>
      <path
        d="m20 20-3.5-3.5"
      ></path>
    </svg>
  </UiIconButton>
</UiCluster>
import { Component } from "@angular/core";
import { UiCluster, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiIconButton],
  template: `
    <div
      ui-cluster
      [gap]="'s'"
    >
      <button
        ui-icon-button
        [label]="'Add'"
        [variant]="'outline'"
        [disabled]="true"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <path
            d="M12 5v14M5 12h14"
          ></path>
        </svg>
      </button>
      <button
        ui-icon-button
        [label]="'Search'"
        [disabled]="true"
      >
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
        >
          <circle
            cx="11"
            cy="11"
            r="7"
          ></circle>
          <path
            d="m20 20-3.5-3.5"
          ></path>
        </svg>
      </button>
    </div>
  `,
})
export default class Example {}

Help toggletip

A round ghost button holding the help icon, named for what it explains, opens a click-triggered tooltip. It opens on click, Enter, or Space, and closes the same way or with Escape.

Email

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-icon-button/ui-icon-button.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-icon/ui-icon.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-tooltip/ui-tooltip.html"
>

<ui-cluster
  gap="xs"
>
  <ui-text
    weight="medium"
  >Email</ui-text>
  <ui-icon-button
    id="email-help"
    label="Help for Email"
    variant="ghost"
    size="sm"
    round
  >
    <ui-icon
      name="help"
    ></ui-icon>
  </ui-icon-button>
</ui-cluster>
<ui-tooltip
  for="email-help"
  trigger="click"
>Receipts and sign-in links go to this address.</ui-tooltip>
<script setup>
  import { UiCluster, UiIcon, UiIconButton, UiText, UiTooltip } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="xs"
  >
    <UiText
      weight="medium"
    >Email</UiText>
    <UiIconButton
      id="email-help"
      label="Help for Email"
      variant="ghost"
      size="sm"
      :round="true"
    >
      <UiIcon
        name="help"
      />
    </UiIconButton>
  </UiCluster>
  <UiTooltip
    for="email-help"
    trigger="click"
  >Receipts and sign-in links go to this address.</UiTooltip>
</template>
import { UiCluster, UiIcon, UiIconButton, UiText, UiTooltip } from "@threadlabs/looma";

export default function Example() {
  return <>
    <UiCluster
      gap="xs"
    >
      <UiText
        weight="medium"
      >Email</UiText>
      <UiIconButton
        id="email-help"
        label="Help for Email"
        variant="ghost"
        size="sm"
        round
      >
        <UiIcon
          name="help"
        />
      </UiIconButton>
    </UiCluster>
    <UiTooltip
      htmlFor="email-help"
      trigger="click"
    >Receipts and sign-in links go to this address.</UiTooltip>
  </>;
}
/** @jsxImportSource preact */
import { UiCluster, UiIcon, UiIconButton, UiText, UiTooltip } from "@threadlabs/looma";

export default function Example() {
  return <>
    <UiCluster
      gap="xs"
    >
      <UiText
        weight="medium"
      >Email</UiText>
      <UiIconButton
        id="email-help"
        label="Help for Email"
        variant="ghost"
        size="sm"
        round
      >
        <UiIcon
          name="help"
        />
      </UiIconButton>
    </UiCluster>
    <UiTooltip
      htmlFor="email-help"
      trigger="click"
    >Receipts and sign-in links go to this address.</UiTooltip>
  </>;
}
<script>
  import { UiCluster, UiIcon, UiIconButton, UiText, UiTooltip } from "@threadlabs/looma";
</script>

<UiCluster
  gap="xs"
>
  <UiText
    weight="medium"
  >Email</UiText>
  <UiIconButton
    id="email-help"
    label="Help for Email"
    variant="ghost"
    size="sm"
    round
  >
    <UiIcon
      name="help"
    />
  </UiIconButton>
</UiCluster>
<UiTooltip
  for="email-help"
  trigger="click"
>Receipts and sign-in links go to this address.</UiTooltip>
import { Component } from "@angular/core";
import { UiCluster, UiIcon, UiIconButton, UiText, UiTooltip } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiText, UiIconButton, UiIcon, UiTooltip],
  template: `
    <div
      ui-cluster
      [gap]="'xs'"
    >
      <ng-template
        ui-text
        [weight]="'medium'"
      >Email</ng-template>
      <button
        ui-icon-button
        id="email-help"
        [label]="'Help for Email'"
        [variant]="'ghost'"
        [size]="'sm'"
        [round]="true"
      >
        <span
          ui-icon
          name="help"
        ></span>
      </button>
    </div>
    <span
      ui-tooltip
      [for]="'email-help'"
      [trigger]="'click'"
    >Receipts and sign-in links go to this address.</span>
  `,
})
export default class Example {}

Loading icon action

Loading keeps the button's accessible label and focus while a spinner replaces its icon.

Code

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

<ui-icon-button
  label="More options"
  loading
>
  <ui-icon
    name="ellipsis"
  ></ui-icon>
</ui-icon-button>
<script setup>
  import { UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiIconButton
    label="More options"
    :loading="true"
  >
    <UiIcon
      name="ellipsis"
    />
  </UiIconButton>
</template>
import { UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiIconButton
    label="More options"
    loading
  >
    <UiIcon
      name="ellipsis"
    />
  </UiIconButton>;
}
/** @jsxImportSource preact */
import { UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiIconButton
    label="More options"
    loading
  >
    <UiIcon
      name="ellipsis"
    />
  </UiIconButton>;
}
<script>
  import { UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<UiIconButton
  label="More options"
  loading
>
  <UiIcon
    name="ellipsis"
  />
</UiIconButton>
import { Component } from "@angular/core";
import { UiIcon, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiIconButton, UiIcon],
  template: `
    <button
      ui-icon-button
      [label]="'More options'"
      [loading]="true"
    >
      <span
        ui-icon
        name="ellipsis"
      ></span>
    </button>
  `,
})
export default class Example {}

Match a text button

A companion icon button follows the text button's control height, including theme and touch sizes.

Code

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

<ui-cluster
  gap="xs"
  align="stretch"
  wrap="nowrap"
>
  <ui-button
    size="sm"
  >Save changes</ui-button>
  <ui-icon-button
    size="sm"
    variant="outline"
    match-button
    label="More save options"
  >
    <ui-icon
      name="chevron-down"
    ></ui-icon>
  </ui-icon-button>
</ui-cluster>
<script setup>
  import { UiButton, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="xs"
    align="stretch"
    wrap="nowrap"
  >
    <UiButton
      size="sm"
    >Save changes</UiButton>
    <UiIconButton
      size="sm"
      variant="outline"
      :match-button="true"
      label="More save options"
    >
      <UiIcon
        name="chevron-down"
      />
    </UiIconButton>
  </UiCluster>
</template>
import { UiButton, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="xs"
    align="stretch"
    wrap="nowrap"
  >
    <UiButton
      size="sm"
    >Save changes</UiButton>
    <UiIconButton
      size="sm"
      variant="outline"
      matchButton
      label="More save options"
    >
      <UiIcon
        name="chevron-down"
      />
    </UiIconButton>
  </UiCluster>;
}
/** @jsxImportSource preact */
import { UiButton, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiCluster
    gap="xs"
    align="stretch"
    wrap="nowrap"
  >
    <UiButton
      size="sm"
    >Save changes</UiButton>
    <UiIconButton
      size="sm"
      variant="outline"
      matchButton
      label="More save options"
    >
      <UiIcon
        name="chevron-down"
      />
    </UiIconButton>
  </UiCluster>;
}
<script>
  import { UiButton, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<UiCluster
  gap="xs"
  align="stretch"
  wrap="nowrap"
>
  <UiButton
    size="sm"
  >Save changes</UiButton>
  <UiIconButton
    size="sm"
    variant="outline"
    matchButton
    label="More save options"
  >
    <UiIcon
      name="chevron-down"
    />
  </UiIconButton>
</UiCluster>
import { Component } from "@angular/core";
import { UiButton, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiButton, UiIconButton, UiIcon],
  template: `
    <div
      ui-cluster
      [gap]="'xs'"
      [align]="'stretch'"
      [wrap]="'nowrap'"
    >
      <ng-template
        ui-button
        [size]="'sm'"
      >Save changes</ng-template>
      <button
        ui-icon-button
        [size]="'sm'"
        [variant]="'outline'"
        [matchButton]="true"
        [label]="'More save options'"
      >
        <span
          ui-icon
          name="chevron-down"
        ></span>
      </button>
    </div>
  `,
})
export default class Example {}

Outline toggles

Native aria-pressed keeps an outline action visibly pressed after release. The app owns the toggle state; an accent tone adds colour without a solid fill. A tooltip supplies the same label on hover and keyboard focus.

Code

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

<ui-cluster
  gap="m"
>
  <ui-icon-button
    label="Notifications"
    variant="outline"
    tone="neutral"
    aria-pressed="false"
  >
    <ui-icon
      name="bell"
    ></ui-icon>
  </ui-icon-button>
  <ui-icon-button
    id="notifications-toggle-example"
    label="Notifications"
    variant="outline"
    tone="accent"
    aria-pressed="true"
  >
    <ui-icon
      name="bell"
    ></ui-icon>
  </ui-icon-button>
</ui-cluster>
<ui-tooltip
  for="notifications-toggle-example"
>Notifications</ui-tooltip>
<script setup>
  import { UiCluster, UiIcon, UiIconButton, UiTooltip } from "@threadlabs/looma";
</script>

<template>
  <UiCluster
    gap="m"
  >
    <UiIconButton
      label="Notifications"
      variant="outline"
      tone="neutral"
      aria-pressed="false"
    >
      <UiIcon
        name="bell"
      />
    </UiIconButton>
    <UiIconButton
      id="notifications-toggle-example"
      label="Notifications"
      variant="outline"
      tone="accent"
      aria-pressed="true"
    >
      <UiIcon
        name="bell"
      />
    </UiIconButton>
  </UiCluster>
  <UiTooltip
    for="notifications-toggle-example"
  >Notifications</UiTooltip>
</template>
import { UiCluster, UiIcon, UiIconButton, UiTooltip } from "@threadlabs/looma";

export default function Example() {
  return <>
    <UiCluster
      gap="m"
    >
      <UiIconButton
        label="Notifications"
        variant="outline"
        tone="neutral"
        aria-pressed="false"
      >
        <UiIcon
          name="bell"
        />
      </UiIconButton>
      <UiIconButton
        id="notifications-toggle-example"
        label="Notifications"
        variant="outline"
        tone="accent"
        aria-pressed="true"
      >
        <UiIcon
          name="bell"
        />
      </UiIconButton>
    </UiCluster>
    <UiTooltip
      htmlFor="notifications-toggle-example"
    >Notifications</UiTooltip>
  </>;
}
/** @jsxImportSource preact */
import { UiCluster, UiIcon, UiIconButton, UiTooltip } from "@threadlabs/looma";

export default function Example() {
  return <>
    <UiCluster
      gap="m"
    >
      <UiIconButton
        label="Notifications"
        variant="outline"
        tone="neutral"
        aria-pressed="false"
      >
        <UiIcon
          name="bell"
        />
      </UiIconButton>
      <UiIconButton
        id="notifications-toggle-example"
        label="Notifications"
        variant="outline"
        tone="accent"
        aria-pressed="true"
      >
        <UiIcon
          name="bell"
        />
      </UiIconButton>
    </UiCluster>
    <UiTooltip
      htmlFor="notifications-toggle-example"
    >Notifications</UiTooltip>
  </>;
}
<script>
  import { UiCluster, UiIcon, UiIconButton, UiTooltip } from "@threadlabs/looma";
</script>

<UiCluster
  gap="m"
>
  <UiIconButton
    label="Notifications"
    variant="outline"
    tone="neutral"
    aria-pressed="false"
  >
    <UiIcon
      name="bell"
    />
  </UiIconButton>
  <UiIconButton
    id="notifications-toggle-example"
    label="Notifications"
    variant="outline"
    tone="accent"
    aria-pressed="true"
  >
    <UiIcon
      name="bell"
    />
  </UiIconButton>
</UiCluster>
<UiTooltip
  for="notifications-toggle-example"
>Notifications</UiTooltip>
import { Component } from "@angular/core";
import { UiCluster, UiIcon, UiIconButton, UiTooltip } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiCluster, UiIconButton, UiIcon, UiTooltip],
  template: `
    <div
      ui-cluster
      [gap]="'m'"
    >
      <button
        ui-icon-button
        [label]="'Notifications'"
        [variant]="'outline'"
        [tone]="'neutral'"
        aria-pressed="false"
      >
        <span
          ui-icon
          name="bell"
        ></span>
      </button>
      <button
        ui-icon-button
        id="notifications-toggle-example"
        [label]="'Notifications'"
        [variant]="'outline'"
        [tone]="'accent'"
        aria-pressed="true"
      >
        <span
          ui-icon
          name="bell"
        ></span>
      </button>
    </div>
    <span
      ui-tooltip
      [for]="'notifications-toggle-example'"
    >Notifications</span>
  `,
})
export default class Example {}

Anticipatory context actions

A resting dot reveals the action on proximity, hover or keyboard focus. revealed keeps the action visible while its context is selected, without implying a pressed state. Touch always shows the icon.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-affordance-scope/ui-affordance-scope.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-cluster/ui-cluster.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-icon-button/ui-icon-button.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-icon/ui-icon.html"
>

<ui-affordance-scope>
  <ui-cluster
    gap="m"
  >
    <ui-icon-button
      label="Settings"
      anticipatory
    >
      <ui-icon
        name="settings"
      ></ui-icon>
    </ui-icon-button>
    <ui-icon-button
      label="Selected block settings"
      anticipatory
      revealed
    >
      <ui-icon
        name="settings"
      ></ui-icon>
    </ui-icon-button>
  </ui-cluster>
</ui-affordance-scope>
<script setup>
  import { UiAffordanceScope, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<template>
  <UiAffordanceScope>
    <UiCluster
      gap="m"
    >
      <UiIconButton
        label="Settings"
        :anticipatory="true"
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
      <UiIconButton
        label="Selected block settings"
        :anticipatory="true"
        :revealed="true"
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
    </UiCluster>
  </UiAffordanceScope>
</template>
import { UiAffordanceScope, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiAffordanceScope>
    <UiCluster
      gap="m"
    >
      <UiIconButton
        label="Settings"
        anticipatory
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
      <UiIconButton
        label="Selected block settings"
        anticipatory
        revealed
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
    </UiCluster>
  </UiAffordanceScope>;
}
/** @jsxImportSource preact */
import { UiAffordanceScope, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

export default function Example() {
  return <UiAffordanceScope>
    <UiCluster
      gap="m"
    >
      <UiIconButton
        label="Settings"
        anticipatory
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
      <UiIconButton
        label="Selected block settings"
        anticipatory
        revealed
      >
        <UiIcon
          name="settings"
        />
      </UiIconButton>
    </UiCluster>
  </UiAffordanceScope>;
}
<script>
  import { UiAffordanceScope, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";
</script>

<UiAffordanceScope>
  <UiCluster
    gap="m"
  >
    <UiIconButton
      label="Settings"
      anticipatory
    >
      <UiIcon
        name="settings"
      />
    </UiIconButton>
    <UiIconButton
      label="Selected block settings"
      anticipatory
      revealed
    >
      <UiIcon
        name="settings"
      />
    </UiIconButton>
  </UiCluster>
</UiAffordanceScope>
import { Component } from "@angular/core";
import { UiAffordanceScope, UiCluster, UiIcon, UiIconButton } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiAffordanceScope, UiCluster, UiIconButton, UiIcon],
  template: `
    <span
      ui-affordance-scope
    >
      <div
        ui-cluster
        [gap]="'m'"
      >
        <button
          ui-icon-button
          [label]="'Settings'"
          [anticipatory]="true"
        >
          <span
            ui-icon
            name="settings"
          ></span>
        </button>
        <button
          ui-icon-button
          [label]="'Selected block settings'"
          [anticipatory]="true"
          [revealed]="true"
        >
          <span
            ui-icon
            name="settings"
          ></span>
        </button>
      </div>
    </span>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: button

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
anticipatoryKeeps the button out of sight until it is wanted: at rest a fine pointer sees only a small guide dot, and the button appears on hover, on focus, or when the pointer comes near inside a ui-affordance-scope. Touch devices and the solid variant always show it.anticipatorybooleanfalse—
disabledDisables the button, so it cannot be pressed or focused, and gives it a flat neutral surface and muted icon.disabledbooleanfalse—
guideThe idle marker of an anticipatory button: dot for contextual actions, or a slim neutral rounded bar for a panel-edge control. The icon appears on hover or keyboard focus; touch always shows the icon.guidekeyworddotdot, bar
labelAccessible name for the icon.labelstring——
loadingKeeps the button focusable and named while work is in progress. It shows a spinner, states aria-disabled and aria-busy, and prevents activation until cleared.loadingbooleanfalse—
match-buttonMatches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row's height, on mouse and touch alike. Touch expansion stays vertical so an adjacent action keeps its own horizontal boundary. Leave it off for compact toolbar and inline icon buttons.matchButtonbooleanfalse—
pendingDeprecated alias for loading.pendingbooleanfalse—
presetThe same shortcuts as Button: primary is solid accent, standard is solid neutral, quiet is ghost neutral, and destructive is solid danger. A named preset wins over variant and tone; none preserves independent choices.presetkeywordnonenone, primary, standard, quiet, destructive
revealedKeeps an anticipatory button visible while its context is active, such as a selected block or an open popup. It does not imply a pressed or expanded state.revealedbooleanfalse—
roundUse a fully circular shape.roundbooleanfalse—
sizeButton and icon size together: xs is the compact control height (1.5rem), matching Button xs for inline actions; sm is 1.75rem with a small icon, md is 2rem, and lg is 2.5rem with a large icon. Touch uses the adjustable control target preference; xs uses --ui-inline-control-min-block-size so dense inline actions keep independent targets.sizekeywordmdxs, sm, md, lg
toneColour for every variant. The default neutral shares the quiet control family with fields and text buttons. Choose accent explicitly for a coloured action, or primary for solid accent. danger, success, warning and info share Button's intent colors. Native aria-pressed="true" keeps an outline toggle visibly pressed; the consumer owns that state. Supporting brand families use accent-secondary and accent-tertiary; their usable colors derive from the theme, and unset families follow the primary accent.tonekeywordneutralaccent, accent-secondary, accent-tertiary, neutral, danger, success, warning, info
variantEmphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with its chosen tone.variantkeywordghostghost, outline, solid

Framework props

NameTypeDefaultAllowed values
anticipatorybooleanfalse—
disabledbooleanfalse—
guide"dot" | "bar"dotdot, bar
labelstring——
loadingbooleanfalse—
matchButtonbooleanfalse—
pendingbooleanfalse—
preset"none" | "primary" | "standard" | "quiet" | "destructive"nonenone, primary, standard, quiet, destructive
revealedbooleanfalse—
roundbooleanfalse—
size"xs" | "sm" | "md" | "lg"mdxs, sm, md, lg
tone"accent" | "accent-secondary" | "accent-tertiary" | "neutral" | "danger" | "success" | "warning" | "info"neutralaccent, accent-secondary, accent-tertiary, neutral, danger, success, warning, info
variant"ghost" | "outline" | "solid"ghostghost, outline, solid

Events

No events.

Slots

NamePurpose
defaultDefault child content.

Design tokens

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

Component tokens

TokenDeclared valuesFallback
--ui-action-shadowvar(--_ui-action-edge), 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20))—
--ui-icon-button-active-scale—var(--ui-press-scale, 0.96)
--ui-icon-button-active-surfacevar(--ui-accent-active, var(--ui-accent-hover)) | var(--ui-accent-secondary-active, var(--ui-accent-secondary-hover)) | var(--ui-accent-tertiary-active, var(--ui-accent-tertiary-hover)) | var(--ui-danger-active, var(--ui-danger-hover)) | var(--ui-success-active, var(--ui-success-hover)) | var(--ui-warning-active, var(--ui-warning-hover)) | var(--ui-info-active, var(--ui-info-hover)) | var(--ui-neutral-active, var(--ui-neutral-hover))var(--ui-neutral-active) | color-mix(in srgb, currentColor 16%, transparent) | color-mix(in srgb, currentColor 12%, var(--ui-surface-default))
--ui-icon-button-bordervar(--ui-accent-border, var(--ui-accent-solid)) | var(--ui-accent-secondary-border, var(--ui-accent-secondary)) | var(--ui-accent-tertiary-border, var(--ui-accent-tertiary)) | var(--ui-accent-border, var(--ui-accent)) | var(--ui-danger-border, var(--ui-danger)) | var(--ui-success-border, var(--ui-success)) | var(--ui-warning-border, var(--ui-warning)) | var(--ui-info-border, var(--ui-info)) | var(--ui-control-border, var(--ui-neutral-surface)) | var(--ui-accent-outline-border, var(--ui-accent-subtle-text)) | var(--ui-accent-secondary-outline-border, var(--ui-accent-secondary-subtle-text)) | var(--ui-accent-tertiary-outline-border, var(--ui-accent-tertiary-subtle-text)) | var(--ui-danger-outline-border, var(--ui-danger-subtle-text)) | var(--ui-success-outline-border, var(--ui-success-subtle-text)) | var(--ui-warning-outline-border, var(--ui-warning-subtle-text)) | var(--ui-info-outline-border, var(--ui-info-subtle-text)) | var(--ui-control-border)var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong))) | var(--ui-control-border)
--ui-icon-button-disabled-filter—var(--ui-disabled-filter)
--ui-icon-button-disabled-opacity—1
--ui-icon-button-hover-bordervar(--ui-accent-outline-border, var(--ui-accent-subtle-text)) | var(--ui-accent-secondary-outline-border, var(--ui-accent-secondary-subtle-text)) | var(--ui-accent-tertiary-outline-border, var(--ui-accent-tertiary-subtle-text)) | var(--ui-danger-outline-border, var(--ui-danger-subtle-text)) | var(--ui-success-outline-border, var(--ui-success-subtle-text)) | var(--ui-warning-outline-border, var(--ui-warning-subtle-text)) | var(--ui-info-outline-border, var(--ui-info-subtle-text)) | var(--ui-control-border) | var(--ui-accent-hover-border, var(--ui-accent-hover)) | var(--ui-accent-secondary-hover-border, var(--ui-accent-secondary-hover)) | var(--ui-accent-tertiary-hover-border, var(--ui-accent-tertiary-hover)) | var(--ui-danger-hover-border, var(--ui-danger-hover)) | var(--ui-success-hover-border, var(--ui-success-hover)) | var(--ui-warning-hover-border, var(--ui-warning-hover)) | var(--ui-info-hover-border, var(--ui-info-hover)) | var(--ui-control-border-hover, var(--ui-neutral-hover))var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)))
--ui-icon-button-hover-surfacevar(--ui-accent-ghost-hover) | var(--ui-accent-secondary-ghost-hover) | var(--ui-accent-tertiary-ghost-hover) | var(--ui-danger-ghost-hover) | var(--ui-success-ghost-hover) | var(--ui-warning-ghost-hover) | var(--ui-info-ghost-hover) | var(--ui-neutral-ghost-hover)transparent
--ui-icon-button-hover-text—var(--_icon-button-text, var(--ui-text-primary))
--ui-icon-button-icon-sizevar(--ui-icon-size-md) | var(--ui-icon-size-xs) | var(--ui-icon-size-sm) | var(--ui-icon-size-lg)—
--ui-icon-button-icon-stroke-width—1.75
--ui-icon-button-outline-surface—var(--_icon-button-outline-surface, var(--ui-surface-default)) | transparent
--ui-icon-button-outline-text—var(--_icon-button-text, var(--ui-text-primary))
--ui-icon-button-radius—var(--ui-action-radius, var(--ui-radius-md))
--ui-icon-button-size2rem | var(--ui-control-size-xs) | 1.75rem | 2.5rem | var(--ui-control-size-md) | var(--ui-control-size-sm) | var(--ui-control-size-lg)—
--ui-icon-button-solid-hover-surface—var(--_icon-button-solid-hover-surface, var(--ui-accent-hover))
--ui-icon-button-solid-shadow—var(--ui-action-shadow, var(--_ui-action-shadow)) | var(--ui-neutral-shadow)
--ui-icon-button-solid-surface—var(--_icon-button-solid-surface, var(--ui-accent-solid))
--ui-icon-button-solid-text—var(--_icon-button-solid-text, var(--ui-non-text-on-accent, var(--ui-text-on-accent)))
--ui-icon-button-surface—transparent
--ui-neutral-hover-highlightvar(--ui-accent-highlight, none) | var(--ui-accent-secondary-highlight, none) | var(--ui-accent-tertiary-highlight, none) | var(--ui-danger-highlight, none) | var(--ui-success-highlight, none) | var(--ui-warning-highlight, none) | var(--ui-info-highlight, none) | var(--ui-neutral-highlight, none)—

Shared tokens

TokenFallback
--ui-accent—
--ui-accent-activevar(--ui-accent-hover)
--ui-accent-active-bordervar(--ui-accent-active)
--ui-accent-bordervar(--ui-accent-solid) | var(--ui-accent)
--ui-accent-ghost-hover—
--ui-accent-glow0 0 transparent
--ui-accent-highlightnone
--ui-accent-hover—
--ui-accent-hover-bordervar(--ui-accent-hover)
--ui-accent-hover-highlightnone
--ui-accent-outline-bordervar(--ui-accent-subtle-text)
--ui-accent-secondary—
--ui-accent-secondary-activevar(--ui-accent-secondary-hover)
--ui-accent-secondary-active-bordervar(--ui-accent-secondary-active)
--ui-accent-secondary-bordervar(--ui-accent-secondary)
--ui-accent-secondary-ghost-hover—
--ui-accent-secondary-glow0 0 transparent
--ui-accent-secondary-highlightnone
--ui-accent-secondary-hover—
--ui-accent-secondary-hover-bordervar(--ui-accent-secondary-hover)
--ui-accent-secondary-hover-highlightnone
--ui-accent-secondary-outline-bordervar(--ui-accent-secondary-subtle-text)
--ui-accent-secondary-solid—
--ui-accent-secondary-subtle-textvar(--ui-accent-secondary-solid)
--ui-accent-secondary-wash—
--ui-accent-secondary-wash-hover—
--ui-accent-solid—
--ui-accent-subtle-textvar(--ui-accent-solid)
--ui-accent-tertiary—
--ui-accent-tertiary-activevar(--ui-accent-tertiary-hover)
--ui-accent-tertiary-active-bordervar(--ui-accent-tertiary-active)
--ui-accent-tertiary-bordervar(--ui-accent-tertiary)
--ui-accent-tertiary-ghost-hover—
--ui-accent-tertiary-glow0 0 transparent
--ui-accent-tertiary-highlightnone
--ui-accent-tertiary-hover—
--ui-accent-tertiary-hover-bordervar(--ui-accent-tertiary-hover)
--ui-accent-tertiary-hover-highlightnone
--ui-accent-tertiary-outline-bordervar(--ui-accent-tertiary-subtle-text)
--ui-accent-tertiary-solid—
--ui-accent-tertiary-subtle-textvar(--ui-accent-tertiary-solid)
--ui-accent-tertiary-wash—
--ui-accent-tertiary-wash-hover—
--ui-accent-wash—
--ui-accent-wash-hover—
--ui-action-edgeinset var(--_ui-action-start) 1px 0 light-dark(rgb(255 255 255 / 0.08), rgb(255 255 255 / 0.06)), inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.08))
--ui-action-radiusvar(--ui-radius-md)
--ui-affordance-guide-colorvar(--ui-border-strong)
--ui-affordance-guide-opacity—
--ui-affordance-guide-size—
--ui-affordance-motionvar(--ui-motion-fast)
--ui-border-strong—
--ui-border-width—
--ui-control-bordervar(--ui-neutral-surface) | var(--ui-border-strong)
--ui-control-border-hovervar(--ui-neutral-hover) | var(--ui-neutral-active) | var(--ui-control-border)
--ui-control-min-block-size—
--ui-control-size-lg—
--ui-control-size-md—
--ui-control-size-sm—
--ui-control-size-xs—
--ui-danger—
--ui-danger-activevar(--ui-danger-hover)
--ui-danger-active-bordervar(--ui-danger-active)
--ui-danger-bordervar(--ui-danger)
--ui-danger-ghost-hover—
--ui-danger-glow0 0 transparent
--ui-danger-highlightnone
--ui-danger-hover—
--ui-danger-hover-bordervar(--ui-danger-hover)
--ui-danger-hover-highlightnone
--ui-danger-on-strong—
--ui-danger-outline-bordervar(--ui-danger-subtle-text)
--ui-danger-subtle-text—
--ui-danger-wash—
--ui-danger-wash-hover—
--ui-disabled-border—
--ui-disabled-filter—
--ui-disabled-surface—
--ui-disabled-text—
--ui-focus-halo—
--ui-focus-width—
--ui-icon-size-lg—
--ui-icon-size-md—
--ui-icon-size-sm—
--ui-icon-size-xs—
--ui-info—
--ui-info-activevar(--ui-info-hover)
--ui-info-active-bordervar(--ui-info-active)
--ui-info-bordervar(--ui-info)
--ui-info-ghost-hover—
--ui-info-glow0 0 transparent
--ui-info-highlightnone
--ui-info-hover—
--ui-info-hover-bordervar(--ui-info-hover)
--ui-info-hover-highlightnone
--ui-info-on-strong—
--ui-info-outline-bordervar(--ui-info-subtle-text)
--ui-info-subtle-text—
--ui-info-wash—
--ui-info-wash-hover—
--ui-inline-control-min-block-size—
--ui-motion-base—
--ui-motion-ease—
--ui-motion-fast—
--ui-motion-pressvar(--ui-motion-fast)
--ui-neutral-activevar(--ui-neutral-hover)
--ui-neutral-ghost-hover—
--ui-neutral-glow0 0 transparent
--ui-neutral-highlightnone
--ui-neutral-hover—
--ui-neutral-shadow—
--ui-neutral-surface—
--ui-neutral-wash-hover—
--ui-non-text-on-accentvar(--ui-text-on-accent)
--ui-non-text-on-accent-secondaryvar(--ui-on-accent-secondary)
--ui-non-text-on-accent-tertiaryvar(--ui-on-accent-tertiary)
--ui-non-text-on-dangervar(--ui-danger-on-strong)
--ui-non-text-on-infovar(--ui-info-on-strong)
--ui-non-text-on-successvar(--ui-success-on-strong)
--ui-non-text-on-warningvar(--ui-warning-on-strong)
--ui-on-accent-secondary—
--ui-on-accent-tertiary—
--ui-press-scale0.96
--ui-pressed—
--ui-radius-md—
--ui-radius-round—
--ui-success—
--ui-success-activevar(--ui-success-hover)
--ui-success-active-bordervar(--ui-success-active)
--ui-success-bordervar(--ui-success)
--ui-success-ghost-hover—
--ui-success-glow0 0 transparent
--ui-success-highlightnone
--ui-success-hover—
--ui-success-hover-bordervar(--ui-success-hover)
--ui-success-hover-highlightnone
--ui-success-on-strong—
--ui-success-outline-bordervar(--ui-success-subtle-text)
--ui-success-subtle-text—
--ui-success-wash—
--ui-success-wash-hover—
--ui-surface-default—
--ui-text—
--ui-text-on-accent—
--ui-text-primary—
--ui-text-secondary—
--ui-warning—
--ui-warning-activevar(--ui-warning-hover)
--ui-warning-active-bordervar(--ui-warning-active)
--ui-warning-bordervar(--ui-warning)
--ui-warning-ghost-hover—
--ui-warning-glow0 0 transparent
--ui-warning-highlightnone
--ui-warning-hover—
--ui-warning-hover-bordervar(--ui-warning-hover)
--ui-warning-hover-highlightnone
--ui-warning-on-strong—
--ui-warning-outline-bordervar(--ui-warning-subtle-text)
--ui-warning-subtle-text—
--ui-warning-wash—
--ui-warning-wash-hover—