npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ink-json-viewer

v0.4.0

Published

Interactive, collapsible JSON tree viewer component for Ink

Readme

ink-json-viewer

npm version CI license npm downloads

Interactive, collapsible JSON tree viewer component for Ink. Renders any JavaScript value as a navigable, syntax-colored tree in the terminal.

Features

  • Collapsible/expandable tree nodes with expand/collapse all
  • Syntax coloring for 16 value types
  • Full keyboard navigation (arrows, vim-style home/end, expand all, collapse all)
  • Virtual scrolling for large data sets (10K+ nodes)
  • Circular reference detection
  • Customizable color themes
  • TypeScript-first with full type exports
  • Headless hooks for custom UI

Install

npm install ink-json-viewer

Peer dependencies: ink >= 6.0.0 and react >= 19.0.0. Requires Node.js >= 20.

Quick Start

import {render} from 'ink';
import {JsonViewer} from 'ink-json-viewer';

const data = {
  name: 'ink-json-viewer',
  version: '0.3.0',
  features: ['collapsible', 'keyboard nav', 'syntax coloring'],
  config: {maxHeight: 20, theme: 'default'},
  active: true,
  tags: null,
};

render(<JsonViewer data={data} defaultExpandDepth={1} />);

Props API

| Prop | Type | Default | Description | |------|------|---------|-------------| | data | unknown | required | The value to render. Accepts any JS value: objects, arrays, primitives, Date, RegExp, Map, Set, BigInt, Symbol, functions, etc. | | defaultExpandDepth | number | 1 | Number of depth levels to expand on initial render. 0 = fully collapsed, Infinity = fully expanded. | | maxHeight | number | 20 | Maximum number of visible rows before virtual scrolling kicks in. | | showRootBraces | boolean | true | Whether to show the outermost brackets for the root value. When false, the root {}/[] rows are omitted and children render at depth 0 (unindented). | | sortKeys | boolean | false | Alphabetically sort object keys. | | enableKeyboard | boolean | true | Enable keyboard navigation and interaction. | | indentWidth | number | 2 | Number of spaces per indentation level. | | maxStringLength | number | 120 | Maximum display length for string values before truncation (includes quotes). | | onSelect | (path: string, value: unknown) => void | undefined | Called when Enter is pressed on a leaf node. Receives the node id and raw value. The id is a bespoke path (e.g. $.users[0].name), not spec JSONPath: each string key segment has ., [, ], and % percent-encoded, so a key like a.b arrives as $.a%2Eb. | | theme | Partial<JsonViewerTheme> | undefined | Partial theme overrides merged with the default theme. | | isActive | boolean | true | Whether the component is focused/active for keyboard input. Useful when embedding alongside other interactive components. | | rootLabel | string | undefined | Label to display for the root node (e.g., the variable name). |

Keyboard Shortcuts

| Key | Action | |-----|--------| | Down Arrow | Move focus to the next node | | Up Arrow | Move focus to the previous node | | Right Arrow | Expand focused node, or move to first child if already expanded | | Left Arrow | Collapse focused node, or move to parent if already collapsed | | Enter | Toggle expand/collapse on containers; triggers onSelect on leaf nodes | | Space | Toggle expand/collapse on containers | | g | Jump to the first node | | G | Jump to the last node | | * or e | Expand all nodes | | - or E | Collapse all nodes |

Note: Search is planned for a future release.

Syntax Coloring

Each value type renders in a distinct color by default:

| Type | Color | |------|-------| | string | green | | number | yellow | | boolean | magenta | | null | red (dim) | | undefined | red (dim) | | date | green | | regexp | green | | bigint | yellow | | symbol | green (dim) | | function | red (dim, italic) | | circular | red (bold) | | object | gray (preview) | | array | gray (preview) | | map | gray (preview) | | set | gray (preview) | | keys | white | | brackets | gray | | focus indicator | blue |

Supported Value Types

The viewer detects and renders 16 value types:

| Type | Rendered As | |------|------------| | string | "hello" (with escaping for \n, \t, \\, \") | | number | 42, 3.14, -1 | | boolean | true, false | | null | null | | undefined | undefined | | date | ISO string, e.g. 2024-01-15T00:00:00.000Z. Invalid dates render as Invalid Date. | | regexp | /pattern/flags | | bigint | 42n | | symbol | Symbol(description) | | function | [Function: name] | | object | Expandable tree with {N keys} collapsed preview | | array | Expandable tree with [N items] collapsed preview | | map | Expandable tree with Map(N) preview | | set | Expandable tree with Set(N) preview | | circular | [Circular] (bold red) | | unknown | [Max depth exceeded] when nesting exceeds 100 levels |

Virtual Scrolling

When the visible row count exceeds maxHeight, the viewer enables virtual scrolling. Only maxHeight rows are rendered at a time. Scroll indicators appear at the top and bottom to show how many rows are hidden:

  ^ 3 more
  ...visible rows...
  v 12 more

The scroll window automatically follows the focused row as you navigate.

Theme Customization

Override any color by passing a partial theme prop:

<JsonViewer
  data={myData}
  theme={{
    colors: {
      string: 'cyan',
      number: 'blueBright',
      focusIndicator: 'greenBright',
    },
  }}
/>

All color values are Ink/Chalk color names (e.g., 'red', 'greenBright', 'gray').

Available theme keys: string, number, boolean, null, key, bracket, expandIcon, focusIndicator, circular, preview.

Large Data

The component keeps rendering cheap even for large data sets:

  • Eager flatten, then windowed render: flattenTree walks the entire input once up front, so the initial flatten is O(total nodes). After that, only the visible window is rendered.
  • Virtual scrolling: Only maxHeight rows are rendered at any time, keeping the rendered output size constant regardless of data size.
  • Collapsed subtrees skipped on render: Children of collapsed containers are skipped at the visible-row computation stage, so a collapsed tree stays cheap to display even though every node was flattened.
  • Immutable state updates: The reducer produces new state objects without mutating previous state.

The whole input is flattened up front, so extremely large inputs still pay an O(total nodes) cost per data change. For data with 10,000+ nodes, set defaultExpandDepth to 0 or 1 and rely on maxHeight (default 20) to keep the render fast. Users can expand sections on demand.

Headless Usage

For custom UI, import the hooks and utilities directly:

import {
  useJsonViewerState,
  useJsonViewer,
  flattenTree,
  buildNodeIndex,
  detectType,
  formatValue,
  formatKey,
  truncate,
  defaultTheme,
  mergeTheme,
} from 'ink-json-viewer';

import type {JsonViewerState} from 'ink-json-viewer';
  • useJsonViewerState(props) is the headless state hook: it returns the full JsonViewerState (visible rows, focus, expand state, and navigation methods like focusNext() / expandAll()) for rendering your own rows
  • useJsonViewer({state, isActive, onSelect}) wires the default keyboard bindings (arrows, g/G, expand/collapse, select) onto a JsonViewerState
  • flattenTree(data, options?) converts any value into a flat JsonNode[] array
  • buildNodeIndex(nodes) creates a Map<string, JsonNode> for O(1) lookups
  • detectType(value) returns the JsonValueType for any value
  • formatValue(value, type, maxStringLength) formats a value for display
  • formatKey(key) formats a property key (quoting if needed)
  • truncate(string, maxLength) truncates with ellipsis
  • defaultTheme / mergeTheme(base, overrides) for theme management
  • JsonViewerState is the full state object returned by the internal useJsonViewerState hook, including navigation methods like focusNext(), expandAll(), etc.

TypeScript

All types are exported for use in your own components:

import type {
  JsonValueType,     // Union of all 16 type strings
  JsonNode,          // A node in the flattened tree
  VisibleRow,        // A row in the visible output
  JsonViewerTheme,   // Color theme shape
  JsonViewerProps,   // Component props
  JsonViewerState,   // Full viewer state with navigation methods
  ExpandState,       // ReadonlyMap<string, boolean> of expanded nodes
  TreeState,         // Internal reducer state
} from 'ink-json-viewer';

Contributing

Contributions are welcome. Please open an issue first to discuss what you'd like to change.

  1. Fork the repository
  2. Create a feature branch (git checkout -b my-feature)
  3. Make your changes and add tests
  4. Run npm test and npx tsc --noEmit to verify
  5. Commit and open a pull request

Changelog

See GitHub Releases.

License

MIT