Skip to content

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.

10
24
vue
<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.

vue
<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.

vue
<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:

vue
<!-- 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>
vue
<!-- 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-expanded reflects the open state; aria-describedby points 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 label a 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.

Props ​

PropTypeDefaultDescription
textstring—Plain-text description. Ignored when the default slot is used.
titlestring—Optional bold heading above the body.
termstring—Glossary / doc identifier. Mirrored to data-term and emitted on activate. Never resolved by the library.
placement'top' | 'bottom' | 'left' | 'right''top'Preferred side. Flipped and clamped to stay in the viewport.
sizenumber14Icon size in pixels.
iconstring'info'Any icon name NbIcon accepts, e.g. 'question'.
labelstring'More information'Accessible name for the trigger button.
openDelaynumber120Milliseconds before a hover opens the popover.
closeDelaynumber140Milliseconds before leaving the trigger closes it. Ignored while pinned.
teleportTostring'body'Teleport target for the popover.
disabledbooleanfalseRenders the icon inert and suppresses the popover.

Events ​

EventPayloadDescription
open—The popover became visible, by hover, focus or click.
close—The popover was dismissed.
activateterm?: stringThe hint was deliberately activated (click / Enter / Space), not merely hovered. Use this, not open, to drive glossary navigation or analytics.

Slots ​

SlotPropsDescription
default—Rich popover body. Takes precedence over the text prop when provided.

Exposed methods ​

MemberTypeDescription
open() => voidOpens the popover imperatively.
close() => voidCloses the popover imperatively.
isOpenRef<boolean>Current visibility.

Tokens used ​

TokenApplied to
--nb-c-text-subtle / --nb-c-textIcon at rest / on hover and focus
--nb-c-layer-3, --nb-c-layer-border-3Popover surface and border (overlay depth)
--nb-c-text, --nb-c-text-mutedPopover title and body
--nb-c-scrimPopover shadow
--nb-c-focus-ringFocus outline
--nb-radius-md, --nb-radius-pillPopover and trigger rounding
--nb-type-label-md-*, --nb-type-body-sm-*Title and body typography