Tooltip Plugin
The Tooltip plugin shows popover tooltips when header or cell text overflows its container. It uses the Popover API with CSS anchor positioning for a native, consistent experience across browsers — with a JavaScript fallback for older browsers.
Tooltips appear automatically on hover. Per-column overrides let you provide custom static text or dynamic content derived from row data.
Installation
Section titled “Installation”import '@toolbox-web/grid/features/tooltip';Basic Usage
Section titled “Basic Usage”import { queryGrid } from '@toolbox-web/grid';import '@toolbox-web/grid/features/tooltip';
const grid = queryGrid('tbw-grid');grid.gridConfig = { columns: [ { field: 'id', header: 'ID', width: 60 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email Address' }, { field: 'department', header: 'Department / Division' }, ], features: { tooltip: true },};import '@toolbox-web/grid-react/features/tooltip';import { DataGrid } from '@toolbox-web/grid-react';import type { GridConfig } from '@toolbox-web/grid-react';
const gridConfig: GridConfig = { columns: [ { field: 'id', header: 'ID', width: 60 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email Address' }, ], features: { tooltip: true },};
function App({ data }) { return <DataGrid rows={data} gridConfig={gridConfig} style={{ height: '400px' }} />;}<script setup>import '@toolbox-web/grid-vue/features/tooltip';import { TbwGrid } from '@toolbox-web/grid-vue';import type { GridConfig } from '@toolbox-web/grid-vue';
const gridConfig: GridConfig = { columns: [ { field: 'id', header: 'ID', width: 60 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email Address' }, ], features: { tooltip: true },};</script>
<template> <TbwGrid :rows="data" :grid-config="gridConfig" style="height: 400px" /></template>import '@toolbox-web/grid-angular/features/tooltip';import { Component } from '@angular/core';import { Grid } from '@toolbox-web/grid-angular';import type { GridConfig } from '@toolbox-web/grid-angular';
@Component({ selector: 'app-grid', imports: [Grid], template: ` <tbw-grid [rows]="rows" [gridConfig]="gridConfig" style="height: 400px; display: block;"> </tbw-grid> `,})export class GridComponent { rows = []; gridConfig: GridConfig = { columns: [ { field: 'id', header: 'ID', width: 60 }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email Address' }, ], features: { tooltip: true }, };}Hover over truncated column headers or cell values to see tooltips. Toggle header/cell tooltips with the controls. The Job Title column demonstrates a custom headerTooltip string and a dynamic cellTooltip function.
<tbw-grid style="height: 400px;"></tbw-grid>import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';import '@toolbox-web/grid/features/tooltip';
const grid = queryGrid('tbw-grid');
const sampleData = [ { id: 1, name: 'Alice Johnson', email: 'alice.johnson@acmecorporation.com', department: 'Engineering & Development', role: 'Senior Software Engineer' }, { id: 2, name: 'Bob Smith', email: 'bob.smith@acmecorporation.com', department: 'Marketing & Communications', role: 'Brand Strategy Director' }, { id: 3, name: 'Carol Williams', email: 'carol.williams@acmecorporation.com', department: 'Human Resources', role: 'Recruitment Specialist' }, { id: 4, name: 'David Brown', email: 'david.brown@acmecorporation.com', department: 'Sales & Business Development', role: 'Regional Account Manager' }, { id: 5, name: 'Eve Davis', email: 'eve.davis@acmecorporation.com', department: 'Finance & Accounting', role: 'Senior Financial Analyst' },];
function rebuild(opts: Record<string, unknown>) { grid.gridConfig = { columns: [ { field: 'id', header: 'ID', width: 50 }, { field: 'name', header: 'Full Name', width: 100 }, { field: 'email', header: 'Email Address', width: 120 }, { field: 'department', header: 'Department / Division', width: 110 }, { field: 'role', header: 'Job Title & Responsibilities', width: 120, headerTooltip: 'The official job title and primary area of responsibility', cellTooltip: (ctx) => `${ctx.row.name} — ${ctx.value}` }, ], features: { tooltip: { header: (opts.header) ?? true, cell: (opts.cell) ?? true, }, }, }; grid.rows = sampleData;}
rebuild({ header: true, cell: true });Configuration Options
Section titled “Configuration Options”| Option | Type | Default | Description |
|---|---|---|---|
header | boolean | true | Enable automatic tooltips on overflowing header text |
cell | boolean | true | Enable automatic tooltips on overflowing cell text |
focus | boolean | true | Show the tooltip for the focused cell during keyboard navigation. Pointer interaction is unaffected. |
hideDelay | number | 120 | Grace period in milliseconds before the tooltip hides once the pointer leaves the cell, so it can be moved onto the tooltip itself. 0 hides immediately. |
Per-Column Overrides
Section titled “Per-Column Overrides”Override tooltip behavior on individual columns with headerTooltip and cellTooltip:
const columns = [ // Static header tooltip { field: 'revenue', header: 'Rev.', headerTooltip: 'Total revenue in USD (before tax)' },
// Dynamic cell tooltip that adds context beyond the cell value { field: 'name', cellTooltip: (ctx) => `Hired ${new Date(ctx.row.hireDate).toLocaleDateString()}` },
// Disable tooltip for a specific column { field: 'actions', cellTooltip: false, headerTooltip: false },];| Property | Type | Description |
|---|---|---|
headerTooltip | false | string | (ctx) => string | null | Override header tooltip. false disables it, a string sets static text, a function returns dynamic text (return null to suppress). |
cellTooltip | false | string | (ctx) => string | null | Override cell tooltip. Same signature as headerTooltip. The callback receives { value, row, field, column }. |
Styling
Section titled “Styling”The tooltip is placed above the anchor cell whenever it fits there, and drops below only when the space above the cell is too small. A directional arrow points at the anchor and flips with the placement. It supports CSS custom properties:
| Property | Default | Description |
|---|---|---|
--tbw-tooltip-bg | light-dark(#333338, #484850) | Tooltip background color |
--tbw-tooltip-fg | light-dark(#f5f5f5, #f0f0f0) | Tooltip text color |
--tbw-tooltip-border | light-dark(#222226, #6a6a72) | Tooltip border and arrow color |
--tbw-tooltip-shadow | drop-shadow(0 4px 4px rgba(0,0,0,.45)) | Tooltip shadow (a filter value, so it follows the arrow) |
--tbw-tooltip-radius | var(--tbw-border-radius) | Border radius |
--tbw-tooltip-max-width | 300px | Maximum width before the text wraps |
--tbw-tooltip-arrow-size | 14px | Size of the arrow’s (pre-rotation) box |
--tbw-tooltip-arrow-offset | 16px | Horizontal offset of the arrow from the left edge |
Accessibility
Section titled “Accessibility”The plugin satisfies WCAG 2.2 SC 1.4.13 Content on Hover or Focus:
- Dismissible — Escape hides a visible tooltip from anywhere on the page, without moving the pointer. The key is not consumed, so it still cancels an in-progress cell edit.
- Hoverable — the tooltip stays up for
hideDelaymilliseconds after the pointer leaves the cell, and indefinitely while the pointer rests on the tooltip itself. Its text is selectable, so long content can be read with a screen magnifier or copied. - Persistent — the tooltip is never dismissed on a timer; it hides only when the pointer or keyboard focus moves away, or on Escape.
- Focus-triggered — arrowing onto a truncated cell shows its tooltip, so keyboard users can read content a mouse user would hover for. The anchor cell is linked to the popover via
aria-describedby, and the popover carriesrole="tooltip".
The focus path is driven by key presses, so it only ever runs for keyboard navigation — clicking a cell with a pointer never triggers it. Set focus: false to opt out entirely (this forfeits the SC 1.4.13 “focus” path).
See Also
Section titled “See Also”- Plugins Overview — all available plugins
- Context Menu — another popover-based plugin
- Responsive — card layout on narrow containers
tbw-grid { --tbw-tooltip-bg: #1e1e2e; --tbw-tooltip-fg: #cdd6f4; --tbw-tooltip-border: #45475a;}