Skip to content

3.1.0

Latest

Choose a tag to compare

@gfazioli gfazioli released this 12 Apr 12:00

Tip

This is a feature release with no breaking changes. All existing props and behavior remain fully backward compatible.


New Features

1. Redesigned toolbar

The header area has been redesigned into a proper toolbar with modern icons and additional controls. The expand/collapse icons have been replaced with IconArrowBarToDown / IconArrowBarToUp (previously IconLibraryPlus / IconLibraryMinus), and buttons now use variant="subtle" with consistent size="sm" for a cleaner appearance.

The toolbar groups all action buttons on the right side of the header, while the title and badge sit on the left. The header is now displayed whenever any toolbar prop is enabled — even without an explicit title.

2. Search with tree filtering

The new withSearch prop adds a search toggle button to the toolbar. When activated, a search bar appears between the header and the tree. Typing a query performs case-insensitive matching against both key names and formatted values.

How it works:

  • Tree filtering: non-matching branches are removed from the tree entirely (not just dimmed), keeping the view clean and focused
  • Text highlighting: matching portions of keys and values are highlighted with an amber background via the searchHighlight Styles API selector
  • Row highlighting: rows with direct matches get a subtle amber background (rgba(251, 191, 36, 0.15))
  • Auto-expand: ancestor nodes of matches are automatically expanded to reveal results
  • State preservation: the pre-search expanded state is saved and restored when the search is cleared or closed
  • Debounced input: search queries are debounced (default 300ms) to avoid excessive re-renders

New search-related props:

Prop Type Default Description
withSearch boolean false Show the search toggle button
searchIcon ReactNode <IconSearch /> Custom search toggle icon
searchPlaceholder string 'Filter keys and values...' Search input placeholder
searchQuery string Controlled search query
onSearchChange (query: string) => void Callback when search query changes
searchDebounce number 300 Debounce delay in milliseconds

New utility functions exported from lib/utils.tsx:

  • searchTree(nodes, query) — returns matchedPaths, directMatches, and expandedPaths
  • filterTreeBySearch(nodes, matchedPaths) — prunes the tree to keep only matched branches and their ancestors

3. Paper wrapper via withBorder

The new withBorder prop wraps the entire component in a Mantine <Paper withBorder> element, providing a clean bordered container out of the box. The border radius is configurable via borderRadius (default 'sm').

Prop Type Default Description
withBorder boolean false Wrap in Paper with border
borderRadius MantineRadius 'sm' Paper border radius

4. Custom root node label via rootName

The new rootName prop allows customizing the label displayed for the root node of the tree (default 'root'). This is useful when the JSON data represents a named entity such as "response", "config", or "user".

Prop Type Default Description
rootName string 'root' Label for the root node

5. Key count badge

The new withKeyCountBadge prop displays a badge next to the title showing the total number of top-level keys (for objects) or items (for arrays). The label is customizable via keyCountBadgeLabel.

Prop Type Default Description
withKeyCountBadge boolean false Show key/item count badge
keyCountBadgeLabel (count: number) => string Custom badge label formatter

6. Global copy-to-clipboard

The new withCopyAll prop adds a button to the toolbar that copies the entire JSON data (JSON.stringify(data, null, 2)) to the clipboard.

Prop Type Default Description
withCopyAll boolean false Show global copy button
copyAllIcon ReactNode <IconCopy /> Custom copy-all icon
onCopyAll (json: string) => void Callback when JSON is copied

7. Copy feedback (green check icon)

Both the global copy button and per-node copy buttons now show a brief green check icon (IconCheck) after a successful clipboard write. The feedback lasts 1.5 seconds before reverting to the original icon. This is implemented via the new CopyNodeButton internal component which manages its own copied state and cleanup timer.


New Styles API Selectors

8 new selectors have been added for styling the toolbar and search features:

Selector Description
paper Paper wrapper element (when withBorder is true)
toolbar Toolbar button group on the right side of the header
keyCountBadge Key count badge next to the title
copyAllButton Global copy JSON button in toolbar
searchToggle Search toggle button in toolbar
searchBar Search bar container between header and tree
searchInput Search text input
searchHighlight Highlighted matching text in search results

New CSS Variable

Variable Selector Default Description
--json-tree-search-highlight-color searchHighlight rgba(251, 191, 36, 0.4) Background color for search match highlights (slightly dimmer in dark mode)

Internal Changes

Nullish coalescing in tree data conversion

The convertToTreeData function in lib/utils.tsx now uses nullish coalescing (??) instead of logical OR (||) when falling back to the path value for node labels. This correctly handles cases where the key is an empty string or 0 (both falsy but valid keys).

Refactored expand/collapse handlers

The expand-all and collapse-all logic has been extracted from inline arrow functions into named handleExpandAll and handleCollapseAll callbacks wrapped in useCallback, improving readability and memoization.

New internal component: CopyNodeButton

Per-node copy buttons are now rendered by a CopyNodeButton component that encapsulates the copied/feedback state. The handleCopy function now returns Promise<boolean> to communicate success/failure to the button.

data-searching attribute

The root element receives a data-searching attribute when a search query is active, enabling CSS-based conditional styling.


Tests

16 new tests added (from 35 to 51 total):

Toolbar tests (11):

  • Paper wrapper rendering (present/absent)
  • Key count badge for objects and arrays
  • Custom keyCountBadgeLabel
  • No badge for primitive data
  • Copy-all button rendering
  • Search toggle rendering
  • Header visibility when any toolbar prop is set
  • Search bar opening on toggle click
  • All toolbar features combined
  • rootName custom label
  • rootName default value

Search utility tests (5):

  • searchTree finds matches by key name
  • searchTree finds matches by value
  • searchTree returns empty for empty query
  • filterTreeBySearch keeps only matching branches
  • searchTree is case insensitive

Documentation

  • Configurator demo updated with all new props (withBorder, withKeyCountBadge, withCopyAll, withSearch, rootName), with sensible defaults enabled
  • New demo: rootName — shows custom root labels for objects and arrays
  • New demo: search — shows full toolbar with search, expand-all, copy-all, and key count badge on a realistic API response payload
  • Styles API demo updated with all toolbar features and showLineNumbers enabled
  • Styles API definitions updated with all 8 new selectors and the --json-tree-search-highlight-color CSS variable
  • CLAUDE.md updated with toolbar and search architecture documentation

All New Props Summary

Prop Type Default
rootName string 'root'
withBorder boolean false
borderRadius MantineRadius 'sm'
withKeyCountBadge boolean false
keyCountBadgeLabel (count: number) => string
withCopyAll boolean false
copyAllIcon ReactNode <IconCopy />
onCopyAll (json: string) => void
withSearch boolean false
searchIcon ReactNode <IconSearch />
searchPlaceholder string 'Filter keys and values...'
searchQuery string
onSearchChange (query: string) => void
searchDebounce number 300

Commits

Hash Date Message
b64bf06 2026-04-11 feat: redesign toolbar with counter badge, copy all, search toggle, Paper wrapper
5d02bd5 2026-04-11 feat: add tests, storybook stories, and update demo configurator for toolbar upgrade
1e55bd2 2026-04-11 feat: implement search with highlight, auto-expand, and dimming (Phase 2)
f332b64 2026-04-11 fix: improve search highlight visibility and story defaults
472c843 2026-04-11 fix: use inline opacity for search dimming instead of CSS selectors
7f693a0 2026-04-12 feat: add rootName prop + switch search from dimming to filtering
4e27291 2026-04-12 feat: update docs, demos, README, CLAUDE.md for toolbar upgrade + search + rootName
63c2d3f 2026-04-12 fix: enable all toolbar features in Styles API demo
e358a97 2026-04-12 feat: add copy feedback (green check icon) for global and per-node copy
745c0a4 2026-04-12 fix: address Copilot review — nullish check, copy feedback robustness, search tests
430a5f9 2026-04-12 Release 3.1.0

What's Changed

  • Redesigned toolbar, search with filtering, Paper wrapper, rootName by @gfazioli in #19

Full Changelog: 3.0.0...3.1.0