C&C Docs
Log in

cnc-toolbar

The strip of small icon buttons that sits above an editor, a preview or a canvas. You give it an array of items and it draws the row — buttons, vertical rules, and the gap that pushes the rest to the right edge. It owns none of the behaviour: every click leaves as one toolbaraction event carrying the id of the button that was pressed, and what happens next is yours.

Quick start

items is an array, so it is bound with $items rather than written as a plain attribute. Each button needs an id — that is what comes back on the event — and an icon. Everything else is optional.

Nothing pressed yet

<cnc-toolbar
  $items="[
    { id: 'refresh', icon: 'lucide/refresh-cw', title: 'Refresh' },
    { id: 'copy', icon: 'lucide/copy', title: 'Copy path' }
  ]"
  @toolbaraction="run($event.detail.id)"
></cnc-toolbar>

The bar draws its own bottom border and background, and is one fixed row tall. It is meant to sit flush against the thing it commands, not to be padded away from it.

The three items

An entry's type picks which of three things it is. Omitting type means button, which is why the common case reads as plain data.

type Renders
button
(or omitted)
An icon button. The only item that emits anything.
divider A short vertical rule. Purely visual grouping — it takes no id and is not clickable.
spacer An elastic gap that eats the leftover width, pushing everything after it to the right edge. Two spacers split the slack between them.

Button fields

Field Purpose
id What arrives as $event.detail.id, and the handle the imperative API takes. A button without one still renders and still emits — with id: undefined, which no handler can tell apart from any other. Give every button an id.
icon Any cnc-icon name, drawn small. There is no label: the icon is the whole button.
title The native tooltip, and — since the button has no text — the only thing naming it. Not optional in practice.
active Draws the button pressed: a filled background and a darker icon. The initial state only; moving it later is the imperative API's job.
activeIcon A second icon shown in place of icon while the button is active — a moon that becomes a sun. Both are rendered; only one is visible.
hidden Renders the button but keeps it out of the layout, for a tool that only applies to some documents. The button exists, so it can be revealed later without rebuilding the bar.

Things to know

  • The row is fixed after the first render. init() copies items into the private array the template loops over, and init() runs once. Adding, removing or relabelling an item later updates nothing, whether you bound it with $items or :items. Server-render the tools you need — including the ones that start hidden — and drive them with _toolbar.
  • The buttons are icons and nothing else. There is no label field and no text variant. title is the only name a button has, for a pointer and for a screen reader alike, so a button without one is unusable rather than merely undocumented.
  • Active is paint, not state. A pressed-in button carries no aria-pressed and reports nothing back — the widget does not track which of your buttons is on. What is active is whatever you last set, and keeping that in step with your own model is your side of the contract.
  • hidden hides, it does not remove. The button stays in the DOM and stays findable by getButton; only the layout skips it. That is what makes revealing it later a one-line call.
  • Nested toolbars bubble through their parent. A cnc-toolbar slotted inside another one emits from itself, but the event still bubbles up through the outer bar, so a handler there sees both. Check $event.target if you nest, or listen on the inner one directly.
  • The bar draws a bottom border, always. It is designed to be the top edge of a panel. Standing on its own, as on this page, that border reads as a stray rule; put it against the content it commands.

Usage guidance

Reach for cnc-toolbar when the actions are frequent, icon-sized and belong to one surface — an editor, a preview frame, a canvas. It is deliberately thin: no labels, no overflow menu, no keyboard roving, and no memory of what is on. If the actions need words, use cnc-button-group; if they are a menu of rarely-used commands, use cnc-context-menu, or a cnc-drop in the slot as cnc-markdown-tiptap does for its parameter list. Keep the row short enough to read at a glance — reach for wrap only when the tool count is genuinely the point.

← Back to Widgets