Spinner

Compact progress indicator for asynchronous work.
vue
<script setup lang="ts">
import { Button, Spinner } from '@typlog/ui'
</script>

<template>
  <div class="flex flex-wrap items-center gap-6">
    <Spinner aria-label="Loading" />
    <Spinner
      size="1"
      color="blue"
      aria-label="Loading"
    />
    <Spinner
      size="3"
      color="green"
      aria-label="Loading"
    />
    <Button
      disabled
      aria-label="Saving changes"
    >
      <Spinner
        size="1"
        aria-hidden="true"
      />
      Saving changes
    </Button>
  </div>
</template>

API Reference ​

PropDefaultType
color
–

Overrides the accent color inherited from the theme.

size"2"
"1""2""3"

Controls the size of the spinner.

By default, Spinner is decorative and hidden from assistive technology. Passing aria-label or aria-labelledby gives it a status role automatically; pass an explicit role to override that default. When a spinner appears inside a Button that already has an accessible name, use aria-hidden="true" on the spinner.

Examples ​

Size ​

Size 1
Size 2
Size 3
vue
<script setup lang="ts">
import { Spinner } from '@typlog/ui'
</script>

<template>
  <div class="flex flex-wrap items-end gap-6">
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner
        size="1"
        aria-label="Loading, size 1"
      />
      <span class="text-sm text-gray-11">Size 1</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner
        size="2"
        aria-label="Loading, size 2"
      />
      <span class="text-sm text-gray-11">Size 2</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner
        size="3"
        aria-label="Loading, size 3"
      />
      <span class="text-sm text-gray-11">Size 3</span>
    </div>
  </div>
</template>

Color ​

Gray
Blue
Green
Amber
Red
Violet
vue
<script setup lang="ts">
import { Spinner } from '@typlog/ui'
</script>

<template>
  <div class="flex flex-wrap items-end gap-6">
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="gray" aria-label="Loading, gray" />
      <span class="text-sm text-gray-11">Gray</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="blue" aria-label="Loading, blue" />
      <span class="text-sm text-gray-11">Blue</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="green" aria-label="Loading, green" />
      <span class="text-sm text-gray-11">Green</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="amber" aria-label="Loading, amber" />
      <span class="text-sm text-gray-11">Amber</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="red" aria-label="Loading, red" />
      <span class="text-sm text-gray-11">Red</span>
    </div>
    <div class="flex flex-col items-center gap-2 text-center">
      <Spinner color="violet" aria-label="Loading, violet" />
      <span class="text-sm text-gray-11">Violet</span>
    </div>
  </div>
</template>

Status indicators ​

SpinnerIcon is the unstyled, current-color glyph used inside composed controls. SavingIndicator switches between idle, saving, and saved states. Pair either visual with accessible status text when it communicates state.

Loading Saving Saved
vue
<script setup lang="ts">
import { SavingIndicator, SpinnerIcon } from '@typlog/ui'
</script>

<template>
  <div class="flex items-center gap-6">
    <span class="flex items-center gap-2">
      <SpinnerIcon aria-hidden="true" />
      Loading
    </span>
    <span class="flex items-center gap-2">
      <SavingIndicator status="saving" aria-hidden="true" />
      Saving
    </span>
    <span class="flex items-center gap-2">
      <SavingIndicator status="saved" aria-hidden="true" />
      Saved
    </span>
  </div>
</template>
PropDefaultType
size"2"
"1""2""3"
status
–
SavingStatus
Last updated Sep 15, 2026