βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β app/layout.tsx β
β (Root Layout + Metadata) β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β app/page.tsx β
β (Main Orchestrator) β
β β
β State: β
β β’ jsonInput (string) β
β β’ jsonError (string | null) β
β β’ rootNode (TreeNode | null) β
β β’ selectedNode (TreeNode | null) β
β β’ searchTerm (string) β
β β’ expandedPaths (Set<string>) β
β β
β Effects: β
β β’ Load JSON from URL on mount β
β β’ Parse JSON when input changes β
β β’ Auto-expand search results β
ββββββββ¬βββββββ¬βββββββ¬βββββββ¬βββββββ¬βββββββββββββββββββββββββββββββ
β β β β β
βΌ βΌ βΌ βΌ βΌ
βββββ βββββ βββββ βββββ ββββββββββ
β 1 β β 2 β β 3 β β 4 β β 5 β
βββββ βββββ βββββ βββββ ββββββββββ
app/page.tsx (Main App)
β
βββ Header
β βββ Title + Description
β βββ ShareButton (5)
β
βββ SearchBar (2) [conditional: if rootNode exists]
β
βββ Main Content Area (flex)
β β
β βββ Left Panel
β β βββ JsonInput (1)
β β βββ Textarea
β β βββ Upload Button
β β βββ Prettify Button
β β βββ Clear Button
β β βββ Error Display
β β
β βββ Right Panel
β βββ TreeViewer (3)
β βββ TreeNodeComponent (recursive)
β βββ Node Header
β β βββ Expand Icon
β β βββ Key
β β βββ Value
β βββ Children (recursive TreeNodeComponent)
β
βββ Bottom Panel [conditional: if selectedNode exists]
β βββ PathPreview (4)
β βββ Path Display + Copy Button
β βββ Value Preview
β βββ Copy Value Button
β βββ Type Indicator
β
βββ Footer
βββ Usage Hints
User types/pastes JSON
β
JsonInput onChange
β
app/page.tsx setJsonInput
β
useEffect (on jsonInput change)
β
validateJson()
β
JSON.parse()
β
jsonToTree()
β
setRootNode
β
TreeViewer re-renders
User clicks leaf value
β
TreeNodeComponent handleClick
β
copyToClipboard(node.path)
β
onNodeClick(node)
β
app/page.tsx setSelectedNode
β
PathPreview re-renders with new node
User clicks object/array
β
TreeNodeComponent handleClick
β
onToggleExpand(node.path)
β
app/page.tsx handleToggleExpand
β
Update expandedPaths Set
β
TreeNodeComponent re-renders
β
Children show/hide
User types in SearchBar
β
onSearchChange(term)
β
app/page.tsx setSearchTerm
β
useEffect (on searchTerm change)
β
searchTree(rootNode, term)
β
getParentPaths(each match)
β
Update expandedPaths
β
TreeViewer re-renders
β
Matched nodes visible and highlighted
User clicks Share button
β
ShareButton handleShare
β
createShareableUrl(jsonString)
β
encodeJsonToUrl
ββ pako.deflate (compress)
ββ btoa (base64 encode)
ββ URL-safe replacements
β
copyToClipboard(url)
β
Show success message
Purpose: Accept and validate JSON input
Props:
value: string- Current JSONonChange: (json: string) => void- Update callbackerror: string | null- Error message
Features:
- Textarea input
- File upload
- Drag & drop
- Prettify button
- Clear button
- Error display
No State: Fully controlled by parent
Purpose: Search for keys in JSON
Props:
searchTerm: string- Current searchonSearchChange: (term: string) => void- Update callbackmatchCount?: number- Number of matches
Features:
- Text input
- Clear button
- Match counter
No State: Fully controlled by parent
Purpose: Display JSON tree structure
TreeViewer Props:
rootNode: TreeNode | null- Tree rootonNodeClick: (node: TreeNode) => void- Click handlerselectedPath: string | null- Currently selected pathsearchTerm: string- For highlightingexpandedPaths: Set<string>- Expanded nodesonToggleExpand: (path: string) => void- Toggle handler
TreeNodeComponent Props:
node: TreeNode- Node to renderonToggleExpand: (path: string) => voidonNodeClick: (node: TreeNode) => voidisExpanded: boolean- Is this node expanded?isSelected: boolean- Is this node selected?searchTerm: string- For highlightingexpandedPaths: Set<string>- Pass to children
Features:
- Recursive rendering
- Expand/collapse icons
- Color-coded types
- Search highlighting
- Click to copy path (leaf)
- Click to expand (object/array)
- Drag to copy value
Local State:
showCopyHint: boolean- Temporary copy feedback
Purpose: Show path and value of selected node
Props:
selectedNode: TreeNode | null- Node to preview
Features:
- Path display with copy button
- Value preview (formatted JSON)
- Copy value button
- Type indicator
Local State:
copiedItem: 'path' | 'value' | null- Temporary copy feedback
Purpose: Generate shareable URL
Props:
jsonString: string- JSON to encodedisabled?: boolean- Disable if invalid
Features:
- Compress JSON with pako
- Encode to URL-safe base64
- Copy to clipboard
- Error handling for large JSON
Local State:
status: 'idle' | 'copied' | 'error'- Button state
Components
β
lib/jsonUtils.ts
β’ validateJson
β’ prettifyJson
β’ jsonToTree
β’ searchTree
β’ getParentPaths
β’ formatValueDisplay
β’ buildPath
β’ isLeafNode
β’ toJsonString
lib/urlUtils.ts
β’ encodeJsonToUrl
β’ decodeJsonFromUrl
β’ createShareableUrl
β’ getJsonFromUrl
lib/clipboardUtils.ts
β’ copyToClipboard
β’ showNotification
lib/types.ts
β’ TreeNode
β’ JsonValueType
β’ Component props interfaces
- Single source of truth: All state in
app/page.tsx - Predictable: Easy to understand data flow
- Debuggable: One place to check state
- No prop drilling: Components receive only what they need
-
jsonInput: Raw JSON string- Updated by: JsonInput onChange
- Used by: JSON parsing effect
-
jsonError: Validation error- Updated by: JSON parsing effect
- Used by: JsonInput (display), ShareButton (disable)
-
rootNode: Parsed tree structure- Updated by: JSON parsing effect
- Used by: TreeViewer, search effect
-
selectedNode: Current selection- Updated by: TreeNodeComponent click
- Used by: PathPreview
-
searchTerm: Search query- Updated by: SearchBar input
- Used by: Search effect, TreeNodeComponent (highlight)
-
expandedPaths: Set of expanded paths- Updated by: Toggle handler, search effect, auto-expand
- Used by: TreeNodeComponent (determine expanded state)
// app/page.tsx passes data down
<TreeViewer
rootNode={rootNode}
selectedPath={selectedNode?.path}
// ... other props
/>// TreeNodeComponent calls parent function
onNodeClick(node); // Updates selectedNode in parent
onToggleExpand(path); // Updates expandedPaths in parentSiblings communicate through shared parent state:
JsonInput β app/page.tsx (jsonInput) β TreeViewer
SearchBar β app/page.tsx (searchTerm) β TreeViewer
TreeViewer β app/page.tsx (selectedNode) β PathPreview
- React default reconciliation
- Re-render on state change
- Sufficient for small to medium JSON
-
useMemo for expensive computations:
const treeData = useMemo(() => jsonToTree(parsed), [parsed]);
-
useCallback for event handlers:
const handleClick = useCallback((node) => {...}, [deps]);
-
React.memo for components:
export default React.memo(TreeNodeComponent);
-
Virtual scrolling for large trees:
- Use
react-windoworreact-virtualized
- Use
All components are controlled (no internal state for data):
<JsonInput value={jsonInput} onChange={setJsonInput} />Parent passes handlers to control behavior:
<TreeViewer onNodeClick={handleNodeClick} />Show/hide based on state:
{rootNode && <SearchBar />}
{selectedNode && <PathPreview />}TreeNodeComponent renders itself for children:
{node.children?.map(child => (
<TreeNodeComponent node={child} />
))}Load/parse/search in useEffect:
useEffect(() => {
// Parse JSON when input changes
}, [jsonInput]);Refer to this diagram when understanding component relationships!