# @humanspeak/svelte-json-view-lite — full reference > Concatenated dump of every doc page under https://jsonview.svelte.page/docs. > Each section is bounded by an HTML comment with the source URL, > so agents can extract individual pages or cite a specific section. --- # Accessibility > WAI-ARIA treeview semantics, keyboard navigation, and SSR-safe IDs in @humanspeak/svelte-json-view-lite. **Source:** [https://jsonview.svelte.page/docs/accessibility](https://jsonview.svelte.page/docs/accessibility) --- `` implements the [WAI-ARIA Treeview pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/) out of the box. The root renders as `role="tree"`, branches as `role="treeitem"`, and expand toggles as `role="button"` with matching `aria-expanded` and `aria-controls` wiring. ## DOM Shape Simplified output for `{ user: { id: 1 } }`: ```html
``` Every `aria-controls` is produced by Svelte 5's `$props.id()` — the same ID is emitted server-side and client-side, so hydration never breaks the assistive-tech contract. ## Keyboard Contract When focus is on any expander button inside the tree: | Key | Action | |-----|--------| | `Enter` / `Space` | Toggle the focused branch | | `ArrowRight` | Expand the branch, or move focus to the first child if already expanded | | `ArrowLeft` | Collapse the branch, or move focus to the parent if already collapsed | | `ArrowDown` | Move focus to the next visible branch | | `ArrowUp` | Move focus to the previous visible branch | | `Home` | Move focus to the first branch in the tree | | `End` | Move focus to the last visible branch | | `Tab` / `Shift+Tab` | Move focus out of the tree (roving tabindex) | The tree uses a **roving tabindex** — exactly one expander has `tabindex="0"` at a time, while the rest are `tabindex="-1"`. Clicking or focusing any expander updates the roving target, so tabbing into the tree always lands on the last-interacted branch. ## Screen Reader Labels Each expander announces its state via `aria-label`. The default strings are: ```ts { collapseJson: 'collapse JSON', expandJson: 'expand JSON' } ``` Override for localization or terser wording by setting `ariaLabels` on your style map: ```svelte ``` > **Note on `ariaLables` (sic).** `react-json-view-lite`'s original `StyleProps` shipped the typoed key. The Svelte port accepts either at runtime for parity but logs a `console.warn` when only the typoed key is present. Prefer `ariaLabels`; the alias is removed in 2.0. ## Click-to-Expand Considerations When `clickToExpandNode` is enabled, labels become click targets but **do not** receive focus or a button role — the expander glyph remains the single keyboard-accessible activator. Keyboard users never see duplicated tab stops; mouse users get a larger hit target. ## SSR and Hydration The tree is safe to render during SSR. Every `aria-controls` / `id` pair is produced by `$props.id()`, which is deterministic across server and client. No `Math.random()` or `Date.now()` — the IDs committed in the initial HTML match the ones rehydrated on the client. ## Testing with `@testing-library/svelte` The tree's ARIA contract means queries work without implementation-specific selectors: ```ts import { render, screen, fireEvent } from '@testing-library/svelte' import { JsonView } from '@humanspeak/svelte-json-view-lite' test('expands a branch on Enter', async () => { render(JsonView, { data: { nested: { inner: 1 } } }) const expander = screen.getByRole('button', { name: /expand/i }) await fireEvent.keyDown(expander, { key: 'Enter' }) expect(expander).toHaveAttribute('aria-expanded', 'true') }) ``` ## Known Limitations - **Custom snippets.** Renderers you supply via snippet overrides are rendered inside the `
  • ` cell; if you embed interactive elements (links, buttons) they add their own tab stops outside the roving tabindex. Keep snippet content non-interactive when possible or scope focus management yourself. - **Text direction.** The arrow-key contract assumes LTR ("right opens, left closes"). RTL-aware swapping is not implemented. - **Virtualization.** The tree is fully materialized — focus order matches DOM order. If you wrap the viewer in a virtualized list, the keyboard contract may not survive. ## Related - [JsonView props](/docs/api/json-view) — `clickToExpandNode` and the interactive prop set - [Types & snippets](/docs/api/types) — `AriaLabels` and the style shape # JsonView Props > Complete prop reference for the JsonView component in @humanspeak/svelte-json-view-lite. **Source:** [https://jsonview.svelte.page/docs/api/json-view](https://jsonview.svelte.page/docs/api/json-view) --- `` accepts the full `Props` interface plus anything you'd normally pass to a `
    `. Spread attributes (`class`, `id`, `data-*`, `aria-*`) land on the root container. ```svelte ``` ## Prop Reference | Prop | Type | Default | Description | |------|------|---------|-------------| | `data` | `object \| unknown[]` | — | **Required.** Object or array payload. Nested values can include strings, numbers, booleans, `Date`, `bigint`, functions, `null`, and `undefined`. | | `style` | `Partial` | `defaultStyles` | Classname map. Import `defaultStyles` or `darkStyles`, or pass a partial to override individual keys. | | `shouldExpandNode` | `(level: number, value: unknown, field?: string) => boolean` | `allExpanded` | Predicate called for every expandable node. Return `true` to expand. Use the exported `allExpanded` / `collapseAllNested` helpers for the common cases. | | `clickToExpandNode` | `boolean` | `false` | When `true`, clicking the field label (key) also toggles expand/collapse, not just the arrow. | | `beforeExpandChange` | `(event: NodeExpandingEvent) => boolean` | — | Veto handler. Receives `{ level, value, field, newExpandValue }`. Return `false` to cancel the transition. | | `compactTopLevel` | `boolean` | `false` | Render top-level primitives inline without the enclosing `{…}` wrapper. Useful when `data` is an array of mixed primitives. | | `string` | `Snippet<[StringSnippetProps]>` | Default renderer | Override the renderer for string values. See [Snippet overrides](/docs/snippet-overrides). | | `number` | `Snippet<[NumberSnippetProps]>` | Default renderer | Override the renderer for numbers. | | `boolean` | `Snippet<[BooleanSnippetProps]>` | Default renderer | Override the renderer for booleans. | | `null` | `Snippet<[NullSnippetProps]>` | Default renderer | Override the renderer for `null` values. | | `undefined` | `Snippet<[UndefinedSnippetProps]>` | Default renderer | Override the renderer for `undefined` values. | | `bigint` | `Snippet<[BigIntSnippetProps]>` | Default renderer | Override the renderer for `bigint` values. | | `date` | `Snippet<[DateSnippetProps]>` | Default renderer | Override the renderer for `Date` instances. | | `function` | `Snippet<[FunctionSnippetProps]>` | Default renderer | Override the renderer for function values. | | `label` | `Snippet<[LabelSnippetProps]>` | Default renderer | Override the renderer for field labels (keys). | ## `data` The root `data` prop is an object or array. Inside that tree, the viewer handles JSON values plus a few richer JavaScript leaves: - **Plain objects and arrays** render as collapsible branches. - **`Date`** renders with `toISOString()` by default; override with the `date` snippet. - **`bigint`** renders as its decimal representation with the `n` suffix preserved in source. - **`null` and `undefined`** render as red sentinels (color driven by `--sjv-null` / `--sjv-undefined`). - **Functions** render as `function() { }` by default; override with the `function` snippet. ```svelte ``` ## `shouldExpandNode` The predicate runs once per expandable node on initial render. Subsequent toggling is user-driven. ```svelte ``` Two exports cover the common cases: ```ts import { allExpanded, collapseAllNested } from '@humanspeak/svelte-json-view-lite' ``` - `allExpanded` — `() => true` - `collapseAllNested` — `(level) => level === 0` (root only) ## `clickToExpandNode` When `true`, the field label (key text) becomes a click target alongside the arrow. The style map's `clickableLabel` class is applied to affected labels. ```svelte ``` ## `beforeExpandChange` Called synchronously before an expansion state change. Return `false` to cancel. ```svelte ``` ## `compactTopLevel` Useful for arrays of primitives where the wrapping `[…]` adds noise: ```svelte ``` Renders each element inline instead of nested under an array bracket. ## Snippet Props All nine snippet props receive the same shape with a typed `value`. See [Snippet overrides](/docs/snippet-overrides) for the full recipe book. ```svelte {#snippet string({ value })} {value} {/snippet} ``` ## Spread Attributes Everything in `HTMLAttributes` except `data` and `style` forwards to the root container: ```svelte ``` ## Related - [Types & snippets](/docs/api/types) — `StyleProps`, `SnippetOverrides`, event payloads in full - [Themes & CSS variables](/docs/themes) — `--sjv-*` tokens - [Accessibility](/docs/accessibility) — keyboard + ARIA contract # Types & Snippet Props > Exported TypeScript types, style shape, and snippet prop interfaces for @humanspeak/svelte-json-view-lite. **Source:** [https://jsonview.svelte.page/docs/api/types](https://jsonview.svelte.page/docs/api/types) --- Every public type is exported from the package root. Import types with `import type`: ```ts import type { Props, StyleProps, AriaLabels, SnippetOverrides, NodeExpandingEvent, StringSnippetProps, NumberSnippetProps, BooleanSnippetProps, NullSnippetProps, UndefinedSnippetProps, BigIntSnippetProps, DateSnippetProps, FunctionSnippetProps, LabelSnippetProps } from '@humanspeak/svelte-json-view-lite' ``` ## `Props` Accepted by ``. See [JsonView props](/docs/api/json-view) for narrative documentation. ```ts export interface Props extends Omit, 'data' | 'style'> { data: object | unknown[] style?: Partial shouldExpandNode?: (level: number, value: unknown, field?: string) => boolean clickToExpandNode?: boolean beforeExpandChange?: (event: NodeExpandingEvent) => boolean compactTopLevel?: boolean string?: Snippet<[StringSnippetProps]> number?: Snippet<[NumberSnippetProps]> boolean?: Snippet<[BooleanSnippetProps]> null?: Snippet<[NullSnippetProps]> undefined?: Snippet<[UndefinedSnippetProps]> bigint?: Snippet<[BigIntSnippetProps]> date?: Snippet<[DateSnippetProps]> function?: Snippet<[FunctionSnippetProps]> label?: Snippet<[LabelSnippetProps]> } ``` ## `StyleProps` Classname map consumed by the viewer. `defaultStyles` and `darkStyles` are ready-made instances. ```ts export interface StyleProps { container: string basicChildStyle: string label: string clickableLabel: string nullValue: string undefinedValue: string numberValue: string stringValue: string booleanValue: string otherValue: string punctuation: string expandIcon: string collapseIcon: string collapsedContent: string childFieldsContainer: string noQuotesForStringValues?: boolean quotesForFieldNames?: boolean ariaLabels: AriaLabels /** @deprecated Use `ariaLabels`. Removed in 2.0. */ ariaLables?: AriaLabels stringifyStringValues: boolean } ``` ### Key roles | Key | Applies to | |-----|------------| | `container` | Outermost `
    ` around the tree | | `basicChildStyle` | Wrapper around each leaf or expandable child | | `label` | Field label (key) text | | `clickableLabel` | Label variant when `clickToExpandNode` is on | | `nullValue` / `undefinedValue` | `null` / `undefined` leaves | | `numberValue` / `stringValue` / `booleanValue` | Matching primitive leaves | | `otherValue` | `bigint`, `Date`, functions, and anything else | | `punctuation` | Braces, brackets, colons, commas | | `expandIcon` / `collapseIcon` | Arrow glyphs | | `collapsedContent` | Summary shown for collapsed branches (`{…}` / `[…]`) | | `childFieldsContainer` | `
      ` wrapping child fields | ### Boolean options - `noQuotesForStringValues` — omit `"` around string leaves. - `quotesForFieldNames` — wrap labels in `"`. - `stringifyStringValues` — call `JSON.stringify` on strings so newlines and control characters appear as escape sequences. ## `AriaLabels` Screen-reader labels applied to expander buttons. ```ts export interface AriaLabels { collapseJson: string expandJson: string } ``` Default (exported as `defaultAriaLabels`): ```ts { collapseJson: 'collapse JSON', expandJson: 'expand JSON' } ``` > **Note on `ariaLables` (sic).** The React source shipped this typo on the style shape. The Svelte port accepts either key at runtime and emits a `console.warn` if only the typoed key is set. Use `ariaLabels`; the typoed alias is scheduled for removal in 2.0. ## `SnippetOverrides` Bag of optional per-type snippets. Every key matches a same-named prop on ``. ```ts export interface SnippetOverrides { string?: Snippet<[StringSnippetProps]> number?: Snippet<[NumberSnippetProps]> boolean?: Snippet<[BooleanSnippetProps]> null?: Snippet<[NullSnippetProps]> undefined?: Snippet<[UndefinedSnippetProps]> bigint?: Snippet<[BigIntSnippetProps]> date?: Snippet<[DateSnippetProps]> function?: Snippet<[FunctionSnippetProps]> label?: Snippet<[LabelSnippetProps]> } ``` ## Snippet Prop Types All value snippets share a single generic shape parameterized by the value's type: ```ts export interface ValueSnippetProps { value: T field?: string level: number } ``` | Type alias | `value` type | |------------|--------------| | `StringSnippetProps` | `string` | | `NumberSnippetProps` | `number` | | `BooleanSnippetProps` | `boolean` | | `NullSnippetProps` | `null` | | `UndefinedSnippetProps` | `undefined` | | `BigIntSnippetProps` | `bigint` | | `DateSnippetProps` | `Date` | | `FunctionSnippetProps` | `Function` | `field` is the parent key (undefined at root and inside arrays). `level` is the depth (root = 0). The `label` snippet gets a slightly different shape (no `value`): ```ts export interface LabelSnippetProps { field: string level: number } ``` ## `NodeExpandingEvent` Payload passed to `beforeExpandChange`. Return `false` to veto. ```ts export interface NodeExpandingEvent { level: number value: unknown field?: string newExpandValue: boolean } ``` ## Related - [JsonView props](/docs/api/json-view) — narrative prop docs - [Snippet overrides](/docs/snippet-overrides) — worked examples for each snippet - [Themes & CSS variables](/docs/themes) — how `StyleProps` maps to real CSS # Getting Started > Install and render your first JSON tree with @humanspeak/svelte-json-view-lite in under a minute. **Source:** [https://jsonview.svelte.page/docs/getting-started](https://jsonview.svelte.page/docs/getting-started) --- **@humanspeak/svelte-json-view-lite** is a Svelte 5 port of [react-json-view-lite](https://github.com/AnyRoad/react-json-view-lite). It renders any JSON-serializable value as a collapsible tree with keyboard navigation, SSR-stable IDs, CSS-variable theming, and typed per-type `Snippet` overrides — all with zero runtime dependencies. ## Installation ```bash npm install @humanspeak/svelte-json-view-lite ``` ```bash pnpm add @humanspeak/svelte-json-view-lite ``` ```bash yarn add @humanspeak/svelte-json-view-lite ``` The package ships types, so TypeScript consumers need no additional `@types/*`. ## Quick Start Import the component and pass any value as `data`: ```svelte ``` That's the whole API for the default case. The tree renders light-theme by default and respects `prefers-color-scheme` only through explicit theme swapping (see below). ## Dark Theme Every public style token ships in two flavors. Swap them with a single prop: ```svelte ``` For a mode-aware site, bind the prop to your mode store: ```svelte ``` Prefer theming with CSS variables? Every color is exposed as a `--sjv-*` custom property — see [Themes & CSS variables](/docs/themes). ## Expansion Strategies By default every node is collapsed except the root. Pass a `shouldExpandNode` predicate to change that: ```svelte level < 2} /> ``` ## Next Steps - [JsonView props](/docs/api/json-view) — every prop with defaults and types - [Types & snippets](/docs/api/types) — `StyleProps`, `SnippetOverrides`, event payloads - [Themes & CSS variables](/docs/themes) — the full `--sjv-*` token table - [Snippet overrides](/docs/snippet-overrides) — replace any primitive's renderer - [Accessibility](/docs/accessibility) — WAI-ARIA treeview + keyboard contract # Migration > Port react-json-view-lite usage to Svelte JSON View Lite with matching prop names and Svelte snippets. **Source:** [https://jsonview.svelte.page/docs/migration](https://jsonview.svelte.page/docs/migration) --- Svelte JSON View Lite intentionally follows `react-json-view-lite` closely. Most migrations are a component import change plus replacing React render functions with Svelte snippets when you need custom values. ## Install ```bash npm i @humanspeak/svelte-json-view-lite ``` ## Basic Component ```svelte ``` ## Prop Mapping | React JSON View Lite | Svelte JSON View Lite | Notes | | --- | --- | --- | | `data` | `data` | Object or array JSON root. | | `style` | `style` | Use `defaultStyles`, `darkStyles`, or a merged style map. | | `shouldExpandNode` | `shouldExpandNode` | Same purpose: decide initial expansion by level and value. | | `clickToExpandNode` | `clickToExpandNode` | Same interaction model. | | `compactTopLevel` | `compactTopLevel` | Same root rendering option. | | custom renderers | snippet props | Svelte snippets replace React render callbacks. | ## Snippet Override ```svelte {#snippet stringValue({ value }: { value: string })} {#if value.startsWith('https://')} {value} {:else} {value} {/if} {/snippet} ``` ## Deliberate Difference The original React package includes a typoed `ariaLables` style key. Svelte JSON View Lite uses `ariaLabels`, while still honoring the typoed key at runtime with a warning for compatibility. # Snippet Overrides > Replace the default renderer for any primitive, Date, bigint, function, or field label using Svelte 5 snippets. **Source:** [https://jsonview.svelte.page/docs/snippet-overrides](https://jsonview.svelte.page/docs/snippet-overrides) --- Snippet overrides are the one deliberate extension the Svelte port adds on top of `react-json-view-lite`'s API. Pass a `Snippet` as any of the nine type-keyed props and the viewer calls it instead of the built-in renderer for every matching value. ```svelte {#snippet string({ value })} {value} {/snippet} ``` ## Snippet Props Every value snippet receives the same shape — just with a differently typed `value`: ```ts interface ValueSnippetProps { value: T field?: string // parent key, or undefined at the root / inside arrays level: number // depth (root = 0) } ``` | Snippet | Fires for | `value` type | |---------|-----------|--------------| | `string` | String leaves | `string` | | `number` | Number leaves | `number` | | `boolean` | Boolean leaves | `boolean` | | `null` | `null` leaves | `null` | | `undefined` | `undefined` leaves | `undefined` | | `bigint` | `bigint` leaves | `bigint` | | `date` | `Date` instances | `Date` | | `function` | Function values | `Function` | | `label` | Every field label (key) | — (`{ field, level }`) | See [Types & snippets](/docs/api/types) for the exported type aliases. ## Render URLs as links ```svelte {#snippet string({ value })} {#if isUrl(value)} {value} {:else} "{value}" {/if} {/snippet} ``` ## Relative time for `Date` values ```svelte {#snippet date({ value })} {/snippet} ``` ## Format large numbers ```svelte {#snippet number({ value })} {fmt.format(value)} {/snippet} ``` ## Badge booleans ```svelte {#snippet boolean({ value })} {value ? 'yes' : 'no'} {/snippet} ``` ## Field-scoped rendering The `field` prop lets you key behavior off the parent label: ```svelte {#snippet string({ value, field })} {#if field === 'email'} {value} {:else} "{value}" {/if} {/snippet} ``` `field` is `undefined` at the root and inside array elements. `level` is the depth — useful for nested-specific styling. ## Custom label renderer The `label` snippet replaces the default key rendering. It receives `{ field, level }` and no `value`: ```svelte {#snippet label({ field, level })} {field} {/snippet} ``` ## Mixing themes and snippets Snippets only replace the value cell. The surrounding container, punctuation, and field label continue to use `StyleProps` classes and `--sjv-*` tokens. Combine both for full theming: ```svelte {#snippet string({ value })} {value} {/snippet} ``` ## Related - [JsonView props](/docs/api/json-view) — every snippet listed alongside the other props - [Types & snippets](/docs/api/types) — exported prop types for each snippet - [Themes & CSS variables](/docs/themes) — theming the parts snippets don't touch # Themes & CSS Variables > Swap built-in light and dark themes or drive every color through CSS custom properties with @humanspeak/svelte-json-view-lite. **Source:** [https://jsonview.svelte.page/docs/themes](https://jsonview.svelte.page/docs/themes) --- The library ships two classname maps — `defaultStyles` (light) and `darkStyles` — and exposes every color as a `--sjv-*` CSS custom property so you can retheme without swapping the `style` prop. ## Built-in Themes ```svelte ``` Both exports conform to `StyleProps`. Spread them to patch individual keys: ```svelte ``` ## CSS Variable Tokens Every color used by the viewer is declared on the container element as a `--sjv-*` custom property. Overriding any token cascades to every descendant that reads it. | Token | Applies to | Light default | Dark default | |-------|------------|---------------|--------------| | `--sjv-background` | Container background | `#eee` | `rgb(0, 43, 54)` | | `--sjv-label` | Field labels (keys) | `#000000` | `rgb(253, 246, 227)` | | `--sjv-punctuation` | Braces, brackets, colons, commas | `#000000` | `rgb(253, 246, 227)` | | `--sjv-string` | String values | `rgb(42, 63, 60)` | `rgb(203, 75, 22)` | | `--sjv-number` | Number values | `#0b75f5` | `rgb(211, 54, 130)` | | `--sjv-boolean` | Boolean values | `rgb(70, 144, 56)` | `rgb(174, 129, 255)` | | `--sjv-null` | `null` values | `#df113a` | `rgb(129, 181, 172)` | | `--sjv-undefined` | `undefined` values | `#df113a` | `rgb(129, 181, 172)` | | `--sjv-other` | `bigint`, `Date`, functions | `#43413d` | `rgb(38, 139, 210)` | | `--sjv-expander` | Arrow glyphs + collapsed summary | `#000000` | `rgb(253, 246, 227)` | ## Global Overrides Set tokens on `:root` to retheme every instance on the page: ```css :root { --sjv-string: lavender; --sjv-number: var(--brand-500); --sjv-background: transparent; } ``` Because the defaults are declared on the container (not fallbacks on `var()`), inheritance from `:root` alone does **not** win against the per-container declarations. Use a selector with higher specificity, or target the tree element directly: ```css [role='tree'] { --sjv-background: transparent; } ``` ## Per-Instance Overrides Scope custom tokens to one viewer with a wrapping class. The library's container selector has specificity `(0,1,0)`; anything with `(0,2,0)` or higher wins without `!important`: ```svelte
      ``` This is exactly how the landing page's live playground tracks light and dark modes — it maps `--sjv-*` tokens to the site's design-system variables. ## Dark Mode with `mode-watcher` If you use [`mode-watcher`](https://www.npmjs.com/package/mode-watcher), derive the style prop from the current mode: ```svelte ``` Or skip the prop swap entirely and let CSS variables switch based on a root class: ```css :root { --sjv-background: #eee; } .dark { --sjv-background: #0f172a; } ``` ## Boolean Style Options `StyleProps` has three booleans that affect rendering regardless of which palette you pick: | Option | Effect | |--------|--------| | `noQuotesForStringValues` | Omits the `"` around string leaves | | `quotesForFieldNames` | Wraps field labels in `"` | | `stringifyStringValues` | Passes string values through `JSON.stringify` so control characters render as escapes | ```svelte ``` ## Related - [Types & snippets](/docs/api/types) — the full `StyleProps` shape - [Snippet overrides](/docs/snippet-overrides) — when theming isn't enough and you need a custom renderer