JavaScript Toolbar

@lemonadejs/toolbar · ✓ 10 contract checks · framework-agnostic · zero dependencies

<Toolbar /> — a flat action bar, ported faithfully from the v5 plugin.

Three positions (v5 data-position): the default is a fixed bottom app bar (mobile pattern), ‘static’ is an inline editor bar, ‘left’ is a vertical rail. Three item kinds:

  • regular items: <a> with optional image / material icon / title, route (href), selected and visible flags
  • dividers (v5 type ‘divisor’ — both spellings accepted)
  • ‘select’ pickers: a header that opens a dropdown right under itself, composed ON the Contextmenu block exactly like v5 (); options are Contextmenu items, plain strings normalize to { title }

v5 → v6 mapping: data/HTML-children extraction → options array; item.onclick (declared in the v5 data model but never wired in the dist template) now fires; the dead v5 onchange/onload params became real events — onchange fires when a picker option is chosen, onitemclick (not “onclick”: the name would collide with the native click event on web-component hosts) fires on any item activation. v5’s data-gap CSS hook (left rail spacer) gets its missing template plumbing via item.gap. One Contextmenu is shared by all pickers (v5 mounted one per picker), so hovering another picker moves the open dropdown instead of stacking menus.

Editor-host additions (the Editor block drives its bar through these):

  • item flags are LIVE: mutate selected / disabled / visible / title on the item objects, then api.refresh() — the bar patches the affected attributes in place (no rebuild, keyed by item identity). A caret move updating twelve toggle states costs twelve attribute writes, not a bar teardown.
  • item.tooltip: hover text for icon-only items (title renders as a visible label, so icon bars need a separate hover string)
  • type ‘color’: a swatch item that opens the Color block (grid + spectrum panel) in a small popover under the item. A pick lands on item.value (swatch underline), fires item.onchange(value, item) and the bar-level onchange(e, item, { value }), then closes. Outside mousedown and Escape dismiss.

Example

live
import { html } from 'lemonadejs';
import Toolbar from '@lemonadejs/toolbar';

const App = (props, { state }) => {
    const last = state('nothing yet');

    const items = [
        { icon: 'undo', tooltip: 'Undo', onclick: () => (last.value = 'undo') },
        { icon: 'redo', tooltip: 'Redo', onclick: () => (last.value = 'redo') },
        { type: 'divider' },
        { type: 'select', title: 'Verdana', options: ['Verdana', 'Arial', 'Georgia', 'Courier New'] },
        { type: 'divider' },
        { icon: 'format_bold', tooltip: 'Bold', selected: true, onclick: () => (last.value = 'bold') },
        { icon: 'format_italic', tooltip: 'Italic', onclick: () => (last.value = 'italic') },
        { icon: 'format_underlined', tooltip: 'Underline', disabled: true },
    ];

    return html`<div>
        <${Toolbar} position="static" options="${items}"
            onchange="${(e, item, option) => (last.value = 'font = ' + option.title)}" />
        <p>Last action: <b>${last}</b></p>
    </div>`;
};

Installation

npm install @lemonadejs/toolbar
import Toolbar from '@lemonadejs/toolbar';
import '@lemonadejs/toolbar/style.css';

The icons come from Google Material Symbols. Load the font once per page:

<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined">

Three deployment forms, one component:

html`<${Toolbar} />`                       // by value (no registration)
setComponents({ Toolbar });               // then <Toolbar /> by name anywhere
createWebComponent(Toolbar);              // <lm-toolbar> in plain HTML/any framework

Props

Every declared prop arrives as a live state — pass a value for a snapshot or a state for a two-way live wire. Attribute strings are coerced to the declared type.

PropTypeDefaultDescription
optionsarrayToolbarItem[]
positionstring''” = fixed bottom bar (v5 default)
visiblebooleantruefalse hides the whole bar

Events

All event names are lowercase (the platform convention — LJS-305 warns otherwise).

  • onitemclick — (e, item, index) on any item activation
  • onchange — (e, item, option) when a picker option is chosen, (e, item, { value }) on a color pick

API

import { ref } from 'lemonadejs';
const toolbar = ref();
html`<${Toolbar} ref="${toolbar}" />`;
// toolbar.current.open(...)  ·  toolbar.current.close(...)  ·  toolbar.current.refresh(...)
  • open()
  • close()
  • refresh()

Styling

All classes follow the lm-toolbar-* convention; visual variants are data-* attributes on the root. Override freely — there is no styling engine to fight.

Contract

The machine-readable schema ships with the package:

import contract from '@lemonadejs/toolbar/contract.json';

verify.json carries the conformance proof produced by verify(Toolbar).

Looking for the v5 plugin? See the archived v5 documentation.