JSON Editor

unlisted

by Johannes Kaindl

View and edit JSON and JSONC files in a tree or source view. Comments and formatting in JSONC survive editing. Renders JSON code blocks in Markdown notes.

1 starsUpdated 28d agoAGPL-3.0
View on GitHub

JSON Editor for Obsidian

View and edit .json and .jsonc files inside Obsidian, with a Tree↔Source toggle and comments that survive editing.

License: AGPL-3.0 Docs: CC BY-SA 4.0 Release Obsidian

Renders ```json and ```jsonc code blocks inside Markdown notes as collapsible, theme-aware trees, too. Every structural edit on a .jsonc file is applied as a targeted text edit, so your comments and formatting stay exactly where you put them.

Auch auf Deutsch verfügbar: README.de.md.

Target platform: Obsidian 1.5.7+ on desktop and mobile. No external services, no remote resources, no telemetry.

Status: 1.11.2 released. Tree mode is a full structural editor — add / delete / rename keys, add / delete items, reorder rows (drag-and-drop or Alt+/), and switch a value's JSON type. Undo/redo (Cmd/Ctrl+Z / Cmd/Ctrl+Shift+Z) is unified across tree and source modes. On mobile, a long-press action menu, touch-sized controls and toolbar undo/redo make tree editing fully usable by touch. Optional JSON Schema validation (opt-in) and a large-file guard round out the editor. See CHANGELOG.md for the full per-release log.

A .json file open in Obsidian in tree mode: the file list on the left, and on the right a toolbar with breadcrumb, search field and Tree/Source pills above a colour-coded, collapsible tree of the file.

About

JSON inside Obsidian — without losing the editing affordances you'd expect from a real editor. Open a .json file and it opens in a dedicated view with two modes:

  • Tree mode — fold and inline-edit values, restructure with add/rename/delete/reorder/type-switch, with a breadcrumb that follows the cursor.
  • Source mode — CodeMirror 6 with JSON syntax highlighting, a parse-error banner, and Cmd/Ctrl+F find.
  • Schema-aware (optional) — opt-in JSON Schema validation flags invalid rows in real time against a companion *.schema.json file.

The plugin also renders ```json fences inside regular Markdown notes as read-only collapsible trees, so your config snippets and API examples stop being unreadable walls of text.

Everything stays inside your vault. The plugin uses Obsidian's own CSS variables, so it follows whichever theme you're using — light, dark, minimal, anything.


Features

  • .json and .jsonc file view with a Tree↔Source mode toggle in a unified top toolbar.
  • .jsonc comment preservation — open a JSONC file (comments + trailing commas) and edit it in the tree; every edit is applied as a targeted text edit on the source, so comments and formatting are kept. An unedited open→save is byte-identical. .json stays strict (comments are an error). On reorder a comment travels with the element it belongs to — the trailing comment behind it and the comment lines directly above it; a comment set off by a blank line reads as a heading for its position and stays there.
  • Inline editing of strings, numbers, and booleans in tree mode — click a value, press Enter to commit, Escape to cancel.
  • Structural editing — add keys to objects (+ Add key affordance at the bottom of each container), append items to arrays, rename object keys (✎ hover button), delete any row (✕ hover button or Backspace / Delete on focused row).
  • Drag-and-drop reorder — hover a row to reveal a ⋮⋮ handle; drag it up/down within its container (array items or object keys). Same-parent only; undoable.
  • Type-switching — every row has a T button to switch a value's JSON type (string / number / boolean / null / object / array). Destructive but undoable.
  • Undo / redoCmd/Ctrl+Z reverts the last edit; Cmd/Ctrl+Shift+Z redoes. The history is unified across tree and source mode (a single 100-deep text-based stack since 1.2.0); switching modes no longer wipes it. While you're typing in an inline editor, undo falls through to the native input. The undo/redo and focus-search commands ship with no default hotkeys — a view-local keymap handles Cmd/Ctrl+Z / Shift+Z / F while the JSON view is focused; bind your own in Settings if you prefer.
  • Search & filterCmd/Ctrl+F opens a live search that strict-filters the tree to matching keys and primitive values (case-insensitive substring); in source mode it opens CodeMirror's find panel instead. Enter / Shift+Enter jump to the next / previous match (the counter shows 3/17), ESC clears or blurs. Clearing the search restores the collapse state it had opened.
  • JSON Schema validation (opt-in) — enable in settings to auto-load a companion data.schema.json next to data.json; a banner shows the error count and offending rows get a red outline + hover message. Off by default — auto-loading schema files from a shared vault is a trust decision.
  • Large-file guard — files past a render budget (~1 MB or ~15k nodes) open in source mode with a Load tree anyway banner, so a multi-MB file never freezes the UI on open.
  • Big-integer / lossy-number safety — files containing integers JSON can't represent exactly (> 2^53) open the tree read-only with a banner; source mode stays editable, so an edit can't silently corrupt 64-bit IDs.
  • Keyboard navigation — Tab focuses the tree; / walk visible rows; / expand-collapse or jump children / parent; Home / End jump to first / last visible row; Enter / F2 open inline-edit on a primitive. WAI-ARIA tree roles (role="tree", role="treeitem", aria-expanded) for screen-reader support.
  • Collapse all / Expand all — one toolbar button toggles between them; the commands Collapse all, Expand all and Collapse to default depth are also in the palette. The collapse state is remembered per file (50 most recent) and survives closing and reopening.
  • Go to path — a quick-switcher style picker over every path in the file; choosing one scrolls to that row.
  • Long values are shortened at 120 characters with a Show more chip. Editing and copying always use the full value.
  • Breadcrumb showing the current path; clicking a segment scrolls back up the tree.
  • Copy buttons on hover — click copies the value, Alt-click copies the JSON path.
  • Theme-aware styling via Obsidian CSS variables — no hardcoded colors, no theme breakage.
  • Embedded code blocks```json and ```jsonc fences in any Markdown note render as a titled card with a collapsible tree (the ```jsonc variant tolerates comments). Blocks over 20 lines auto-collapse. Invalid JSON renders as a styled error card with line/column info, not a crash.
  • Settings — default mode, indent (2 / 4 / tab), tree marker style (modern / classic), auto-collapse depth, JSON Schema validation (opt-in), companion-schema suffix.
  • No telemetry, no remote resources. All assets ship with the plugin.

See it in action

Tree mode close up: one row is hovered and shows its per-row actions — copy, change type, rename and delete — with a drag handle on the left, while the breadcrumb above follows the active path.

Tree mode: hover a row for rename, delete, type-switch and drag handle; the breadcrumb follows the active path.

Source mode showing a .jsonc file in CodeMirror with line numbers and syntax highlighting; the line and block comments are intact and the Source pill is active.

Source mode on a .jsonc file — comments and formatting are preserved across tree edits.

Search in tree mode: the query distanceKm matches three rows, the match counter reads 3 matches, and the tree is filtered down to the matching entries and their parents.

Cmd/Ctrl+F filters the tree to matches and counts them; Enter steps from match to match.

Optional schema validation: a banner reads 3 schema errors and two rows are outlined in red — a replica count above the allowed maximum and a timeout below the required minimum.

Opt-in schema validation marks the offending rows and counts them in a banner.

A ```json fence inside a Markdown note, rendered in reading view as a read-only collapsible tree with a Copy button in its header.

A ```json fence in a note, rendered read-only in reading view.

The plugin settings tab with six options: default mode, indent, tree marker style, auto-collapse depth, schema validation and the companion schema suffix.

Click the preview for the full-size settings tab.


Requirements

Obsidian1.5.7 or newer (minAppVersion) — the view-local keymap the plugin uses was added in 1.5.7.
PlatformDesktop and mobile. Not desktop-only; the tree has a dedicated touch interaction model (long-press menu instead of hover buttons, Alt+arrow reorder).
DependenciesNone to install. The two runtime libraries (@cfworker/json-schema, jsonc-parser) are bundled into main.js.
NetworkNone. No telemetry, no remote resources, no schema fetching over the network — everything resolves inside the vault.
Building from sourceNode.js 20+ and npm (see Development).

Install

Not currently in the Community Plugin Directory. The listing was removed in September 2026 for a reason unrelated to this plugin's code: the Directory installs exclusively from GitHub releases, and the maintainer's GitHub account was flagged, which took every plugin distributed through it out of the store at once. The plugin itself is unchanged and actively maintained — releases continue on Forgejo, and the two routes below install and update from there.

With AnySource Sideloader (recommended)

AnySource Sideloader installs and updates Obsidian plugins from any git forge, which is exactly the single point of failure described above. Once it is installed, subscribe to this catalog under Browse catalogs:

https://git.jkaindl.de/jkaindl/anysource-sideloader/raw/branch/main/catalog.json

JSON Editor is listed there and installs from its Forgejo release. Updates are then offered like any store update — visible, and never applied without confirmation.

From Obsidian's Community plugins browser

Available again once the store listing returns:

  1. Settings → Community plugins → Browse, search for "JSON Editor", select Install.
  2. Enable it.

Manually

  1. Download main.js, manifest.json, and styles.css from the latest Forgejo release. Each release also ships checksums.sha256, so you can verify what you downloaded: shasum -a 256 -c checksums.sha256
  2. Drop the three files into your vault's .obsidian/plugins/json-editor/ directory.
  3. In Obsidian: Settings → Community plugins → Installed → Enable "JSON Editor".

Already installed it by hand and want updates? AnySource Sideloader recognises plugins that are already in the vault and can adopt them without a reinstall.

From source

git clone https://git.jkaindl.de/jkaindl/json-editor.git
cd json-editor
npm install
npm run build
# copy main.js, manifest.json, styles.css to <vault>/.obsidian/plugins/json-editor/

Usage

  • Open a .json file — the plugin's view is registered as the default opener for that extension.
  • Switch mode with the Tree / Source pills on the right of the toolbar, or press Cmd/Ctrl+E while a JSON file is focused (this only toggles tree/source inside JSON views — the core "Toggle reading view" binding is untouched everywhere else). You can also bind your own key via the Toggle tree/source view command.
  • Edit values in tree mode by clicking them. Strings get an <input>, numbers get numeric validation, booleans get a toggle. Press Enter to commit, Esc to cancel.
  • Edit structure in tree mode+ Add key / + Add item at the bottom of each container; hover a row for ✎ (rename key), ✕ (delete), ⋮⋮ (drag to reorder), and T (switch JSON type). Backspace / Delete removes the focused row.
  • Edit free-text in source mode — full CodeMirror editing with Cmd/Ctrl+F find. Switching back to tree re-renders from the current text.
  • Copy any value with the hover button — plain click = value, Alt-click = JSON path (e.g. $.users[2].address.city).
  • Inside Markdown notes, write a JSON code block and it renders as a collapsible tree:
    ```json
    { "feature": "tree-rendered", "collapsible": true }
    ```
    
  • Reorder a row with Alt+ / Alt+ (keyboard), or drag the ⋮⋮ handle (mouse).
  • Collapse or expand the whole tree with the toolbar button, or via the Collapse all / Expand all commands. Collapse to default depth returns to the state a freshly-opened file has. Where you left the tree is remembered per file.
  • Jump to a path with the Go to path command, then type any part of it.

On mobile

Hover and drag-and-drop don't exist on touch, so the row actions are consolidated into a menu:

  • Long-press a tree row to open its action menu: Copy value · Copy path · Rename key · Change type · Move up / Move down · Delete.
  • Single-tap a value to edit it; tap the chevron to collapse/expand.
  • Undo / Redo buttons appear in the toolbar (no hardware Cmd/Ctrl+Z on touch).

Configuration

SettingDefaultEffect
Default modetreeMode .json files open in.
IndentTwo spacesSerialization indent (Two spaces / Four spaces / Tab).
Tree marker stylemodernVisual style of the tree connectors (modern / classic).
Auto-collapse depth2Tree nodes deeper than this start collapsed.
Validate against JSON schemaoffWhen enabled, auto-loads a companion *.schema.json next to the open file and flags validation errors live. Off by default (auto-loading vault files is a trust decision).
Companion schema suffix.schema.jsonSuffix used to locate the sibling schema (data.jsondata.schema.json).

Settings live under Settings → Community plugins → JSON Editor.


How it works

Two layers. The rendering and editing logic is plain TypeScript with no Obsidian imports (src/core/); a thin adapter (src/obsidian/) binds it to the Obsidian API. That boundary is why the core is unit-testable in isolation — and why the same tree renderer serves both the file view and the code blocks in your notes.

Opening a file. The text is parsed into a plain JavaScript value and rendered as a DOM tree — no virtual DOM, no framework. Before that, two guards run: a render budget (very large files open in source mode with a Load tree anyway banner) and a lossy-number scan (a file with integers beyond 2^53 opens read-only, so an edit cannot silently corrupt 64-bit IDs).

Editing. Every structural operation — edit a value, add, delete, rename, change type, reorder — is a pure, immutable function on the parsed value. Which route the result takes back to disk depends on the file type:

  • .json — the edited value is re-serialized with your indent setting. Clean and total, but it rewrites the whole document (see the object-key-order caveat below).
  • .jsonc — re-serializing would throw your comments away, so nothing is re-serialized. The edit is translated into a targeted text edit on the source via jsonc-parser, leaving every byte you didn't touch alone. Comments and formatting survive; an unedited open→save is byte-identical.

Undo. Both modes push the pre-edit text onto one shared 100-deep stack, so undo works across a mode switch — edit in the tree, switch to source, and Cmd/Ctrl+Z still steps back through what you did.

Schema validation (off by default) looks for a sibling data.schema.json next to data.json and validates with the eval-free @cfworker/json-schema — a tree-walking validator, no new Function, no eval. It is opt-in because auto-loading a schema file from a shared vault is a trust decision, and a hostile regex inside one is a denial-of-service vector; pattern and size guards cover the rest.


Known conflicts / Compatibility

This plugin registers itself as the editor for the .json file extension. Obsidian allows only one plugin to own a given extension, so installing it alongside another plugin that also claims .json will conflict. Known examples: JSON Viewer (read-only viewer), JSON Collapsible, and Data Files Editor.

What happens on conflict (since 1.5.0): whichever plugin loads second fails to claim the extension. Rather than crashing, JSON Editor catches the error and shows a notice — "another plugin already handles .json — file view disabled, code-block rendering still active." The dedicated .json file view is disabled, but everything else keeps working: settings, the toggle / undo / redo / search commands, and ```json code-block rendering inside Markdown notes.

To use JSON Editor as your .json editor: disable the other .json plugin and reload Obsidian. Load order is not user-controllable, so two .json editors enabled at once is unsupported by design.

Tree-edit limitation — object key order: a tree edit re-serializes the whole document, and JavaScript reorders integer-like object keys (e.g. "10" before "2"). So editing an object whose keys are numeric strings may reorder them on save. Files with big integers (> 2^53) are already protected — they open read-only (edit them in source mode). For numeric-string keys where order matters, prefer source mode.


Development

npm install                                # use --legacy-peer-deps if needed; .npmrc handles it
npm test                                   # 640 Vitest tests, ~3s
npm run dev                                # esbuild watch mode
npm run build                              # production build (tsc-check + esbuild)
npm run lint                               # Biome (format + general lint)
npm run lint:obsidian                      # eslint-plugin-obsidianmd guideline gate
npx vitest run tests/core/parse.test.ts    # single test file
npx vitest                                 # watch mode

The codebase is strict TDD — every change in src/core/ and src/obsidian/ is backed by a failing test first. See CONTRIBUTING.md for the workflow.


Project layout

json-editor/
├── src/
│   ├── core/                  pure TS, no Obsidian imports — fully unit-testable
│   │   ├── types.ts           JsonValue, JsonPath, ParseResult, RenderOptions
│   │   ├── parse.ts           parse(text) → ParseResult (line/col errors)
│   │   ├── serialize.ts       serialize(value, opts) → string
│   │   ├── jsonc.ts           comment-preserving JSONC edit engine (text-in/text-out,
│   │   │                      wraps jsonc-parser; used only on the .jsonc path)
│   │   ├── edit.ts            structural ops (add/delete/rename/move/changeType), immutable
│   │   ├── history.ts         generic undo/redo stack (unified text history)
│   │   ├── render.ts          renderTree(value, opts) → HTMLElement
│   │   ├── search.ts          findMatches(value, query) for the tree filter
│   │   ├── schema.ts          compileSchema (@cfworker/json-schema) + Pointer→JsonPath + draft-07 meta-validation + ReDoS guards
│   │   ├── draft07-meta-schema.ts  canonical draft-07 meta-schema (detects malformed companion schemas)
│   │   ├── roundtrip.ts       detects lossy number literals (> 2^53, format)
│   │   ├── render-budget.ts   large-file guard (byte + node budget)
│   │   ├── textdiff.ts        minimal-span diff for source-mode undo
│   │   └── path.ts            pathToString utility
│   ├── obsidian/              adapter layer — imports core/ + obsidian API
│   │   ├── JsonFileView.ts    TextFileView; mode toggle, view Scope, banners, per-file reset
│   │   ├── TreeView.ts        wraps core/render + inline edit + copy/row actions + drag
│   │   ├── SourceView.ts      CodeMirror 6 wrapper (@codemirror/lang-json + search)
│   │   ├── CodeblockProcessor.ts  read-only tree for ```json blocks in notes
│   │   ├── SettingsTab.ts     the six settings
│   │   ├── Breadcrumb.ts      path display, segment-click → scrollToPath
│   │   ├── SearchBar.ts       tree-filter input + match count
│   │   ├── RowActions.ts      ✎ / ✕ / T hover buttons per row
│   │   ├── AddAffordance.ts   + Add key / + Add item per container
│   │   ├── TypeMenu.ts        JSON-type picker popover
│   │   ├── SchemaBanner.ts    schema-error count banner
│   │   ├── LossBanner.ts      lossy-number warn banner
│   │   ├── LargeFileBanner.ts large-file banner + "Load tree anyway"
│   │   ├── CopyButton.ts      hover-only buttons; click=value, Alt+click=path
│   │   └── Tooltip.ts         singleton hover-tooltip
│   └── main.ts                plugin entry — registers view (guarded .json claim),
│                              codeblock processor, settings, and commands
├── tests/                     core/ + obsidian/ + toolchain/ (640 tests)
│   └── __mocks__/obsidian.ts  Vitest-only mock (resolved via vitest.config + tsconfig.test.json)
├── docs/superpowers/          design specs and implementation plans (one per release)
├── .github/workflows/         release.yml + test.yml (CI: tests, lint:obsidian, build)
├── eslint.config.mjs          eslint-plugin-obsidianmd guideline gate
├── manifest.json              Obsidian plugin manifest
├── styles.css                 token-based theme-aware stylesheet
├── THIRD-PARTY-NOTICES.md      bundled-dependency license texts
├── CHANGELOG.md               Keep-A-Changelog release notes
├── CONTRIBUTING.md            bug reports, PRs, TDD workflow
└── SECURITY.md                security-reporting policy

Three tsconfigs:

  • tsconfig.json — IDE + the community-portal eslint scan; no paths alias, so obsidian resolves to the real obsidian.d.ts (this is what keeps the portal review clean).
  • tsconfig.build.json — production tsc check (validates against real obsidian.d.ts).
  • tsconfig.test.json — editor typing of tests, with the paths alias obsidiantests/__mocks__/obsidian.ts (Vitest itself resolves the mock via vitest.config.ts).

Documentation

  • README.de.md — deutsche Fassung dieser Datei (the English README is authoritative).
  • CHANGELOG.md — per-release notes (Keep-A-Changelog format).
  • CONTRIBUTING.md — bug reports, pull requests, commit conventions, TDD workflow.
  • SECURITY.md — how to report a security issue.
  • docs/superpowers/specs/ — design specs (one per release, brainstormed before implementation).
  • docs/superpowers/plans/ — checkbox implementation plans (one per release, task-by-task with TDD steps).

Hosting

This project is mirrored across two forges:

RemoteURLRole
Forgejohttps://git.jkaindl.de/jkaindl/json-editorPrimary — source development, issues, PRs
GitHubhttps://github.com/johannes-kaindl/json-editorMirror, currently inactive — see below

Issues, pull requests and releases belong on Forgejo; that is where installs come from. The GitHub mirror existed because the Community Plugin Directory links to GitHub releases only — since the account was flagged it serves no distribution purpose, and its release automation is switched off. It is kept as a mirror of the source, not as a download location.


Contributing

Bug reports and pull requests are welcome on Forgejo. For larger changes, please open an issue first to discuss the approach. See CONTRIBUTING.md for the full workflow — commit conventions, branch naming, TDD requirements, and review notes.


Project status

Actively maintained by a single maintainer (@jkaindl / @johannes-kaindl). Built for personal use, released because it might be useful to others.

Listed in the Community Plugin Directory from 12 July 2026 until September 2026, passing its automated review throughout (that check is automated; no Obsidian staff review is implied). The removal was not about this plugin: the Directory distributes from GitHub only, and the maintainer's GitHub account was flagged, which removed every plugin published through it. See Install for the routes that work — development, releases and support continue unchanged on Forgejo.

Shipped (see CHANGELOG.md): structural tree editing & undo/redo (1.0.0), drag-and-drop reorder + type-switching (1.1.0), unified cross-mode undo/redo (1.2.0), JSON Schema validation (1.3.0, opt-in since 1.5.0), data-integrity & crash hardening (1.5.0), guideline alignment + large-file guard + source-mode search (1.6.0), submission-prep + plugin rename to json-editor (1.7.0), mobile interaction model + toolbar polish (1.8.0), pop-out window correctness + community-review cleanup (1.8.1–1.8.2), eval-free schema validation with a ~52% smaller bundle (1.9.0), .jsonc support with comment-preserving tree editing (1.10.0–1.10.1), tree-rendering polish (1.10.2), storefront description (1.10.3), tree navigation & comfort — collapse-all, remembered collapse state, match-to-match search, go-to-path, shortened long values (1.11.0), portal-review hygiene: zero reviewer warnings, declarative settings (1.11.1).

Roadmap (rough, 2.x ideas):

  1. Tree search match navigation — next/prev jumps and match highlighting, beyond the current strict filter.
  2. Schema-aware autocompletion — key/enum suggestions when a companion schema is loaded.

License

  • Open source (default): GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later) — see LICENSE. This applies to everyone by default.
  • Commercial license (on request): If the AGPL's copyleft does not fit your use case — for example a proprietary/closed-source product or an Apple App Store build (App Store terms are incompatible with the AGPL) — a separate commercial license is available. See LICENSING.md.
  • Contributing: external contributions are accepted under the Contributor License Agreement, which keeps the dual-licensing model possible.
  • Documentation/text: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0) — see LICENSE-DOCS.

Dependency licenses (bundled in main.js): This plugin statically bundles @cfworker/json-schema (MIT) for JSON Schema validation and jsonc-parser (MIT) for comment-preserving .jsonc editing, plus the source-mode JSON grammar @codemirror/lang-json (MIT) and @lezer/json (MIT). All are AGPL-3.0-compatible. Full license texts and copyright notices are in THIRD-PARTY-NOTICES.md. The remaining @codemirror/* and @lezer/{common,highlight,lr} packages, and the Obsidian plugin API, are not bundled — they are provided by Obsidian at runtime (marked external in esbuild.config.mjs).


Copyright © 2026 Johannes Kaindl. Code: AGPL-3.0-or-later · Docs: CC BY-SA 4.0.

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.