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):
| Option | Type | Default | Description |
|---|---|---|---|
| el | string|Element | required | Container CSS selector or DOM element. |
| value | Object|Array|string | {} | Initial JSON. Object/Array directly, or a JSON string. |
| title | string | 'JSON 编辑器' | Title shown in the header bar. |
| theme | 'light'|'dark' | 'light' | Color theme. |
| height | string | — | Fixed height, e.g. '420px'. Omit for auto-fit. |
| max_height | string | '50vh' | Max height; content beyond scrolls inside 5px scrollbars. |
| font_size | string | — | Base font size for the whole editor, e.g. '13px'. |
| defaultView | string | 'editor' | Initial tab: 'editor' | 'mindmap' | 'text'. |
| readonly | boolean | false | Disables all editing; view-only. |
| onChange | function(json) | — | Fires after every edit. Receives the current JSON object. |
| onError | function(errors) | — | Fires when validation fails. errors is an array of {path, msg}. |
| onSave | function(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.
| Tab | What it does | Interactions |
|---|---|---|
| editor | Structured tree editor | Click ▼ 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. |
| mindmap | Tree visualization | Drag 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). |
| text | Raw JSON textarea | Manual 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 type | Result |
|---|---|
{"x": 1} | Converted to an object node with children — keep editing inside it |
[1, 2] | Converted to an array node |
true / false / null | Boolean / null literal (case-sensitive) |
123, -3.14, 1e5 | Number (quotes removed automatically) |
"text" | String (escapes parsed) |
| anything else | Plain 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>
| Attribute | Maps to |
|---|---|
| data-title | title |
| data-theme | theme |
| data-height | height |
| data-max-height | max_height |
| data-font-size | font_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
| Prop | Type | Default | Description |
|---|---|---|---|
| v-model | Object|Array|string | {} | Two-way binding; edits emit update:modelValue. |
| title | string | 'JSON 编辑器' | Reactive — changing it rebuilds the header. |
| theme | string | 'light' | Reactive — switching rebuilds with data preserved. |
| height / max_height / font_size | string | see options | Same as vanilla options. |
| default_view | string | 'editor' | Same as vanilla defaultView. |
| readonly | boolean | false | Same 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.