@htmlbricks/hb-json-viewer
v0.76.5
Published
Renders JSON as an expandable, syntax-colored tree. Accepts a parsed object or a JSON string and supports initial expand modes (`open`, `closed`, `first`). Optional `edit` / `strict_schema` enable inline key/value editing and structure add/delete with `up
Readme
hb-json-viewer
Category: data · Tags: data, json · Package: @htmlbricks/hb-json-viewer
Description
hb-json-viewer renders JSON as an expandable, syntax-highlighted tree inside a shadow root. The payload may be a JavaScript object (when you set the json property from code) or a JSON string (from the json attribute or property). When json is a string, the component tries JSON.parse; on failure it logs a console.error and keeps the unparsed string as json.
Optional edit mode (edit="yes") adds inline controls to rename object keys, change primitive values, delete nodes, and append children. Each structural change dispatches an update event on the host whose detail includes deep snapshots previous_json and json so hosts can persist or diff the tree without re-reading the DOM.
Initial expand mode (status)
The status attribute controls the initial collapsed state per depth. Users can still expand or collapse nodes afterward.
| Value | Behavior |
|-------|----------|
| open | All levels start expanded (default). |
| closed | All object/array nodes start collapsed. |
| first | Only the root level is expanded; nested containers start collapsed. |
Edit mode and strict_schema
When edit is no (default), the tree is read-only.
When edit is yes, object keys show a pencil control for renaming, primitives show a pencil for values, non-primitive nodes can add children, and deletable nodes show a remove control. Renaming is ignored if the new key is already taken on the same parent. Add child: arrays receive a new null element; objects receive a new property newKey (or newKey_1, newKey_2, … if those names already exist) with value null.
strict_schema (default yes) controls how values are edited:
strict_schema="yes"— Only string, number, and boolean leaves are editable. Strings use a single-line input or a textarea when the value is long or contains newlines. Numbers use a numeric input; booleans use atrue/falseselect.null,undefined, and other primitive-like displays are not opened for value editing in this mode (structure can still be changed with add/delete where applicable).strict_schema="no"— Any primitive leaf uses one textarea prefilled withJSON.stringify-style text; confirming parses withJSON.parse, or keeps the raw string if parsing fails.
Styling (Bulma and tree tokens)
The component forwards Bulma into the shadow root and themes the tree with --jn-* tokens and --bulma-* variables on :host. Defaults chain through Bulma’s variable system — see Bulma CSS variables.
There are no ::part hooks; customize appearance by setting CSS custom properties on hb-json-viewer.
Notable groups:
- Tree chrome:
--jn-bracket,--jn-close,--jn-key,--jn-sep,--jn-string,--jn-children-border,--jn-button-border,--jn-button-hover-bg,--jn-type-object,--jn-type-array,--jn-popover-*. - Edit UI:
--jn-edit-icon,--jn-edit-border,--jn-edit-focus-border,--jn-edit-bg,--jn-delete-icon,--jn-delete-icon-hover. - Scheme:
--bulma-text,--bulma-text-weak,--bulma-background(and other Bulma tokens as needed).
Dark appearance follows prefers-color-scheme: dark, or data-theme="dark" / .theme-dark on html or body, or data-theme="dark" on the host element.
The authoritative list (types, defaults, and descriptions) lives in extra/docs.ts (styleSetup.vars).
CSS parts
None.
HTML slots
| Slot | Description |
|------|-------------|
| default | Optional light-DOM content rendered below the JSON tree (for example toolbars, help text, or footnotes). |
Custom element
| Name | Tag |
| --- | --- |
| hb-json-viewer | <hb-json-viewer …></hb-json-viewer> |
Attributes (snake_case; string encodings in HTML)
Web component attributes are strings. Use "yes" / "no" for booleans as reflected in HTML.
| Attribute | Required | Default | Description |
|-----------|----------|---------|-------------|
| id | No | — | Optional element id. |
| style | No | — | Optional inline styles on the host. |
| json | No* | — | JSON document as a string in markup, a parsed object from JavaScript, or omitted / undefined for the empty state. If the assigned json is a string, the component parses it when possible. |
| status | No | open | open | closed | first — initial expand/collapse behavior (see above). |
| edit | No | no | yes enables editing and add/delete controls; no is read-only. |
| strict_schema | No | yes | yes uses type-specific editors for primitives; no uses a JSON textarea per leaf. |
*If json is missing or undefined, the host shows a short “No data” message (see component.wc.svelte).
Events
update
Fired after every successful edit-mode mutation. detail matches JsonViewerUpdateDetail in the types below.
| detail.type | Meaning | Extra fields |
|---------------|---------|----------------|
| editvalue | Primitive value changed | oldValue, newValue |
| editkey | Object property renamed | oldKey, newKey |
| deletenode | Entry removed from object or array | deletedValue |
| addnode | New null entry added | — |
Always present: type, previous_json, json (deep clones of the tree before and after), and keyPath ((string | number)[] path to the affected node; for editkey, the path uses the new key as the last segment).
Usage notes
- Large payloads in HTML: Prefer assigning
element.json = myObjectorelement.setAttribute('json', JSON.stringify(obj))from script instead of embedding huge escaped strings in static HTML. - Key paths: Indices in
keyPathare numeric positions for array elements and string keys for object properties. - Snapshots:
previous_jsonandjsonare produced withstructuredClonewhen available, otherwiseJSON.parse(JSON.stringify(...))with a best-effort fallback.
Types
export type Component = {
id?: string;
json?: any;
status?: "open" | "closed" | "first";
edit?: "yes" | "no";
strict_schema?: "yes" | "no";
};
/** Discriminant for `update` — which operation produced the new tree */
export type JsonViewerUpdateType =
| "editvalue"
| "editkey"
| "deletenode"
| "addnode";
export type JsonViewerUpdateDetail = {
type: JsonViewerUpdateType;
/** Full tree before this change (deep snapshot) */
previous_json: any;
/** Full tree after this change (deep snapshot) */
json: any;
keyPath: (string | number)[];
oldValue?: any;
newValue?: any;
oldKey?: string;
newKey?: string;
deletedValue?: any;
};
export type Events = {
update: JsonViewerUpdateDetail;
};Examples
Static HTML
<hb-json-viewer
json='{"hello":"world","nested":{"a":1}}'
status="first"
edit="no"
></hb-json-viewer>JavaScript (property API and events)
<hb-json-viewer id="viewer" status="open" edit="yes" strict_schema="yes"></hb-json-viewer>
<script type="module">
const el = document.getElementById("viewer");
const data = { title: "Demo", count: 3, items: ["a", "b"] };
el.json = data;
el.addEventListener("update", (e) => {
const { type, json, keyPath } = e.detail;
console.log(type, keyPath, json);
});
</script>Additional structured examples (orders, analytics-style payloads, strict vs flexible edit) are defined in extra/docs.ts (examples).
