Raccourci clavier : Ctrl + K
Commencer

Progression linéaire

Une barre qui se remplit à mesure que quelque chose avance, ou s'anime en continu quand il n'y a aucun chiffre à rapporter. Elle peut être dressée à la verticale, et porter son propre pourcentage à l'intérieur.

Utilisation

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

<template>
  <VProgressLinear :value="40" label="Upload" />
</template>

Exemples

Valeur

value est l'avancement, face à un max qui dit ce qui compte comme terminé. Tout ce qui sort de la plage y est ramené.

vue
40 %

value = 40, max = 100

7 of 12 files, max = 12

58 %
<script setup lang="ts">
import { ref } from 'vue'
import { VButton, VProgressLinear, VTypography } from 'vectis-ui'

const value = ref(40)
const step = (delta: number) => (value.value += delta)
</script>

<template>
  <div class="column">
    <VProgressLinear :value="value" thickness="10" label="Upload" show-value />

    <div class="row">
      <VButton variant="outline" tone="neutral" size="sm" @click="step(-25)">-25</VButton>
      <VButton variant="outline" tone="neutral" size="sm" @click="step(25)">+25</VButton>
      <!-- Anything outside the range is brought back into it, so a value of 130 or -10
           needs no clamping of your own. -->
      <VTypography variant="body-sm" tone="muted">value = {{ value }}, max = 100</VTypography>
    </div>

    <!-- `max` says what counts as finished. The other end is always zero. -->
    <div class="labelled">
      <VTypography variant="caption" tone="muted">7 of 12 files, max = 12</VTypography>
      <VProgressLinear :value="7" :max="12" thickness="10" label="Files" show-value />
    </div>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-5);
  max-inline-size: 28rem;
}
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--vectis-space-3);
}
.labelled {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

Indéterminé

indeterminate sert à une attente qui ne se mesure pas : la barre s'anime en continu et la valeur est ignorée. Sous animation réduite, elle est ralentie plutôt qu'arrêtée.

vue

For a server that reports no percentage. Under reduced motion the bar is slowed rather than stopped: a motionless loader no longer says that anything is happening, which is the one thing it exists to say.

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

<template>
  <div class="column">
    <!-- One bar crosses the track, flush with each edge at the extremes, so the loop is
         invisible and the track is never empty. The value is ignored: there is nothing
         to report. -->
    <VProgressLinear indeterminate label="Waiting for the server" />

    <VProgressLinear indeterminate tone="neutral" thickness="8" label="Loading" />

    <VTypography variant="body-sm" tone="muted">
      For a server that reports no percentage. Under reduced motion the bar is slowed rather than
      stopped: a motionless loader no longer says that anything is happening, which is the one thing
      it exists to say.
    </VTypography>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-5);
  max-inline-size: 28rem;
}
</style>

Tonalités

tone dit ce que signifie la progression, sous forme de couleur. Il y en a cinq plutôt que les trois d'un bouton, une barre rendant compte d'un état plutôt que d'amorcer une action.

vue

accent

success

warning

danger

neutral

<script setup lang="ts">
import { VProgressLinear, VTypography, type ProgressLinearTone } from 'vectis-ui'

const TONES: ProgressLinearTone[] = ['accent', 'success', 'warning', 'danger', 'neutral']
</script>

<template>
  <div class="column">
    <div v-for="tone in TONES" :key="tone" class="row">
      <VTypography variant="caption" tone="muted" class="name">{{ tone }}</VTypography>
      <VProgressLinear :value="60" :tone="tone" :label="`Upload, ${tone}`" />
    </div>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-4);
  max-inline-size: 28rem;
}
.row {
  display: grid;
  grid-template-columns: 5rem 1fr;
  align-items: center;
  gap: var(--vectis-space-4);
}
.name {
  text-align: end;
}
</style>

Couleurs personnalisées

color remplace le ton, en hexadécimal, en nom CSS ou en oklch(). La nuance du rail en est dérivée face au thème.

vue

A hex value

A CSS colour name

An oklch() colour

<script setup lang="ts">
import { VProgressLinear, VTypography } from 'vectis-ui'

const COLORS = [
  { value: '#7c3aed', caption: 'A hex value' },
  { value: 'teal', caption: 'A CSS colour name' },
  { value: 'oklch(0.72 0.19 45)', caption: 'An oklch() colour' },
]
</script>

<template>
  <div class="column">
    <div v-for="colour in COLORS" :key="colour.value" class="row">
      <VTypography variant="caption" tone="muted" class="name">{{ colour.caption }}</VTypography>
      <!-- The track's own shade is derived from the colour against the theme, so both
           follow: one value to set, and it stays right in dark mode. -->
      <VProgressLinear :value="60" :color="colour.value" :label="`Upload, ${colour.caption}`" />
    </div>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-4);
  max-inline-size: 28rem;
}
.row {
  display: grid;
  grid-template-columns: 9rem 1fr;
  align-items: center;
  gap: var(--vectis-space-4);
}
.name {
  text-align: end;
}
</style>

Épaisseur

thickness est toujours en pixels, qu'elle soit donnée en nombre ou en chaîne numérique, et vaut 4px sauf indication contraire. Il n'y a pas de prop de longueur à côté : la barre prend la largeur de ce qui la contient.

vue

2px

4px

8px

16px

<script setup lang="ts">
import { VProgressLinear, VTypography } from 'vectis-ui'

const THICKNESSES = [2, 4, 8, 16]
</script>

<template>
  <div class="column">
    <!-- Always pixels, whether a number or a numeric string. The bar takes the width of
         whatever holds it, so its length is the container's business and not a prop. -->
    <div v-for="thickness in THICKNESSES" :key="thickness" class="row">
      <VTypography variant="caption" tone="muted" class="name">{{ thickness }}px</VTypography>
      <VProgressLinear :value="60" :thickness="thickness" :label="`Upload, ${thickness}px`" />
    </div>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-4);
  max-inline-size: 28rem;
}
.row {
  display: grid;
  grid-template-columns: 4rem 1fr;
  align-items: center;
  gap: var(--vectis-space-4);
}
.name {
  text-align: end;
}
</style>

Forme

shape dit si les extrémités de la barre sont arrondies ou coupées net. Cela se voit sur une barre épaisse et presque pas sur les 4px par défaut.

vue

rounded, the default

square

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

<template>
  <div class="column">
    <div class="labelled">
      <VTypography variant="caption" tone="muted">rounded, the default</VTypography>
      <VProgressLinear :value="60" thickness="14" label="Upload, rounded" />
    </div>

    <div class="labelled">
      <VTypography variant="caption" tone="muted">square</VTypography>
      <VProgressLinear :value="60" thickness="14" shape="square" label="Upload, square" />
    </div>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-5);
  max-inline-size: 28rem;
}
.labelled {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

Du contenu dans la barre

showValue écrit le pourcentage dans la barre et valuePosition dit où ce texte se place le long de celle-ci. Le slot par défaut remplace le chiffre et reçoit la valeur, le max et le pourcentage. Le contenu est rendu deux fois, une fois sur le rail et une fois sur le remplissage : il doit donc être sans effet de bord.

vue

valuePosition start

55 %

valuePosition center

55 %

valuePosition end

55 %

A slot of your own

7 of 12 files

The bar is 4px by default, so writing inside it means giving it a thickness that can hold a line of text.

<script setup lang="ts">
import { VProgressLinear, VTypography, type ProgressLinearValuePosition } from 'vectis-ui'

const POSITIONS: ProgressLinearValuePosition[] = ['start', 'center', 'end']
</script>

<template>
  <div class="column">
    <!-- The text is rendered TWICE: once over the empty track, once over the fill in a
         contrasting colour, the second copy clipped at the fill's edge. Whatever the
         slot renders must therefore be free of side effects. -->
    <div v-for="position in POSITIONS" :key="position" class="labelled">
      <VTypography variant="caption" tone="muted">valuePosition {{ position }}</VTypography>
      <VProgressLinear
        :value="55"
        thickness="22"
        show-value
        :value-position="position"
        :label="`Upload, ${position}`"
      />
    </div>

    <!-- The slot replaces the percentage and receives the value, the max and the
         percentage worked out from them. -->
    <div class="labelled">
      <VTypography variant="caption" tone="muted">A slot of your own</VTypography>
      <VProgressLinear :value="7" :max="12" thickness="22" label="Files uploaded">
        <template #default="{ value, max }">{{ value }} of {{ max }} files</template>
      </VProgressLinear>
    </div>

    <VTypography variant="body-sm" tone="muted">
      The bar is 4px by default, so writing inside it means giving it a thickness that can hold a
      line of text.
    </VTypography>
  </div>
</template>

<style scoped>
.column {
  display: grid;
  gap: var(--vectis-space-5);
  max-inline-size: 28rem;
}
.labelled {
  display: grid;
  gap: var(--vectis-space-2);
}
</style>

Orientation

orientation à vertical remplit la barre du bas vers le haut, y compris dans une page de droite à gauche. Sa longueur est un token, 10rem par défaut, que votre propre hauteur remplace. Les copies de texte restent horizontales.

vue

25%

60%

90%

indeterminate

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

<template>
  <div class="row">
    <!-- Upright, the bar fills from the BOTTOM up: zero is anchored to the bottom edge,
         so a vertical bar reads the way a gauge does. It takes the height of whatever
         holds it, the way the horizontal one takes the width. -->
    <div v-for="value in [25, 60, 90]" :key="value" class="gauge">
      <VProgressLinear
        :value="value"
        orientation="vertical"
        thickness="14"
        :label="`Tank, ${value} percent`"
      />
      <VTypography variant="caption" tone="muted">{{ value }}%</VTypography>
    </div>

    <div class="gauge">
      <VProgressLinear indeterminate orientation="vertical" thickness="14" label="Filling" />
      <VTypography variant="caption" tone="muted">indeterminate</VTypography>
    </div>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  align-items: end;
  gap: var(--vectis-space-6);
}
.gauge {
  display: grid;
  justify-items: center;
  gap: var(--vectis-space-2);
  /* The bar takes the height it is given, exactly as the horizontal one takes a width. */
  block-size: 9rem;
  grid-template-rows: 1fr auto;
}
</style>

API

Props

PropTypeDéfaut
valuenumber0
Où en est la progression. Tout ce qui sort de l'intervalle y est ramené.
labelstringaucune
Ce qui progresse, en mots, pour les lecteurs d'écran. Rien ne s'affiche à l'écran, et le dictionnaire du design system sert de repli ; un aria-label ou un aria-labelledby à vous l'emporte sur lui.
maxnumber100
Ce qui compte comme terminé. L'autre extrémité est toujours zéro.
indeterminatebooleanfalse
Dit que la progression ne peut pas être mesurée : la barre s'anime en continu et la valeur est ignorée. C'est ce qu'il faut utiliser en attendant un serveur qui ne rapporte aucun pourcentage.
toneProgressLinearTone'neutral' | 'accent' | 'danger' | 'success' | 'warning''accent'
Ce que la progression signifie, exprimé en couleur.
colorstringaucune
Une couleur à vous, en hexadécimal, en nom CSS ou en oklch(), qui remplace le ton. La nuance de la piste en est dérivée face au thème, elle suit donc les deux.
thicknessnumber | stringaucune
L'épaisseur de la barre, toujours EN PIXELS : 12 et '12' donnent tous deux 12px. Elle vaut 4px par défaut : afficher du texte dans la barre demande donc une épaisseur explicite.
shapeProgressLinearShape'rounded' | 'square''rounded'
Si les extrémités de la barre sont arrondies ou carrées.
showValuebooleanfalse
Écrit le pourcentage dans la barre. C'est ignoré tant que la progression n'est pas mesurable, faute de chiffre à écrire.
valuePositionProgressLinearValuePosition'start' | 'center' | 'end''center'
Où se place ce texte le long de la barre. Sur une barre verticale, le début est l'extrémité zéro, donc le bas.
orientationProgressLinearOrientation'horizontal' | 'vertical''horizontal'
Dresse la barre à la verticale, qui se remplit du bas vers le haut.

Slots

SlotType
defaultProgressLinearSlotProps
Ce qu'il faut écrire dans la barre à la place du pourcentage. Il est rendu DEUX FOIS, une fois sur la piste vide et une fois sur la partie remplie dans une couleur contrastée, chaque copie étant coupée au bord du remplissage : ce qu'il rend doit donc être exempt d'effets de bord.

Types

Les types que les tables ci-dessus nomment, écrits comme la librairie les déclare. Ceux qui portent export s'importent depuis vectis-ui pour typer votre propre code ; les autres décrivent la forme de ce qu'un slot fournit.

export interface ProgressLinearSlotProps {
  value: number
  max: number
  percent: number
}

Variables CSS

TokenValeur
--vectis-control-size-progress-linear-thickness0.25rem
--vectis-control-size-progress-linear-length10rem