Raccourci clavier : Ctrl + K
Commencer

Groupe de boutons

Assemble des boutons en un seul contrôle segmenté : bordures fusionnées, coins arrondis aux extrémités seulement. La rangée est un objet unique, donc c'est le groupe qui décide de son dessin, depuis le fait même d'assembler les boutons jusqu'à la variante, le ton, la taille et la densité que chacun d'eux reprend.

Utilisation

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

<template>
  <VButtonGroup variant="outline" tone="neutral" label="Text alignment">
    <VButton>Left</VButton>
    <VButton>Centre</VButton>
    <VButton>Right</VButton>
  </VButtonGroup>
</template>

Exemples

Variantes et tons

variant et tone se posent une fois sur le groupe. La variante l'emporte sur celle donnée à un bouton ; le ton n'est qu'une valeur de repli.

vue
<script setup lang="ts">
import { VButton, VButtonGroup } from 'vectis-ui'

const variants = ['solid', 'soft', 'outline', 'ghost'] as const
const tones = ['accent', 'neutral', 'danger'] as const
</script>

<template>
  <div v-for="tone in tones" :key="tone" class="row">
    <VButtonGroup
      v-for="variant in variants"
      :key="variant"
      :variant="variant"
      :tone="tone"
      :label="`${variant} ${tone}`"
    >
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--vectis-space-4);
}
</style>

Un segment, un autre ton

Un segment garde son propre tone face au groupe, ce qui permet à une rangée neutre de porter une seule action destructrice.

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

<template>
  <div class="column">
    <VButtonGroup variant="outline" tone="neutral" label="Row actions, outline">
      <VButton>Rename</VButton>
      <VButton>Duplicate</VButton>
      <VButton tone="danger">Delete</VButton>
    </VButtonGroup>

    <VButtonGroup variant="soft" tone="neutral" label="Row actions, tonal">
      <VButton>Rename</VButton>
      <VButton>Duplicate</VButton>
      <VButton tone="danger">Delete</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
}
</style>

Orientation

vertical empile les segments en colonne plutôt qu'en rangée, la jonction suivant l'axe.

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

<template>
  <VButtonGroup variant="outline" tone="neutral" label="Range, as a row">
    <VButton>Day</VButton>
    <VButton>Week</VButton>
    <VButton>Month</VButton>
  </VButtonGroup>

  <VButtonGroup orientation="vertical" variant="outline" tone="neutral" label="Range, as a column">
    <VButton>Day</VButton>
    <VButton>Week</VButton>
    <VButton>Month</VButton>
  </VButtonGroup>
</template>

Séparés

detached laisse les boutons séparés, chacun gardant ses coins et ses bordures, le groupe continuant de transmettre ses props d'apparence.

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

<template>
  <div class="column">
    <VButtonGroup variant="outline" tone="neutral" label="Joined">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup detached variant="outline" tone="neutral" label="Detached">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
}
</style>

Sans traits

seamless retire les traits dessinés à chaque jonction, ne laissant qu'un seul cadre aux bords extérieurs intacts.

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

<template>
  <div class="column">
    <VButtonGroup variant="outline" tone="neutral" label="With lines">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup seamless variant="outline" tone="neutral" label="Seamless">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
}
</style>

Surélevé

elevated donne l'ombre à la rangée plutôt qu'à chaque segment. En mode détaché, chaque bouton porte de nouveau la sienne.

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

<template>
  <div class="column">
    <VButtonGroup variant="ghost" tone="neutral" label="Flat">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup elevated variant="ghost" tone="neutral" label="Raised">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup elevated detached variant="ghost" tone="neutral" label="Raised, detached">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-4);
}
</style>

Tailles

size définit la hauteur de chaque segment : 24, 32, 40, 48 ou 56 pixels. Elle l'emporte sur celle donnée à un bouton.

vue
<script setup lang="ts">
import { VButton, VButtonGroup } from 'vectis-ui'

const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
</script>

<template>
  <div class="column">
    <VButtonGroup
      v-for="size in sizes"
      :key="size"
      :size="size"
      variant="outline"
      tone="neutral"
      :label="`Range, ${size}`"
    >
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
}
</style>

Compact

compact retire 4px à la hauteur de chaque segment.

vue
<script setup lang="ts">
import { VButton, VButtonGroup } from 'vectis-ui'

const sizes = ['sm', 'md', 'lg'] as const
</script>

<template>
  <div v-for="size in sizes" :key="size" class="row">
    <VButtonGroup :size="size" variant="outline" tone="neutral" :label="size">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup :size="size" compact variant="outline" tone="neutral" :label="`${size} compact`">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--vectis-space-4);
}
</style>

Pleine largeur

fullWidth étire la rangée sur son parent et donne à chaque segment une part égale de cette largeur.

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

<template>
  <div class="column">
    <VButtonGroup variant="outline" tone="neutral" label="As wide as its labels">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>

    <VButtonGroup full-width variant="outline" tone="neutral" label="Filling the column">
      <VButton>Day</VButton>
      <VButton>Week</VButton>
      <VButton>Month</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
/* A column narrower than the page, so that filling it is something to see. The rows are
   aligned to the start, which is what leaves the first at the width of its own labels. */
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
  inline-size: 320px;
}
</style>

Avec des icônes

Les segments portent iconStart et iconEnd comme n'importe quel bouton. Un VIconButton est aussi un segment, et demande toujours son label.

vue
<script setup lang="ts">
import { VButton, VButtonGroup, VIconButton } from 'vectis-ui'
import {
  arrow_downward as arrowDownward,
  arrow_upward as arrowUpward,
  description,
  image,
  swap_vert as swapVert,
  table_chart as tableChart,
} from 'vectis-ui/icons'
</script>

<template>
  <VButtonGroup variant="outline" tone="neutral" label="View">
    <VButton :icon-start="description">List</VButton>
    <VButton :icon-start="tableChart">Table</VButton>
    <VButton :icon-start="image">Gallery</VButton>
  </VButtonGroup>

  <VButtonGroup role="toolbar" variant="outline" tone="neutral" label="Sort">
    <VIconButton :icon="arrowUpward" label="Ascending" />
    <VIconButton :icon="swapVert" label="Unsorted" />
    <VIconButton :icon="arrowDownward" label="Descending" />
  </VButtonGroup>
</template>

Un segment auquel on donne un href rend un <a>. Un lien désactivé voit son adresse retirée, ce qui le laisse ni focalisable ni suivable.

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

<template>
  <VButtonGroup variant="outline" tone="neutral" label="Sections of this page">
    <VButton href="#usage">Usage</VButton>
    <VButton href="#examples">Examples</VButton>
    <VButton href="#api">API</VButton>
    <VButton href="#usage" disabled>Changelog</VButton>
  </VButtonGroup>
</template>

États

disabled posé sur le groupe s'ajoute à celui de chaque bouton : un segment ne peut pas se réactiver une fois la rangée coupée. loading reste propre au bouton.

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

<template>
  <div class="column">
    <VButtonGroup disabled variant="outline" tone="neutral" label="Row switched off">
      <VButton>Rename</VButton>
      <VButton>Duplicate</VButton>
      <VButton>Delete</VButton>
    </VButtonGroup>

    <VButtonGroup variant="outline" tone="neutral" label="One segment at a time">
      <VButton>Rename</VButton>
      <VButton disabled>Duplicate</VButton>
      <VButton loading>Deleting</VButton>
    </VButtonGroup>
  </div>
</template>

<style scoped>
.column {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: var(--vectis-space-3);
}
</style>

API

Props

PropTypeDéfaut
orientationButtonGroupOrientation'horizontal' | 'vertical''horizontal'
Le sens dans lequel les boutons sont assemblés : une rangée par défaut, ou une colonne avec vertical.
detachedbooleanfalse
Laisse les boutons séparés, avec un écart entre eux et chacun gardant ses propres coins, au lieu de les assembler en contrôle segmenté. Tout ce que le groupe transmet circule toujours, et une rangée surélevée laisse alors chaque bouton porter sa propre ombre.
seamlessbooleanfalse
Retire les traits entre les boutons assemblés : aucune couture n'est dessinée, et les bordures des deux côtés de chaque arête partagée sont effacées, si bien que la rangée se lit comme un cadre unique plutôt que comme des segments. Les arêtes extérieures restent. Sans effet sous detached, où aucune arête n'est partagée.
fullWidthbooleanfalse
Étire la rangée sur toute la largeur de son parent, chaque segment prenant une part égale de cette largeur quel que soit son libellé. Un segment ne descend jamais sous la largeur de son propre libellé : une rangée de libellés trop longs pour le parent le déborde au lieu d'être écrasée. Sous vertical, il ne reste que la largeur, une colonne étirant déjà chaque segment.
variantButtonVariant'solid' | 'outline' | 'ghost' | 'soft'aucune
Le poids visuel que porte chaque segment, sur les valeurs de VButton : solid, outline, ghost ou soft. Il l'emporte sur la variante donnée à un bouton, un segment d'une autre silhouette ne se lisant plus comme un morceau de la rangée. Omis, chaque bouton garde la sienne.
toneButtonTone'accent' | 'neutral' | 'danger'aucune
La couleur des segments, parmi accent, neutral et danger. Celui-ci est un repli et non un ordre : un bouton qui nomme son propre ton le garde, ce qui permet à une seule action destructrice de se signaler dans la rangée.
sizeButtonSize'xs' | 'sm' | 'md' | 'lg' | 'xl'aucune
La hauteur des segments, tirée de l'échelle de tailles partagée par tous les contrôles : xs, sm, md, lg ou xl. Elle l'emporte sur la taille donnée à un bouton. Omise, chaque bouton garde la sienne.
compactbooleanaucune
Retire 4px à la hauteur de chaque segment. Il l'emporte sur la valeur donnée à un bouton. Omis, chaque bouton garde la sienne.
elevatedbooleanaucune
Soulève la rangée avec l'échelle d'ombres, aux conditions de la prop de VButton. L'ombre est celle de la rangée et non celle de chaque segment, ce qui garde les joints nets : trois ombres qui se chevauchent y dessineraient une bande sombre. Il l'emporte sur la valeur donnée à un bouton. Omis, chaque bouton garde la sienne.
disabledbooleanaucune
Rend chaque segment inutilisable. Celui-ci s'ajoute au lieu de trancher : un bouton qui se désactive lui-même le reste dans une rangée qui ne dit rien, et un segment ne peut pas se réactiver une fois la rangée éteinte.
labelstringaucune
Ce que les lecteurs d'écran annoncent pour la rangée, qui est un role="group" : « Mise en forme », « Affichage ». Un groupe sans nom est annoncé comme un simple groupe. Un aria-label ou un aria-labelledby posé par le consommateur l'emporte.

Slots

SlotType
default{}
Les VButton et VIconButton à assembler.