Skip to content

Migration v1 → v2

v2 is a ground-up modernization with a few deliberate breaking changes. For the vast majority of users, the migration is ≤ 5 lines of code.

  1. Raise your React peer to >=16.14.
  2. Remove the cacheSearch prop from any <TreeMenu> usage.
  3. Update your CSS import to the new subpath.

v1 claimed >=16.6.3. v2 requires >=16.14.

The floor is raised so the library can use React’s automatic JSX runtime internally. Almost no one is still on React 16.6–16.13 (that window closed Oct 2020), but if you are, upgrade first.

CI runs matrix tests against 16.14, 17, 18, and 19.

v1 exposed cacheSearch to opt into fast-memoize’s arg-identity caching for the tree walk. It was leaky — inline locale / matchSearch functions fooled the cache — and confusing.

v2 uses plain useMemo keyed on real dependencies. Correct by default. No user-facing knob.

<TreeMenu data={data} cacheSearch />
<TreeMenu data={data} />

If you explicitly set cacheSearch={false} to disable caching, you can also just drop the prop — there’s nothing to disable anymore.

v1: import 'react-simple-tree-menu/dist/main.css'; v2: import 'react-simple-tree-menu/styles';

import 'react-simple-tree-menu/dist/main.css';
import 'react-simple-tree-menu/styles';

The v1 deep-import path (dist/main.css) is not published in v2 — the swap is mandatory. Byte content is identical, so no visual or behavioral change in the rendered tree.

Semantics: built-in CSS is hand-written, not Sass

Section titled “Semantics: built-in CSS is hand-written, not Sass”

v1 compiled from src/sass/. v2 is a single hand-written src/styles.css. If you overrode Sass variables or imported intermediate partials, those paths no longer exist. Migrate to CSS custom properties.

v1 flattened every rendered row into one <ul> with inline paddingLeft. v2 emits a proper nested tree (<ul role="tree"><li role="treeitem"><ul role="group"><li> …), matching the WAI-ARIA tree pattern.

If you targeted children with :nth-child selectors that assumed a flat list, you’ll need to update them. Most users won’t notice.

Every item is now:

<li class="rstm-tree-item rstm-tree-item-levelN" role="treeitem" ...>
<div class="rstm-tree-item-row rstm-tree-item--active">
...
</div>
</li>

State classes (rstm-tree-item--active, rstm-tree-item--focused) live on the inner row <div>, not the <li>, so a hover/active background doesn’t bleed over nested children.

Selectors like .rstm-tree-item--active { background: red } still match — the class is still there, just on a different element. Compound selectors like li.rstm-tree-item--active will not match anymore. Use .rstm-tree-item--active alone.

v2 adds role="tree", role="treeitem", role="group", aria-level, aria-expanded, aria-selected, aria-setsize, aria-posinset, and a roving tabIndex. There’s no way to turn these off, and there’s no reason you’d want to — they’re the correct behavior for a tree.

v1 had four: classnames, fast-memoize, is-empty, tiny-debounce. v2 has zero. Your npm ls react-simple-tree-menu tree is smaller now.

These are additive — existing code keeps working.

  • classNames — append your own classes to the rstm-* anchors. Use this to go headless with Tailwind or CSS Modules. See Theming.
  • labels — customize the default UI’s i18n strings (search input placeholder + aria-label). See Keyboard & accessibility.

v2 feature-detects useDeferredValue and uses it to keep the search input responsive on very large trees. React 16/17 users get the same behavior as before (no transition). No API change either way.

Open an issue — happy to help.