Open-source project
Tsuzat/Edra avatar
Tsuzat/Edra

Edra: a block-style rich text editor that lands in your Svelte source tree

Fully controllable and best rich text editor for Svelte Developers

680 stars32 forksSvelteMIT

At a glance

What is it?
Edra is a rich text editor for Svelte 5 built on Tiptap and styled with shadcn-svelte, distributed through the shadcn-svelte registry so its source is copied into your project rather than installed as a dependency. That choice gives full control over styling and dependencies, at the cost of owning the code afterwards.
Who is it for?
Edra suits a Svelte 5 team that wants a Notion-like block editor, wants the styling and the source in its own repository, and is prepared to maintain a vendored copy of the editor. It is the wrong choice for a project that prefers a versioned dependency with an upgrade path, for a React codebase, or for a team that needs the editor to be exactly the same on every machine without a manual sync step.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 75 days ago.
What is it written in?
Mainly Svelte, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An editor you copy into your project instead of a dependency

Edra is a rich text editor for Svelte 5, and the way it is distributed is the first thing to understand. The README states that Edra is distributed via the shadcn-svelte registry, meaning the source code is installed directly into your project, and it gives the reason: absolute control over the styling and dependencies.

This is the same model shadcn-svelte uses for its own components. The registry entry is fetched by a CLI, and what lands in your repository is source you own, edit and commit. There is no versioned npm package in the usual sense, so there is also no upgrade button. When Edra ships a change, updating means re-running the install and dealing with the diff, or copying the changed files by hand.

That trade is worth weighing honestly. The upside is real: you can restyle a component without fighting a package's abstraction, you can delete the parts you do not need, and there is no risk of a transitive dependency surprising you. The downside is that you now own the code, including its bugs, its security updates and its compatibility with the next Svelte release.

The project itself is a SvelteKit package. The repository has a src directory, a vite configuration, a components.json file for shadcn-svelte, a registry.json, a bin directory with a CLI entry point, and a static directory. The package metadata names it edra at version 3.1.3, with MIT licensing and Svelte 5 as the only peer dependency.

The audience is a Svelte team building a note-taking app, a documentation tool, a CMS-like interface or an AI chat product that needs a good editing surface.

Tiptap underneath, two variants on top

The editor core is Tiptap, and the README is explicit that Edra is built on top of it for Svelte 5 environments. That matters for what you can extend: Edra is a Svelte-flavoured assembly of Tiptap extensions rather than a from-scratch editor, so the Tiptap extension ecosystem is the extension surface.

There are two variants. One is the opinionated Shadcn UI flavour, with the styling and components of shadcn-svelte, which the README describes as a beautiful, cohesive and fully accessible writing experience out of the box. The other is an unstyled Headless core for bringing your own design system.

That split is the main design decision in the project, and it is a good one, because the two audiences have opposite needs. A team shipping a product with an existing design system wants the behaviour without the opinionated styling, and a team that wants a good-looking editor in a weekend wants the opinionated one. Since the source is in your repository, picking a variant and then diverging from it is a normal code review rather than a fork decision.

On the framework side, the project is Svelte 5 specific and the README says it uses runes and snippets for reactive state management. The package peer dependency pins svelte at ^5.0.0, so a Svelte 4 application cannot install it. The component library underneath is bits-ui, with the Tiptap version badge showing the 2.x line, and the styles come from Tailwind v4 through the Vite plugin.

Block mechanics, slash commands and the extension list

The feature list is what makes this a block editor rather than a contenteditable textarea.

Block mechanics means native support for drag-and-drop block handles, described in the README as just like Notion. Slash commands open a contextual menu when you type /, offering headings, media and tables. Rich media and embeds cover image, video and audio upload, plus pasting HTML to embed YouTube and Spotify through an iframe handler.

The extension list is broader than the usual set. First-class support is claimed for mathematics with KaTeX, Mermaid diagrams, callouts, and syntax-highlighted code blocks. A table of contents is extracted automatically from the hierarchical headings and used to render a scroll-spy side navigation.

The AI integration deserves a specific note because the design is unusual. The README describes hooks designed specifically for streaming AI completions directly into the editor canvas, and the quick start example shows a callAI function that takes a prompt with onChunk and onError callbacks, and the comment says you implement your own AI provider. In other words, Edra does not ship a model client. It gives you a stream-shaped contract, and the transport, the model and the billing are yours.

The quick start shows how the pieces fit. The editor is created with createEditor, passing onUpdate and callAI, and the markup is a component tree: an Edra wrapper, an optional UseAI slot, a Toolbar, a BubbleMenu, a Content area and a DragHandle. Each piece is optional, which is how the same package serves both a minimal headless setup and a full Notion-like surface.

Installation is one registry command, and it writes into your source tree

Installation is a single command, because the shadcn-svelte CLI does the work of fetching the registry entry and writing the files:

bash
npx shadcn-svelte@latest add https://edra.tsuzat.com/r/edra.json

The README points to the installation documentation for the unstyled Headless variant and for more detailed installation options, so the command above is the default path rather than the only one.

What you get afterwards is visible in the quick start example. The import comes from your own lib directory, not from node_modules:

svelte
<script lang="ts">
	import { createEditor, Edra } from '$lib/edra/shadcn/index.js';
	import { updateInDB } from '$lib/db';

The example then shows the two optional hooks. onUpdate is a function you can use to do something when the content is updated, with the comment noting you may want to save the content somewhere and can define your own logic. The callAI function has the signature taking a prompt with onChunk and onError callbacks, and the README comment states it allows you to implement your own AI provider.

The markup half of the example shows the composition, and it is worth reading because it is the whole API surface in miniature:

svelte
<div class="rounded-lg border">
	<Edra {editor}>
		<Edra.UseAI />
		<Edra.Toolbar class="max-w-full! scrollbar-none overflow-x-scroll border-b p-1" />
		<Edra.BubbleMenu />
		<Edra.Content class="h-150 cursor-auto overflow-y-scroll px-8 py-4 *:outline-none" />
		<Edra.DragHandle />
	</Edra>
</div>

The classes are plain Tailwind, and that is the point of the registry distribution. Every dimension, colour and spacing value on the toolbar and content area is yours to change.

Content is JSON, HTML or Markdown, and you choose the storage

The README states that the documentation contains exhaustive guides on configuring the editor, extracting data in JSON, HTML or Markdown, customising the UI, and connecting to i18n libraries.

Three output formats is the right number of choices for an editor that will be persisted. JSON is the native Tiptap document format and the one to store if you want to reopen the document in the editor with all its structure. HTML is what you need for rendering elsewhere. Markdown is what you need if the content is destined for a repository, a documentation pipeline or a text-first workflow.

The example makes the storage side explicit. The onUpdate callback calls editor?.getJSON() and passes the content to updateInDB, a function imported from your own db module. The editor never touches a database, and it never assumes one exists. The optional comment says you may want to save the content somewhere and that you can define your own logic, and the import path $lib/db is your project code, not Edra code.

This is a deliberate and sane separation. The editor produces a document object and hands it to you, and everything about when and where to persist it stays on your side. It also means the editor has no opinion about conflicts, no opinion about offline, and no opinion about multi-user editing. Those are your problems to solve.

The i18n support in the documentation matters for a different reason: an editor with a slash-command menu, a bubble menu and a table of contents has a lot of user-facing strings, and the fact that the project documents connecting to i18n libraries suggests those strings are reachable rather than hard-coded.

Where Edra is the wrong choice

The clearest case is a team that wants a dependency it can version and upgrade. Registry distribution means there is no semver promise, and Edra is moving quickly: 2.4.1 in February 2026, 3.0.1 in July 2026, and 3.1.2 later that month. A major version bump in a copy-into-your-project library means you are likely to be resolving conflicts by hand, and a project with a strict release process will find that painful.

The second case is a React codebase. Tiptap is React-first and has a large React ecosystem, and Edra's value is specifically in the Svelte 5 assembly around it. Porting the component tree to React is not the intended use.

The third case is a need the feature list does not cover. There is no mention of collaborative editing with presence, comments, or a version history in the README, and no mention of a headless editing mode for mobile or a constrained viewport. For a product that needs two people typing in the same document, that is a significant absence, and nothing in the documentation suggests it is planned.

A smaller risk worth naming: because the source lives in your repository, the usual supply chain protections do not apply in reverse. You are not pulling in an unknown package, but you are also not receiving a patched version when one is needed. And the AI hook is a deliberate hole in the editor: Edra streams whatever your provider returns into the canvas, so prompt injection from pasted content, and whatever rendering your provider's output triggers, are your responsibility.

Tooling, release pace and the maintenance picture

The repository shows a normal SvelteKit library workflow. The scripts cover vite dev and vite build with a prepack step, svelte-kit sync, svelte-check for type checking through a check script with a watch variant, prettier and eslint for linting and formatting, and vitest for unit tests with a browser mode using playwright. There is a registry:build script that runs the shadcn-svelte registry build through bunx, which is how the JSON that the install command fetches is produced.

The packaging is careful about what it ships. The files list includes dist, the bin directory and the src/lib/edra directory, with test and spec files excluded, and sideEffects is limited to CSS files so that unused styles can be tree-shaken. The package is an ES module with a Svelte condition in the exports map and a single svelte peer dependency.

The releases came in a burst: 3.0.1 on 2026-07-14 and 3.1.2 on 2026-07-23, after 2.4.1 in February. The last push to the repository was on 2026-08-10, and the repository is not archived. The default branch is next, which suggests the active development line sits there while a released line is maintained elsewhere, and the package version in the manifest, 3.1.3, is ahead of the latest listed release tag, which is a small inconsistency worth checking before you pin anything.

The licence is MIT, with the LICENSE file at the repository root and the same identifier in the package metadata. For copied-in source, MIT means you can modify the vendored code freely, which is the point of the model, and it also means you owe nothing back to the project for changes you make.

Editorial conclusion

Edra suits a Svelte 5 team that wants a Notion-like block editor, wants the styling and the source in its own repository, and is prepared to maintain a vendored copy of the editor. It is the wrong choice for a project that prefers a versioned dependency with an upgrade path, for a React codebase, or for a team that needs the editor to be exactly the same on every machine without a manual sync step. Before adopting it, run the registry install in a scratch branch, check the Tiptap extension set against the features you need, and read the data extraction documentation before you commit to a content format.

Frequently asked questions

How do I install the Edra rich text editor in a Svelte project?

The README gives npx shadcn-svelte@latest add https://edra.tsuzat.com/r/edra.json, which copies the source into your project through the shadcn-svelte registry.

Is Edra a dependency or copied source?

It is copied source. The README states Edra is distributed via the shadcn-svelte registry, meaning the source code is installed directly into your project.

What does Edra use as its editor core?

It is built on top of Tiptap, with the styling and components of shadcn-svelte, and the package peer dependency requires svelte ^5.0.0.

Does Edra include an AI provider?

No, the README describes hooks for streaming AI completions and a callAI function where you implement your own AI provider, using onChunk and onError callbacks.

What content formats can Edra export?

The documentation covers extracting data as JSON, HTML or Markdown, and the quick start example saves editor.getJSON() through your own persistence function.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. Tsuzat/Edra on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tsuzat-edra.svg)](https://hysenlabs.com/projects/tsuzat-edra)

Was this useful?