Keyboard shortcut: Ctrl + K
Get started

Spinner

A turning ring that says something is happening. It occupies an icon box and paints an icon amount of ink, so it drops into a button or a line of text in place of a glyph.

Usage

vue
Loading…
<script setup lang="ts">
import { VSpinner } from 'vectis-ui'
</script>

<template>
  <VSpinner />
</template>

Examples

Sizes

size is a number of pixels, and it names the box the spinner occupies rather than the diameter of the ring. Left out, the box measures 1em and follows the text around it.

vue

Loading… Follows small text

Loading… Follows large text

Loading… 32 pixels, whatever the text does

<script setup lang="ts">
import { VSpinner } from 'vectis-ui'
</script>

<template>
  <div class="demo">
    <!-- With no size the box measures 1em, so the spinner follows the text around it:
         a container that sets a font-size sizes it without being told anything, which
         is how it stays proportionate inside a button. -->
    <p class="small"><VSpinner /> Follows small text</p>
    <p class="large"><VSpinner /> Follows large text</p>

    <!-- `size` is a number of pixels, and it is the BOX the spinner occupies, not the
         diameter of the ring: the ring is drawn a little smaller inside it, at the
         proportion an icon paints its ink at. -->
    <p><VSpinner :size="32" /> 32 pixels, whatever the text does</p>
  </div>
</template>

<style scoped>
.demo {
  display: grid;
  gap: var(--vectis-space-4);
}
.demo p {
  display: flex;
  align-items: center;
  gap: var(--vectis-space-3);
  margin: 0;
}
.small {
  font-size: var(--vectis-text-body-sm-size);
}
.large {
  font-size: var(--vectis-text-heading-3-size);
}
</style>

Colour

There is no colour prop: the ring is painted in currentcolor, so it takes the colour of the text it sits in.

vue

Loading… The colour of the text it sits in

Sending Sending

Retrying Retrying

<script setup lang="ts">
import { VSpinner } from 'vectis-ui'
</script>

<template>
  <div class="demo">
    <!-- There is no colour prop: the ring is painted in `currentcolor`, so it takes
         the colour of the text around it. Set `color` on the spinner or on anything
         above it, and it follows. -->
    <p><VSpinner /> The colour of the text it sits in</p>
    <p class="accent"><VSpinner label="Sending" /> Sending</p>
    <p class="danger"><VSpinner label="Retrying" /> Retrying</p>
  </div>
</template>

<style scoped>
.demo {
  display: grid;
  gap: var(--vectis-space-3);
}
.demo p {
  display: flex;
  align-items: center;
  gap: var(--vectis-space-3);
  margin: 0;
}
.accent {
  color: var(--vectis-color-accent-text);
}
.danger {
  color: var(--vectis-color-danger-text);
}
</style>

In place of an icon

The box is an icon's box, so a VIcon and a VSpinner given the same size are interchangeable. That is what lets VButton, VInput, VTextarea and VCombobox draw one at the size of the glyph it replaces.

vue

Searching the archive

Loading… Searching the archive

Loading…
<script setup lang="ts">
import { VButton, VIcon, VInput, VSpinner } from 'vectis-ui'
import { search } from 'vectis-ui/icons'
</script>

<template>
  <div class="demo">
    <!-- The spinner occupies an icon's box and paints an icon's amount of ink, so one
         stands in for the other with nothing shifting on the line. A VIcon and a
         VSpinner given the same size are interchangeable, box for box. -->
    <p><VIcon :name="search" /> Searching the archive</p>
    <p><VSpinner /> Searching the archive</p>

    <!-- Which is what lets the controls draw their own: they set the icon size and get
         a spinner the size of the glyph it replaces, with no ratio of their own. -->
    <VButton class="control" loading>Saving</VButton>
    <VInput class="control" label="Reference" model-value="INV-2481" loading />
  </div>
</template>

<style scoped>
.demo {
  display: grid;
  justify-items: start;
  gap: var(--vectis-space-4);
}
.demo p {
  display: flex;
  align-items: center;
  gap: var(--vectis-space-3);
  margin: 0;
}
.control {
  inline-size: 14rem;
}
</style>

API

Props

PropTypeDefault
sizenumber | stringnone
A size in pixels, as a number or a numeric string, understood exactly as VIcon's: it is the box the spinner occupies, not the diameter of the ring, which is drawn slightly smaller inside it. Left out, the box measures 1em and follows the size of the text around it, which is how the spinner stays proportionate inside a button without being told anything.
labelstringnone
What screen readers announce while it turns. It falls back to the design system dictionary, in the current language.