<vn-grid-toolbar> — Usage Guide

1. Load the script (after the grid)

<script src="vanilla-grid/vanilla-grid.js"></script>
<script src="vanilla-grid-toolbar/vanilla-grid-toolbar.js"></script>

One <script> tag is all a host needs: vanilla-grid-toolbar.js auto-loads vanilla-grid-toolbar-events.js itself at runtime, exposing window.VanillaGridToolbarReady (optional to await — <vn-grid-toolbar> and its items are defined synchronously regardless). In production, load vanilla-grid-toolbar.bundle.js instead — the built single-file artifact with the auto-loader disabled. See Implementation § Loading & bundling.

<vn-grid id="ordersGrid" selection-mode="multiple" row-key-field="Id"></vn-grid>
<vn-grid-toolbar grid="ordersGrid"> … </vn-grid-toolbar>

Or programmatically: toolbar.setGrid('ordersGrid') / toolbar.grid = gridEl.

3. Author the two state templates

<vn-grid-toolbar grid="ordersGrid">
  <template data-vn-grid-toolbar="empty">
    <vn-grid-toolbar-status></vn-grid-toolbar-status>
    <vn-grid-toolbar-search placeholder="Search orders…" delay="300"></vn-grid-toolbar-search>
    <vn-grid-toolbar-button command="autoFitAllColumns" title-key="autoFitTitle">⤢</vn-grid-toolbar-button>
  </template>

  <template data-vn-grid-toolbar="selected">
    <vn-grid-toolbar-selection-count></vn-grid-toolbar-selection-count>
    <vn-grid-toolbar-export scope="selected"></vn-grid-toolbar-export>
    <vn-grid-toolbar-clear-selection></vn-grid-toolbar-clear-selection>
  </template>
</vn-grid-toolbar>

4. Built-in items

Element Drives Notes
<vn-grid-toolbar-status> counts / total / busy / selection localizable composite line, derived from grid state; uses the theme's grid body-row font (family + size).
<vn-grid-toolbar-status-message> toolbar.setStatusMessage(text, severity) host-driven free text; uses the grid body font + main text color for the theme; renders as plain grid text for info/success, only error tints the text (no background); survives template swaps.
<vn-grid-toolbar-spacer grow separator> — (presentational) inert layout spacer; grow absorbs free space (push left/right groups apart — it does not centre anything, see §4d); separator shows a theme-owned | divider (--vn-grid-toolbar-icon-separator); both optional and combinable.
<vn-grid-toolbar-group align="start|center|end"> — (presentational) layout wrapper that clusters related items so they move as one unit; a start/end pair genuinely centres a center group between them. See §4d.
<vn-grid-toolbar-info> toolbar.setInfoMessage(text) (or static text attr) non-clickable, button-shaped "i" indicator; reveals the text as a themed hover/focus tooltip; hides when empty; survives template swaps. Pass \n-separated lines to render a bulleted list (one concept per line) instead of one run-on line. Shares <vn-grid-toolbar-search>'s edge-aware placement, so an item near the row's right end opens its tooltip leftward instead of overhanging.
<vn-grid-toolbar-search delay="" placeholder="" expandable> gridElement.search(term) debounced. While a term is set, both variants show an accent border and an inline ✕ clear button; ✕ / Escape dispatch search('') immediately (no debounce). Boolean expandable switches to the Carbon-style expandable look: collapsed to a lens button, expanding into the row's free space on click; a non-empty term pins it open. Escape clears first, collapses second (expandable only). See §4b. When the attached DataManager restricts search to a subset of fields, hovering the item (while unfocused) reveals a tooltip listing them, hidden as soon as the item is focused / in use — no attribute, see §4c.
<vn-grid-toolbar-export scope="selected|all" variant="" disabled-when="" show-when="" hide-when=""> exportToExcel exports an .xlsx file of scope's rows. Auto-disabled until selection when scope="selected", and while the grid is busy (state.busy — filter/sort/search/reload in flight, or a load-more prefetch). Handles the export's promise: a cancelled export or a click during a running one is ignored, any other failure is logged (the grid's own overlay shows it to the user). Shares <vn-grid-toolbar-command>'s button styling + variant catalog (default secondary), so it matches its sibling command buttons across themes — set variant to match the neighbouring commands (e.g. ghost). disabled-when adds to the built-in disable rules rather than overriding them (can't re-enable an export with nothing to export, or one that's busy-gated); show-when/hide-when behave exactly like <vn-grid-toolbar-command>'s.
<vn-grid-toolbar-command command="" …> standard or custom command rich command button — localized label, themed icon (left/right), variant; see §6b.
<vn-grid-toolbar-button command="" title-key="" disabled-when=""> allow-list command minimal button; re-based on -command (ghost variant, slotted text).
<vn-grid-toolbar-selection-count hide-when-empty> selectedCount badge/text.
<vn-grid-toolbar-clear-selection variant=""> clearSelection shown only when there is a selection; shares <vn-grid-toolbar-command>'s variant catalog (default secondary), see §6b.

4a. Standard search — inline ✕ clear button

The default (always-visible) <vn-grid-toolbar-search> shows an inline ✕ clear button overlaid on the input's right edge whenever a term is set, and switches the input border to the accent color, so an active refinement is never invisible. Clicking ✕ (or pressing Escape with text present) clears the term and dispatches search('') immediately, bypassing the delay debounce; focus stays in the input. The ✕ is the item's own button (the native WebKit search-cancel glyph is suppressed), localizable via the searchClearLabel i18n key.

4b. Expandable search (<vn-grid-toolbar-search expandable>)

The boolean expandable attribute opts the search item into the IBM Carbon DataTable presentation, with three class-driven visual states:

Everything else is unchanged from the default variant: delay, placeholder, the search command routing, and the external-term re-sync. Localize the two button labels via the searchExpandLabel / searchClearLabel i18n keys. The expand/collapse duration is themable via --vn-grid-toolbar-search-expand-duration (default 0.15s; disabled under prefers-reduced-motion: reduce).

4c. Search-fields tooltip

Both search presentations automatically reveal a hover hint (shown on hover while the item is unfocused) when gridElement.getSearchFields() reports a restricted field list — e.g. a StaticDataManager constructed with searchFields: [...], or an ODataDataManager constructed with searchMode: 'filter', searchFields: [...]. No attribute: it's driven entirely by the attached DataManager and hidden whenever search is unrestricted (the default). Each field renders as its column's header label (matched against gridElement.grid.columns by key/field, or by a dotted path's first segment — e.g. Hometown.Name against a column keyed Hometown), falling back to the raw field string when no column matches; localize via the searchFieldsTooltip i18n key (default 'Searching: {fields}').

Two behaviors keep the tooltip out of the way:

const dm = new ODataDataManager({
    baseUrl: '/api/Orders',
    searchMode: 'filter',
    searchFields: ['ShipName', 'ShipCity', 'Customer.CompanyName']
});
gridElement.setDataManager(dm);
// No column is keyed "ShipName"/"ShipCity"/"Customer.CompanyName" in this
// example, so the raw field strings are shown as-is:
// "Searching: ShipName, ShipCity and Customer.CompanyName"
// A grid with a column { key: 'ShipCity', label: 'Ship City' } would show
// that column's header label instead of the raw "ShipCity" field.

4d. Layout: groups vs spacer grow

Two idioms push items apart in the toolbar row, and they are not interchangeable:

Groups and spacers compose freely; a group is just another flex item. Pick a spacer grow pair for the common "push these two blocks apart" layout, and a group triple whenever something in the row must actually stay centred.

5. Custom sub-components

Extend window.VanillaGridToolbarItem, implement contextChanged(), and use the helpers (this.state, this.gridElement, this.selectedKeys, this.send(command, arg), this.t(key, params)).

5b. Command buttons (<vn-grid-toolbar-command>)

A declarative button that dispatches a standard grid command (run directly) or a custom command (handled by your app), with a localized label, an optional theme-aware icon, and a visual variant. See Implementation § Commands.

<!-- standard command, runs the grid method directly -->
<vn-grid-toolbar-command command="exportToExcel" arg='{"scope":"all"}'
    label-key="exportAllLabel" icon="download" icon-position="right" variant="primary">
</vn-grid-toolbar-command>

<!-- custom command, handled by a host listener -->
<vn-grid-toolbar-command command="archiveSelected" label-key="archiveLabel"
    icon="clear" variant="danger" show-when="hasSelection">
</vn-grid-toolbar-command>

Every command click fires a cancelable vn-grid-toolbar-command event (it bubbles), whose detail carries { command, arg, grid, gridElement, toolbar, state, selectedKeys, selectedRows, source }. If the command is allow-listed/ registered it also runs as the default action, unless a listener calls preventDefault():

toolbar.addEventListener('vn-grid-toolbar-command', (e) => {
  if (e.detail.command === 'archiveSelected') {
    myApi.archive(e.detail.selectedKeys).then(() => e.detail.gridElement.reload());
  }
  // veto a standard command:
  if (e.detail.command === 'clearPersistedSettings' && !confirm('Reset?')) e.preventDefault();
});

Because it is a standard custom element + DOM event, it works from React / Angular / Vue (bind the event; pass object args via the .commandArg property). React ≤18 attaches the listener via a ref.

Icons are theme-owned --vn-grid-toolbar-icon-<name> CSS variables masked over currentColor (so they inherit the theme color and the selection-bar white-flip). Built-ins: download, refresh, reset, auto-fit, view, filter, clear, search, info, close, chevron-down, separator. (filter is descending bars — the shared glyph for a filtered list and a sort order — with a small corner ✕; it's the clearColumnFiltersAndSorting glyph, so it reads as remove both the filters and the sort. The Material theme overrides it with a Google filter_list_off-style variant: the descending bars struck through by a full diagonal slash, deliberately distinct from its grid-header filter_alt funnel — the header funnel applies a filter, this glyph removes them.) Extend with VanillaGridToolbarElement.registerIcon('star', '<svg…>'), or supply a one-off inline <svg data-vn-icon> child (multi-color glyphs).

Icon placement relative to the label is per-command via icon-position="left|right" (default left). The Carbon and Carbon Dark themes invert this for every command (icon trails the text) to match Carbon's button conventions — a theme-scoped rule in themes/vn-grid-toolbar-carbon[-dark].css, no markup change.

<vn-grid-toolbar-button> is the minimal alias (ghost variant, slotted text).

<vn-grid-toolbar-clear-selection> renders through the same button classes as <vn-grid-toolbar-command> and accepts the same variant attribute (default secondary, with accent-tinted text on the secondary/ghost variants), so it automatically follows every theme's radius/icon-order/formatting rules instead of drifting from its sibling command buttons.

6. Localization

toolbar.setMessages({ statusLoadedTotal: 'Mostrati {loaded}/{total}', searchPlaceholder: 'Cerca…' });
toolbar.locale = 'it';

The toolbar renders a few strings itself (e.g. the <vn-grid-toolbar-clear-selection> button label, key clearSelectionLabel). These come from the built-in English default bundle until you override them with setMessages — so a localized app should push translated values for them, otherwise the default (Clear) is shown. people-cities-js does this in localizeStaticUiTexts().

7. Theming

The toolbar mirrors the grid's theme automatically. Override with <vn-grid-toolbar theme="carbon-dark"> or a theme-css-path.

<vn-grid-toolbar-status> text color by selection state: the status line picks one of two theme tokens depending on whether the grid has a selection — --vn-grid-toolbar-info-color while nothing is selected (also used for the transient Loading… line) and --vn-grid-toolbar-success-color once a selection exists. Each theme tunes the pair: the light themes (default, fiori, fluent, material) show black with no selection and the theme's blue once selected; carbon shows black → white and carbon-dark white → white (the selection bar turns solid blue); glow and glow-dark keep their indigo no- selection color and switch to black / white respectively when selected.

<vn-grid-toolbar-clear-selection> ("Cancel") text color: on its low-emphasis secondary/ghost variants the button text uses --vn-grid-toolbar-clear-color, which defaults to the theme accent. The light themes (default, material, fiori, fluent) override it to black; carbon and carbon-dark pin it to white on their blue selection bar (set on the selected content so it resolves in the button's own context); glow-dark pins it to white; the remaining themes (glow) keep the accent tint.

Host icon buttons: prefer <vn-grid-toolbar-command> (§6b) — its masked icons already inherit --vn-grid-toolbar-btn-color (re-mapped to white in the Carbon selection bar) with no per-host CSS. If you must hand-roll a raw <button>, color its SVG with stroke="currentColor" and set color: var(--vn-grid-toolbar-btn-color) so it flips with the component-owned controls instead of staying dark.

Framework note: Vue, React, Angular (and other non-HTML-parser renderers)

The toolbar renders its states by cloning the .content DocumentFragment of its <template data-vn-grid-toolbar="…"> children. Framework-rendered children of a <template> element land in its childNodesnot in .content (only the HTML parser populates that) — so templates authored inside a Vue/JSX render tree clone as empty. Route the template markup through innerHTML instead (Vue: v-html with a static app-authored string; React/Angular: create the HTMLTemplateElement programmatically and assign innerHTML), which parses it as HTML and populates .content. See wikipedia-pages-vue/src/components/VnGridToolbar.vue for a complete Vue wrapper (attribute forwarding, vn-grid-toolbar-command event bridge, imperative API via defineExpose), github-repos-react/src/vanilla/VnGridToolbar.tsx for the React equivalent (a thin component exposing a ref handle), and northwind-orders-angular/src/app/vanilla/vn-grid-toolbar.directive.ts for the Angular equivalent (an element-selector directive).

Templates may also be appended after the element is already connected — frameworks like React and Angular attach the element to the document before host code can add children. The toolbar re-reads its state templates whenever the grid link is (re)established (grid attribute set/changed, setGrid()) and on every refresh(), so the reliable late order is: append the <template> children first, then set the grid attribute (or call refresh() if the grid was already linked).

Reference integration

See people-cities-js (People tab): the .status-container is a full-width <vn-grid-toolbar> with empty/selected templates containing a host-driven <vn-grid-toolbar-status-message> followed by a <vn-grid-toolbar-spacer grow> that pushes the trailing controls to the right edge, a plain (non-expandable) <vn-grid-toolbar-search delay="600"> in both templates, a <vn-grid-toolbar-export scope="selected"> (the built-in item — no host sub-component needed), <vn-grid-toolbar-command> buttons for the standard commands (reload, autoFitAllColumns, clearColumnFiltersAndSorting, clearPersistedSettings), a custom command="viewSelection" (gated via disabled-when="!hasSingleSelection", handled by the app through the vn-grid-toolbar-command event to open the detail panel), <vn-grid-toolbar-clear-selection>, and a <vn-grid-toolbar-info> whose tooltip carries the response conversion-strategy / size / compression details. The app feeds the status line and info tooltip through peopleToolbar.setStatusMessage() / setInfoMessage(), pushes the command titles/labels via setMessages(), and overrides the standard exportToExcel command via peopleToolbar.registerCommand('exportToExcel', …) so the app-specific file name/sheet name and device-aware headersOnly (touch devices) apply — the theme-matched styling itself is automatic (exportToExcel()'s themeStyle default), no bespoke sub-component needed (see exportGridSelection() in toolbar-helpers.js).

northwind-orders-js / -3 / -4 follow the same pattern (status-message + standard commands in the empty template; export + a custom viewSelection command + clear-selection in the selected template; exportToExcel overridden via registerCommand, viewSelection handled through the vn-grid-toolbar-command event; the host-driven status line appends the live selection count). northwind-orders-js additionally hosts a <vn-grid-toolbar-search expandable delay="600"> in both templates — the item re-syncs from the grid's search term after a template swap, so the entered text survives selection changes (and, being expandable, a non-empty term re-renders the fresh clone already expanded; a transient empty expansion is intentionally not preserved across swaps). wikipedia-pages-vue is the Vue integration (see the framework note above).