@carissa-io/components-tree
v0.1.1
Published
Carissa UI: WAI-ARIA tree view with roving tabindex, typeahead and controlled or uncontrolled selection as React components with SCSS variables
Readme
@carissa-io/components-tree
Tree: Tree and TreeItem. The WAI-ARIA tree view: nested nodes, roving tabindex, full keyboard support and typeahead,
with controlled or uncontrolled selection and expansion. A React component set, SCSS-themed, with no other dependency.
npm i @carissa-io/components-treeUse
import { Tree, TreeItem } from '@carissa-io/components-tree'
<Tree label={t('files')} default_expanded={['docs']} on_select={(value) => open(value)}>
<TreeItem value="docs" label={t('documents')} icon={<FolderIcon />}>
<TreeItem value="cv" label="CV.pdf" />
<TreeItem value="notes" label={t('notes')} disabled />
</TreeItem>
<TreeItem value="readme" label="README.md" />
</Tree>| Part | Prop | |
|---|---|---|
| Tree | label | the accessible name (aria-label); aria-labelledby can be passed instead |
| | selected, on_select(value) | controlled selection (null means none); without selected the tree keeps its own state |
| | default_selected | the initial selection when uncontrolled |
| | expanded, on_expanded_change(values) | controlled list of open parents; without expanded the tree keeps its own state |
| | default_expanded | the initial open parents when uncontrolled (default []) |
| TreeItem | value | the item's string identity (used by selected and expanded) |
| | label | the text; it names the item and drives typeahead |
| | icon | a leading node, rendered aria-hidden |
| | disabled | aria-disabled: skipped by the keys, not selectable, not toggleable |
| | children | other TreeItems; makes it a parent |
className is appended on both parts; unknown props go to the ul on Tree and to the li on TreeItem. on_select
receives the value; on_expanded_change receives the full new array of open values. Children of a closed parent are not
rendered. Clicking a row selects it and toggles it when it is a parent.
Accessibility
Follows the WAI-ARIA authoring practices tree view: role="tree", treeitem, children in role="group", aria-expanded on
parents only, aria-selected on every item. One item is in the tab order (roving tabindex): the focused one, else the selected
one, else the first enabled one.
| Key | Action |
|---|---|
| Down / Up | next / previous visible item |
| Right | open a closed parent; on an open parent, go to its first child |
| Left | close an open parent; otherwise go to the parent |
| Home / End | first / last visible item |
| Enter / Space | select the item |
| * | open every closed sibling of the focused item |
| a character | jump to the next item whose label starts with the typed text (the buffer resets after 500 ms; repeating one letter cycles) |
Disabled items are skipped by every key. The chevron is CSS on the aria-hidden c-tree__toggle span (parents only; it turns down when open), coloured with
$c-tree-toggle-color. Give the tree a label.
Style
@use '@carissa-io/components-tree/scss' with (
$c-tree-indent: 1.5rem,
$c-tree-row-background-selected: #eef
);Classes: c-tree, c-tree__item (--parent, --open, --selected, --disabled), c-tree__row, c-tree__toggle,
c-tree__icon, c-tree__label and c-tree__group. Every variable is !default (see
scss/_variables.scss); the defaults are neutral, so the component works without a theme. Transitions
are disabled with prefers-reduced-motion.
| Variable | Default |
|---|---|
| $c-tree-font-size | 1rem |
| $c-tree-row-padding-x, $c-tree-row-padding-y | 0.5rem, 0.25rem |
| $c-tree-row-gap, $c-tree-row-radius, $c-tree-indent | 0.375rem, 0.25rem, 1.25rem |
| $c-tree-toggle-size, $c-tree-toggle-chevron-size, $c-tree-toggle-chevron-width, $c-tree-toggle-color | 1rem, 0.4375rem, 2px, currentColor |
| $c-tree-row-background-hover, $c-tree-row-background-selected | rgb(0 0 0 / 0.04), rgb(0 0 0 / 0.08) |
| $c-tree-row-color-selected, $c-tree-item-disabled-opacity | inherit, 0.5 |
| $c-tree-focus-outline, $c-tree-focus-outline-offset | 2px solid currentColor, -2px |
| $c-tree-transition-duration | 0.15s |
