A modern, lightweight React library for displaying and editing JSON data with an interactive tree interface. Perfect for debugging, data visualization, and JSON editing in React applications.
- π³ Interactive JSON tree view with expand/collapse functionality
- π Search and highlight with auto-expand matching nodes
- βοΈ Inline editing with validation and error handling
- π Copy operations for values and paths
- π¨ Customizable themes (light/dark) with CSS variables
- π± Responsive design with mobile support
- βΏ Accessibility support with keyboard navigation
- π§ Full TypeScript support with comprehensive type definitions
- π¦ Small bundle size (<10KB gzipped)
- β‘ Performance optimized with safety limits and memoization
npm install @rio2k2/json-viewer-react
yarn add @rio2k2/json-viewer-react
pnpm add @rio2k2/json-viewer-react
import React from 'react';
import { JSONViewer } from '@rio2k2/json-viewer-react';
import '@rio2k2/json-viewer-react/styles';
const data = {
name: "John Doe",
age: 30,
isActive: true,
hobbies: ["reading", "coding", "gaming"],
address: {
street: "123 Main St",
city: "New York",
zipCode: "10001"
}
};
function App() {
return (
<JSONViewer
data={data}
theme="light"
editable={true}
showTypes={true}
onChange={(path, oldValue, newValue) => {
console.log('Value changed:', { path, oldValue, newValue });
}}
/>
);
}
Prop | Type | Default | Description |
---|---|---|---|
data |
object | string |
required | JSON data to display |
rootName |
string |
"root" |
Name for the root node |
collapsed |
boolean | number |
false |
Initial collapse state or depth |
editable |
boolean |
false |
Enable inline editing |
search |
string |
undefined |
Controlled search value |
showTypes |
boolean |
true |
Show type badges |
theme |
'light' | 'dark' | string |
"light" |
Theme or custom class |
maxRenderDepth |
number |
6 |
Maximum render depth |
maxNodes |
number |
2000 |
Maximum nodes to render |
className |
string |
undefined |
Additional CSS class |
style |
React.CSSProperties |
undefined |
Inline styles |
Prop | Type | Description |
---|---|---|
onSelect |
(path: string, node: NodeMeta) => void |
Called when a node is selected |
onChange |
(path: string, oldVal: any, newVal: any) => void |
Called when a value is edited |
onError |
(error: Error) => void |
Called when an error occurs |
onSearchMatchCount |
(count: number) => void |
Called with search match count |
Prop | Type | Description |
---|---|---|
renderValue |
(value: any, path: string) => ReactNode |
Custom value renderer |
renderKey |
(key: string, path: string) => ReactNode |
Custom key renderer |
Use a ref to access imperative methods:
import React, { useRef } from 'react';
import { JSONViewer, JSONViewerHandle } from '@rio2k2/json-viewer-react';
function App() {
const viewerRef = useRef<JSONViewerHandle>(null);
const handleExpandAll = () => {
viewerRef.current?.expandAll();
};
const handleCollapseAll = () => {
viewerRef.current?.collapseAll();
};
const handleSearch = () => {
viewerRef.current?.search('John');
};
return (
<div>
<button onClick={handleExpandAll}>Expand All</button>
<button onClick={handleCollapseAll}>Collapse All</button>
<button onClick={handleSearch}>Search "John"</button>
<JSONViewer
ref={viewerRef}
data={data}
/>
</div>
);
}
Method | Description |
---|---|
expandAll() |
Expand all nodes |
collapseAll() |
Collapse all nodes |
search(query: string) |
Search for a query |
get(path: string) |
Get value at path |
set(path: string, value: any) |
Set value at path |
toJSON() |
Get current JSON data |
// Light theme (default)
<JSONViewer data={data} theme="light" />
// Dark theme
<JSONViewer data={data} theme="dark" />
// Custom theme class
<JSONViewer data={data} theme="my-custom-theme" />
Customize the appearance using CSS variables:
.jv-theme-custom {
--jv-bg-color: #f8f9fa;
--jv-text-color: #212529;
--jv-key-color: #0066cc;
--jv-string-color: #22863a;
--jv-number-color: #005cc5;
--jv-boolean-color: #d73a49;
--jv-null-color: #6f42c1;
--jv-border-color: #e1e4e8;
--jv-hover-bg: #f1f8ff;
--jv-focus-border: #0366d6;
}
function SearchableViewer() {
const [searchQuery, setSearchQuery] = useState('');
const [matchCount, setMatchCount] = useState(0);
return (
<div>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search JSON..."
/>
<span>Matches: {matchCount}</span>
<JSONViewer
data={data}
search={searchQuery}
onSearchMatchCount={setMatchCount}
/>
</div>
);
}
function CustomViewer() {
const renderValue = (value: any, path: string) => {
if (typeof value === 'string' && value.startsWith('http')) {
return <a href={value} target="_blank" rel="noopener noreferrer">{value}</a>;
}
return null; // Use default renderer
};
return (
<JSONViewer
data={data}
renderValue={renderValue}
/>
);
}
<JSONViewer
data={largeData}
maxRenderDepth={3}
maxNodes={1000}
collapsed={2}
onError={(error) => console.error('JSON Viewer Error:', error)}
/>
The library is written in TypeScript and provides comprehensive type definitions:
import {
JSONViewer,
JSONViewerHandle,
JSONViewerProps,
NodeMeta,
JSONPath
} from '@rio2k2/json-viewer-react';
interface MyData {
id: number;
name: string;
metadata: Record<string, any>;
}
const data: MyData = {
id: 1,
name: "Example",
metadata: { version: "1.0" }
};
const handleChange = (path: JSONPath, oldValue: any, newValue: any) => {
// Type-safe change handling
};
- Use
collapsed
prop for large datasets to avoid rendering all nodes initially - Set
maxRenderDepth
to limit deep nesting rendering - Set
maxNodes
to prevent browser freezing with huge datasets - Use
React.memo
when wrapping JSONViewer in your components - Debounce search input for better performance with large datasets
We welcome contributions! Please see our Contributing Guide for details.
MIT Β© locnv2k2
The config
prop accepts the following options:
editable
(boolean): Enable inline editing of valuesshowTypes
(boolean): Show type badges for valuestheme
('light' | 'dark'): Color thememaxRenderDepth
(number): Maximum depth to render (default: 6)maxNodes
(number): Maximum number of nodes to render (default: 2000)rootName
(string): Name for the root node (default: 'root')
onSelect
: Called when a node is selectedonChange
: Called when a value is editedonError
: Called when an error occurs
You can provide custom renderers for keys and values:
<JSONViewer
data={data}
renderKey={(key, path) => <strong>{key}</strong>}
renderValue={(value, path) => {
if (typeof value === 'string' && value.startsWith('http')) {
return <a href={value}>{value}</a>;
}
return null; // Use default renderer
}}
/>
# Install dependencies
npm install
# Start development server
npm run dev
# Build library
npm run build
# Run type checking
npm run check
MIT License - see LICENSE file for details.