NbInfoHint is a small, discreet affordance you drop next to anything whose meaning is not self-evident: a KPI number, a status word, a column header, an abbreviation. It renders a compact icon in a subtle token colour and reveals a short description on hover, focus, or click.
It exists so applications stop hand-rolling little grey question marks with hardcoded colours. Every colour here comes from the semantic token layer, so the hint follows the theme without the host knowing anything about it.
<template>
<span>Archived</span>
<NbInfoHint
text="Items moved out of the active list. Kept for 90 days, then deleted."
/>
</template>Where it earns its place
Put a hint next to a label whose meaning a new user cannot guess. Do not use it for content that belongs in the interface itself: if every user needs the sentence, write the sentence.
Hover, focus and touch
The popover opens on hover for pointer users and on focus for keyboard users. A click or tap pins it open, which is what makes it usable on touch devices, where there is no hover at all. A pinned popover is dismissed by clicking the icon again, pressing Escape, or clicking anywhere outside it.
Placement
placement is a preference, not a guarantee. When the preferred side would push the popover off-screen it flips to the opposite side, then to the orthogonal sides, and finally clamps itself inside the viewport with the arrow re-aimed at the icon.
Rich content
Use the default slot when a single sentence is not enough. The slot content inherits the popover's surface tokens, so nested markup themes correctly on its own.
<template>
<NbInfoHint title="How this is calculated">
<p>Tasks finished in the period divided by tasks that came due in it.</p>
<p>Cancelled tasks are excluded from both sides.</p>
</NbInfoHint>
</template>Inside clickable rows and cards
A hint routinely lives inside something that is itself clickable. NbInfoHint stops click, mousedown and pointerdown from propagating, so opening a hint never triggers the host's action.
Wiring a glossary
term is an opaque identifier the library never resolves. It is mirrored onto data-term and echoed back on the activate event, so an app can map hints to a central glossary, count which concepts confuse people, or deep-link into its own documentation.
<template>
<NbInfoHint
term="status.archived"
:text="glossary['status.archived']"
@activate="openGlossary"
/>
</template>
<script setup lang="ts">
import { glossary } from '@/content/glossary'
function openGlossary(term?: string) {
if (term) router.push({ name: 'glossary', hash: `#${term}` })
}
</script>Replacing a hand-rolled help icon
A component like this is the usual reason a codebase ends up with literal greys in it:
<!-- Before: colours frozen at author time, wrong in one theme or the other -->
<template>
<i class="help" style="color: #94a3b8" @mouseenter="show = true">?</i>
</template><!-- After: the same affordance, themed by the design system -->
<template>
<NbInfoHint icon="question" :text="description" />
</template>Accessibility
- The trigger is a real
<button>, so it is reachable by Tab and activated by Enter or Space. aria-expandedreflects the open state;aria-describedbypoints at the popover only while it is visible, so the description is announced as the button's description rather than duplicated in its name.- Give
labela specific value when the hint sits next to an ambiguous value: the default name, "More information", tells a screen-reader user nothing about what is being explained. - Escape closes the popover and leaves focus on the trigger.
- The open animation is suppressed under
prefers-reduced-motion: reduce.