Une courte description de l'élément sous le pointeur, ou sous le focus clavier. C'est une description et jamais un conteneur : rien à l'intérieur ne peut être manipulé.
Utilisation
vue
Copy to the clipboard
<script setup lang="ts">
import { VButton, VTooltip } from 'vectis-ui'
</script>
<template>
<VTooltip text="Copy to the clipboard">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">Copy</VButton>
</template>
</VTooltip>
</template>
Exemples
Placements
placement propose huit côtés, dont quatre alignés sur un bord du déclencheur plutôt que centrés dessus. Il nomme une préférence : le navigateur déplace le panneau quand le côté demandé manque de place.
vue
Placed top
Placed top-start
Placed top-end
Placed bottom
Placed bottom-start
Placed bottom-end
Placed left
Placed right
<script setup lang="ts">
import { VButton, VTooltip, type TooltipPlacement } from 'vectis-ui'
const placements: TooltipPlacement[] = [
'top',
'top-start',
'top-end',
'bottom',
'bottom-start',
'bottom-end',
'left',
'right',
]
</script>
<template>
<!-- Eight sides, four of them aligned to an edge of the trigger rather than centred
on it. The placement names a preference and not a position: with no room on that
side the browser moves the panel by itself. -->
<div class="row">
<VTooltip
v-for="placement in placements"
:key="placement"
:text="`Placed ${placement}`"
:placement="placement"
>
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">{{ placement }}</VButton>
</template>
</VTooltip>
</div>
</template>
<style scoped>
.row {
display: flex;
flex-wrap: wrap;
gap: var(--vectis-space-6) var(--vectis-space-4);
/* Room above and below for the panels, which are drawn outside this box. */
padding-block: var(--vectis-space-8);
}
</style>
Au bord de l'écran
Faute de place du côté demandé, le panneau prend le côté opposé. C'est du CSS pur, sans mesure ni observateur.
vue
Asks for the top, takes the bottom near the edge
Asks for the bottom, takes the top near the edge
<script setup lang="ts">
import { VButton, VTooltip } from 'vectis-ui'
</script>
<template>
<!-- The flip is pure CSS and costs no JavaScript: the panel names the side it would
rather be on, and the browser falls back to the opposite one when the viewport
has no room there. Scroll these buttons up against the top and the bottom of the
window to see it happen. -->
<div class="demo">
<VTooltip text="Asks for the top, takes the bottom near the edge" placement="top">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps"> Prefers the top </VButton>
</template>
</VTooltip>
<VTooltip text="Asks for the bottom, takes the top near the edge" placement="bottom">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">
Prefers the bottom
</VButton>
</template>
</VTooltip>
</div>
</template>
<style scoped>
.demo {
display: flex;
flex-wrap: wrap;
gap: var(--vectis-space-4);
}
</style>
Ouverture et fermeture
delay est le temps pendant lequel le pointeur doit reposer sur le déclencheur avant que l'infobulle apparaisse, 300ms par défaut, et 0 supprime l'attente. Le focus clavier l'ouvre aussitôt, Échap la ferme sans retirer le focus, et appuyer sur le déclencheur la ferme aussi.
vue
Appears after the default wait
Appears after a longer wait
Appears at once
<script setup lang="ts">
import { VButton, VTooltip } from 'vectis-ui'
</script>
<template>
<div class="demo">
<!-- The pointer has to rest on the trigger before the tooltip appears, 300ms by
default, so passing over something on the way somewhere else opens nothing.
Keyboard focus opens it at once instead: the intent is not in doubt there. -->
<VTooltip text="Appears after the default wait">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">300ms</VButton>
</template>
</VTooltip>
<VTooltip text="Appears after a longer wait" :delay="800">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">800ms</VButton>
</template>
</VTooltip>
<!-- A delay of 0 disables the wait entirely. -->
<VTooltip text="Appears at once" :delay="0">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">No wait</VButton>
</template>
</VTooltip>
<!-- Tab to any of these and the tooltip opens immediately; Escape closes it
without taking the focus away, and pressing the trigger closes it too. -->
</div>
</template>
<style scoped>
.demo {
display: flex;
flex-wrap: wrap;
gap: var(--vectis-space-4);
}
</style>
Décrire, pas nommer
L'infobulle pose aria-describedby sur son déclencheur, qui garde son propre nom accessible : un bouton icône porte toujours son label. Une tape n'ouvre rien, ce que dit l'infobulle doit donc exister ailleurs aussi.
vue
Search everything
Export the current view as a CSV file
Discard the draft
<script setup lang="ts">
import { VIconButton, VTooltip } from 'vectis-ui'
import { close, description, search } from 'vectis-ui/icons'
</script>
<template>
<div class="demo">
<!-- The tooltip DESCRIBES and never names: it sets `aria-describedby` on the
trigger, and the trigger keeps its own accessible name. An icon button
therefore still carries its `label`, and the tooltip is the visual
confirmation of it rather than a replacement. -->
<VTooltip text="Search everything">
<template #default="{ triggerProps }">
<VIconButton
v-bind="triggerProps"
:icon="search"
label="Search"
variant="outline"
tone="neutral"
/>
</template>
</VTooltip>
<VTooltip text="Export the current view as a CSV file">
<template #default="{ triggerProps }">
<VIconButton
v-bind="triggerProps"
:icon="description"
label="Export"
variant="outline"
tone="neutral"
/>
</template>
</VTooltip>
<!-- A tap opens nothing, there being no hover on a touch screen and no room for a
panel standing over what the tap just opened. So whatever the tooltip says has
to exist somewhere else too: a visible label, a field hint, a panel. -->
<VTooltip text="Discard the draft">
<template #default="{ triggerProps }">
<VIconButton
v-bind="triggerProps"
:icon="close"
label="Discard"
variant="outline"
tone="danger"
/>
</template>
</VTooltip>
</div>
</template>
<style scoped>
.demo {
display: flex;
flex-wrap: wrap;
gap: var(--vectis-space-4);
}
</style>
Contenu riche
Le slot #content l'emporte sur la prop text quand les deux sont donnés. Il doit rester non interactif : rien à l'intérieur n'est atteignable au clavier, et la description est aplatie en texte simple pour un lecteur d'écran.
vue
Global searchLooks through projects, files and people. Shortcut Ctrl+KRaccourci clavier : Ctrl + K
<script setup lang="ts">
import { VButton, VHotkeys, VTooltip, VTypography } from 'vectis-ui'
</script>
<template>
<!-- The slot wins over the `text` prop when both are given. It has to stay
non-interactive: the tooltip closes as soon as the pointer leaves the trigger,
so a link inside could never be reached, and the description is flattened to
plain text for a screen reader anyway. Anything one can act on belongs in a
panel that stays open. -->
<VTooltip placement="bottom-start">
<template #default="{ triggerProps }">
<VButton variant="outline" tone="neutral" v-bind="triggerProps">Search</VButton>
</template>
<template #content>
<div class="content">
<VTypography variant="label" as="strong">Global search</VTypography>
<span>Looks through projects, files and people.</span>
<!-- The panel is an inverse surface, dark in both themes, and VHotkeys paints
itself from the colour it inherits: the caps follow it with nothing to
set. -->
<span class="shortcut">
Shortcut
<VHotkeys keys="mod+k" variant="outline" />
</span>
</div>
</template>
</VTooltip>
</template>
<style scoped>
.content {
display: grid;
gap: var(--vectis-space-1);
padding-block: var(--vectis-space-1);
}
.shortcut {
display: flex;
align-items: center;
gap: var(--vectis-space-2);
}
</style>
API
Props
Prop
Type
Défaut
text
string
aucune
Ce que dit l'infobulle. Le slot #content la remplace quand les deux sont donnés.
De quel côté de l'élément l'infobulle apparaît. Le navigateur la bascule de lui-même du côté opposé quand la place manque.
delay
number
300
Combien de temps le pointeur doit rester sur l'élément avant que l'infobulle apparaisse, en millisecondes. Le focus clavier l'ouvre immédiatement, l'intention n'y faisant aucun doute, et un délai de 0 supprime entièrement l'attente.
L'élément que l'infobulle décrit. Liez les triggerProps qu'il reçoit dessus, ce qui relie les deux pour les technologies d'assistance, et assurez-vous qu'il puisse prendre le focus, sans quoi les utilisateurs au clavier ne verront jamais l'infobulle.
content
{}
Un contenu plus riche qu'une simple chaîne : une mise en forme, un raccourci clavier, une icône. Il doit rester non interactif : la description est aplatie en texte brut pour les lecteurs d'écran, et rien à l'intérieur n'est atteignable au clavier. Un contenu manipulable appartient à un panneau qui reste ouvert, comme VMenu.
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 type TooltipTriggerProps = {
'aria-describedby': string
}