Installation

Three ways — pick one. All of them are zero-dependency and require no build step.

// 1. CDN (jsdelivr, use the tag you need)
<script src="https://cdn.jsdelivr.net/gh/juicy696/json-editor@main/src/json-editor.js"></script>

// 2. npm
npm install @juicy696/jsoneditor
// entry file:
import '@juicy696/jsoneditor'         // vanilla
import '@juicy696/jsoneditor/vue'     // Vue 3
import '@juicy696/jsoneditor/react'   // React 18

// 3. Download a single file from the Download section and host it yourself

File selection guide: json-editor.js for plain HTML (vanilla), json-vue.js already includes the core + Vue adapter, json-react.js includes core + React adapter. Never load two engine files on the same page.

Quick Start

The fastest path with vanilla JS — a container and one call:

<div id="editor"></div>
<script src="json-editor.js"></script>
<script>
  var editor = JED.create({ el: '#editor', value: { hello: 'world' } });
</script>

Or fully declarative, no JavaScript at all:

<json data-title="Config">{"a": 1, "b": [2, 3]}</json>

Options

All options passed to JED.create(options):

OptionTypeDefaultDescription
elstring|ElementrequiredContainer CSS selector or DOM element.
valueObject|Array|string{}Initial JSON. Object/Array directly, or a JSON string.
titlestring'JSON 编辑器'Title shown in the header bar.
theme'light'|'dark''light'Color theme.
heightstring—Fixed height, e.g. '420px'. Omit for auto-fit.
max_heightstring'50vh'Max height; content beyond scrolls inside 5px scrollbars.
font_sizestring—Base font size for the whole editor, e.g. '13px'.
defaultViewstring'editor'Initial tab: 'editor' | 'mindmap' | 'text'.
readonlybooleanfalseDisables all editing; view-only.
onChangefunction(json)—Fires after every edit. Receives the current JSON object.
onErrorfunction(errors)—Fires when validation fails. errors is an array of {path, msg}.
onSavefunction(json, valid)—Legacy save callback (save button was removed in v1.0; kept for compatibility).

Instance API

var editor = JED.create({ el: '#editor', value: {...} });

editor.get()          // → current JSON as a JS object
editor.get_text()     // → pretty-printed JSON string (2-space indent)
editor.set(value)     // replace content; accepts object or JSON string; re-renders
editor.validate()     // → array of {path, msg}; empty array = valid
editor.view(name)     // switch tab: 'editor' | 'mindmap' | 'text'
editor.destroy()      // remove the editor and clean up the container

// scan() re-scans the page for new <json> / [tag="json"] elements
// (call it after dynamically inserting markup)
JED.scan();

Events / Callbacks

JED.create({
  el: '#editor',
  value: { a: 1 },

  // fires after ANY edit (add/remove/rename/change, in editor or mindmap)
  onChange: function (json) {
    console.log('current value:', json);
  },

  // fires when structure validation fails (empty/duplicate keys, depth > 100)
  onError: function (errors) {
    // errors: [{ path: '$.a.b', msg: 'key 重复: "b"' }, ...]
  }
});

Validation runs automatically on every structural edit. Errors render as an inline red panel under the editor.

Views

Three tabs share one model; every edit is instantly reflected in all of them.

TabWhat it doesInteractions
editorStructured tree editorClick ▼ to collapse one level, ⊞ to collapse all descendants. Hover a row for + ↑ ↓ ×. Hover a {...} range to highlight it. Click any key/value for inline editing. Click a closing brace to collapse.
mindmapTree visualizationDrag empty canvas to pan, mouse-wheel to zoom (30%–300%, centered on cursor). Double-click a node to jump to the editor. + inserts a child then switches to the editor. Root node shows root(n).
textRaw JSON textareaManual edits reveal a floating “Apply to structure” button (top-right) that parses text back into the editor. Invalid JSON shows a warning.

Editing Rules

When you commit an inline value edit, the input is auto-detected in this order:

You typeResult
{"x": 1}Converted to an object node with children — keep editing inside it
[1, 2]Converted to an array node
true / false / nullBoolean / null literal (case-sensitive)
123, -3.14, 1e5Number (quotes removed automatically)
"text"String (escapes parsed)
anything elsePlain string — quotes added for you

Container-aware insertion: inside {} a new key-value pair is created (new_key, auto-deduplicated); inside [] a plain element is created.

Declarative Tags

For static pages, skip JavaScript entirely. Every <json> element and any element with tag="json" is auto-initialized on DOM ready (or call JED.scan() after dynamic insertion).

<json data-title="Config"
      data-theme="dark"
      data-max-height="50vh"
      data-height="400px"
      data-font-size="13px"
      data-readonly>{"a": 1}</json>

<div tag="json" data-title="Order">{"id": "A1024"}</div>
AttributeMaps to
data-titletitle
data-themetheme
data-heightheight
data-max-heightmax_height
data-font-sizefont_size
data-readonly (presence)readonly: true
data-value (optional)value — otherwise the element's text content is parsed

The instance is stored on the element as elem.__jed, so you can still call the API: document.querySelector('json').__jed.get().

Vue Component

Load json-vue.js (core included) and register once:

app.use(JED.vue);   // registers <json-editor> globally
PropTypeDefaultDescription
v-modelObject|Array|string{}Two-way binding; edits emit update:modelValue.
titlestring'JSON 编辑器'Reactive — changing it rebuilds the header.
themestring'light'Reactive — switching rebuilds with data preserved.
height / max_height / font_sizestringsee optionsSame as vanilla options.
default_viewstring'editor'Same as vanilla defaultView.
readonlybooleanfalseSame as vanilla.

External state changes flow in automatically (deep-watched, with loop protection). Editable instance is available via the component's internal _jed if you need direct API access.

React Component

Load json-react.js (core included) — a plain function component, no JSX required:

const e = React.createElement;

e(JED.react.component, {
  value: data,          // controlled value
  onChange: setData,    // unidirectional flow
  title: 'Editor', theme: 'dark', max_height: '50vh',
  default_view: 'editor', readonly: false
});

Props mirror the vanilla options. External value changes are diffed (JSON string compare) and applied with loop protection; theme/title changes rebuild the instance preserving data.

Theming

Two built-in themes via theme: 'light' | 'dark'. All colors are CSS variables on the .jed-root container — override them in your own stylesheet without touching the library:

.jed-root {
  --jed-accent: #0969da;   /* buttons, active tab */
  --jed-key: #0550ae;      /* key color */
  --jed-str: #116329;      /* string values */
  --jed-num: #953800;      /* numbers, [] braces */
  --jed-bool: #8250df;     /* booleans */
  --jed-brace: #cf222e;    /* {} braces (depth-0) */
  --jed-hover: #eef1f4;    /* hover highlight */
}

FAQ

Q: Can I use both json-vue.js and json-editor.js on one page?
No — both define window.JED. Load exactly one engine file per page.

Q: Does it work offline / from file:// ?
Yes. No network requests, no web workers, no fetch — a plain double-clicked HTML file works.

Q: How large is the JSON it can handle?
Comfortable up to a few thousand nodes. Beyond that the DOM tree gets heavy; collapse branches you don't need.

Q: Is the value order preserved?
Yes for rendering and editing. JSON objects are semantically unordered, but JED keeps insertion order and supports reordering with ↑/↓.

Q: How do I get notified of changes in a form workflow?
Use onChange (vanilla), v-model (Vue) or onChange (React). All receive the plain JSON object — JSON.stringify it if you need a string.