@heyramzi/rich-editor
v1.0.2
Published
Svelte 5 rich text editor on Tiptap: slash menu, image toolbar, block ids, a Markdown bridge and an SSR renderer for the saved JSON.
Maintainers
Readme
@heyramzi/rich-editor
A Svelte 5 rich text editor on Tiptap: headings, lists, tables, images, YouTube links, a slash menu, an image toolbar and optional block ids. It saves Tiptap JSON, and a renderer turns that JSON back into HTML on the server, so a crawler sees the body.
It lives in its own package so @heyramzi/ui doesn't pull Tiptap into every app.
Install
pnpm add @heyramzi/rich-editorsvelte (5.57 or newer) and @heyramzi/ui (8 or newer) are peers. The editor's toolbar uses the kit's Button and Input, so import the kit's tokens.css once and point Tailwind at the package:
@import "tailwindcss";
@import "@heyramzi/ui/tokens.css";
@source "../node_modules/@heyramzi/rich-editor";Usage
<script lang="ts">
import { RichEditor, RichRenderer } from "@heyramzi/rich-editor";
let doc = $state<Record<string, unknown> | null>(null);
</script>
<RichEditor content={doc} onchange={(json) => (doc = json)} preset="full" />
<RichRenderer content={doc} />What is inside
| Export | What it is |
| --- | --- |
| RichEditor | The editor. preset is full or notes, blockIds stamps a stable id on each block |
| RichRenderer | Renders saved JSON to HTML, on the server too, with a click-to-load YouTube facade |
| renderTiptapContent, extractHeadings, extractYoutubeVideos | The serializer, for a table of contents or a sitemap |
| BlockIdExtension, generateBlockId | The block id extension |
| @heyramzi/rich-editor/markdown | tiptapToMarkdown and markdownToTiptap. It pulls in markdown-it, so it isn't in the root export |
| @heyramzi/rich-editor/block-ops | Edit a document by block id: replace, insert, delete |
| @heyramzi/rich-editor/inline-editor | A single-block editor for one field |
| @heyramzi/rich-editor/content.css | The typography for editor and renderer. Both import it already |
Comparison tables
A table whose first row has a Winner (or Gagnant, Vainqueur) header gets a comparison-table class, and each cell in that column becomes a pill with data-winner set to the first word of the cell, lowercased. tie and other are styled for you. Colour one product from your own CSS:
.tiptap-content table.comparison-table .winner-cell[data-winner="acme"] p {
background: color-mix(in srgb, var(--color-brand-terra) 14%, transparent);
color: var(--color-brand-terra);
}