Skip to content

Early previewhamur is not on npm yet. The components are being built in the open, follow along on GitHub.

LayoutReact

Toolbar

A container for grouping a set of buttons and controls.

Rendered by React 19.3.1

import * as React from 'react'
import { Toolbar } from '@hamur/react/toolbar'

export default function ToolbarExample() {
  const [last, setLast] = React.useState('nothing yet')
  return (
    <div className="stack">
      <Toolbar.Root className="toolbar" aria-label="Formatting">
        <Toolbar.Group className="toolbar-group" aria-label="Text style">
          <Toolbar.Button
            className="toolbar-button"
            onClick={() => setLast('Bold')}
          >
            Bold
          </Toolbar.Button>
          <Toolbar.Button
            className="toolbar-button"
            onClick={() => setLast('Italic')}
          >
            Italic
          </Toolbar.Button>
        </Toolbar.Group>
        <Toolbar.Separator className="toolbar-separator" />
        <Toolbar.Button
          className="toolbar-button"
          disabled
          onClick={() => setLast('Strike')}
        >
          Strike
        </Toolbar.Button>
        <Toolbar.Separator className="toolbar-separator" />
        <Toolbar.Input
          className="input toolbar-input"
          aria-label="Font size"
          defaultValue="14"
        />
        <Toolbar.Link className="toolbar-link" href="#toolbar">
          Edited 51m ago
        </Toolbar.Link>
      </Toolbar.Root>
      <p className="muted">Last pressed: {last}</p>
    </div>
  )
}
284Tests passing in React · 0 failing
9.2 KiBSize
Not measured yetMemory
Not measured yetSpeed
productdevbook and 11 upstream authors8 commits · last

Installation

npm i @hamur/react

Not on npm yet. The package goes out under the chosen name.

Anatomy

Import the component and assemble its parts:

<Toolbar.Root>
  <Toolbar.Group>
    <Toolbar.Button />
  </Toolbar.Group>
  <Toolbar.Separator />
  <Toolbar.Input />
  <Toolbar.Link />
</Toolbar.Root>

Examples

The demo at the top is the one example this component has so far.

API reference

11 props across 6 parts, in React syntax. className, style, render are listed once, under Shared props.

ButtonToolbar.Button

A button that can be used as-is or as a trigger for other components. Renders a <button>.

Button props
PropTypeDefault
focusableWhenDisabledWhen true the item remains focusable when disabled.booleantrue
nativeButtonWhether the component renders a native <button> element when replacing itbooleantrue
disabledWhen true the item is disabled.booleanfalse
Button data attributes
Data attributeDescription
data-disabledPresent when the button is disabled.
data-orientationIndicates the orientation of the toolbar.
data-focusablePresent when the button remains focusable when disabled.

GroupToolbar.Group

Groups several toolbar items or toggles. Renders a <div>.

Group props
PropTypeDefault
disabledWhen true all toolbar items in the group are disabled.booleanfalse
Group data attributes
Data attributeDescription
data-disabledPresent when the group is disabled.
data-orientationIndicates the orientation of the toolbar.

InputToolbar.Input

A native input element that integrates with Toolbar keyboard navigation. Renders an <input>.

Input props
PropTypeDefault
defaultValuestring | number | readonly string[]—
focusableWhenDisabledWhen true the item remains focusable when disabled.booleantrue
disabledWhen true the item is disabled.booleanfalse
Input data attributes
Data attributeDescription
data-disabledPresent when the input is disabled.
data-orientationIndicates the orientation of the toolbar.
data-focusablePresent when the input remains focusable when disabled.

A link component. Renders an <a>.

Link data attributes
Data attributeDescription
data-orientationIndicates the orientation of the toolbar.

RootToolbar.Root

A container for grouping a set of controls, such as buttons, toggle groups, or menus. Renders a <div>.

Root props
PropTypeDefault
loopFocusIf true, using keyboard navigation will wrap focus to the other end of the toolbar once the end is reached.booleantrue
disabledboolean—
orientationThe orientation of the toolbar.Orientation'horizontal'
Root data attributes
Data attributeDescription
data-disabledPresent when the toolbar is disabled.
data-orientationIndicates the orientation of the toolbar.

SeparatorToolbar.Separator

A separator element accessible to screen readers. Renders a <div>.

Separator props
PropTypeDefault
orientationThe orientation of the separator.Orientation—
Separator data attributes
Data attributeDescription
data-orientationIndicates the orientation of the separator, which is perpendicular to the toolbar.

Shared props

Every part that renders an element takes these.

Shared props
PropType
classNameCSS class applied to the element, or a function that returns a class based on the component's state.string | ((state: State) => string | undefined)
styleStyle applied to the element, or a function that returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>

Keyboard and accessibility

Keyboard

Keyboard
KeysDoesPart
ArrowRightArrowLeftMoves focus to the next or previous item (ArrowDown and ArrowUp when vertical; reversed in right-to-left)Root
ArrowRightStops at the last item while loopFocus is offRoot
EnterActivates a Button, also when it renders an element other than <button>Button

Accessibility

What the parts set
PartSetsSo that
Rootrole="toolbar", aria-orientationa screen reader announces a toolbar and which arrow keys move in it
Grouprole="group"related items are read as a set; name it with aria-label
Separatorrole="separator", with the opposite orientation to Rootthe break between groups is announced
Buttonstays focusable while disabled, since focusableWhenDisabled is on by defaultarrow keys keep a steady path through the toolbar
InputfocusableWhenDisabled is on by default tooa disabled input keeps its place in the arrow-key order

Focus order

  1. The toolbar is one tab stop.
  2. Arrow keys move through Button, Link and Input items and through other components' triggers placed in it; with loopFocus they wrap at the ends.
  3. Use one Input at most, as the last item: in a horizontal toolbar, the left and right arrows also move the text cursor.