Forms
Rich text editor
Headings, lists, quotes, code and links, with a toolbar above and a small menu over whatever you
select. Markdown shortcuts work as you type: ## for a heading, - for a
list, > for a quote.
Installation
npx sinaui add rich-text-editorCopy src/lib/ui/RichTextEditor.svelte, with Toolbar.svelte, Tooltip.svelte, Button.svelte, Icon.svelte, floating.ts, scroll-edges.ts, announce.ts and tokens.css, then install the editor engine:
pnpm add @tiptap/core @tiptap/starter-kit @tiptap/pm @tiptap/extensionsExamples
A catalog note
Select some words to format them from the menu that appears over them.
Catalog note
<script lang="ts">
import RichTextEditor from '#lib/ui/RichTextEditor.svelte';
let html = $state(
'<h2>Kitab al-Manazir</h2><p>Ibn al-Haytham, <strong>Cairo</strong>, c. 1027. Seven books on <em>how we see</em>.</p><ul><li>Book I: the theory of vision</li><li>Books IV–VI: reflection and mirrors</li></ul><blockquote><p>Light travels in straight lines.</p></blockquote>'
);
</script>
<div class="demo">
<RichTextEditor label="Catalog note" bind:html />
</div>
<style>
.demo {
inline-size: min(40rem, 100%);
}
</style>With a length limit
The count turns amber near the limit and red past it. The HTML is what you'd save.
Note for the copyists
0 / 280
HTML it sends
(empty)<script lang="ts">
import RichTextEditor from '#lib/ui/RichTextEditor.svelte';
let html = $state('');
</script>
<div class="demo">
<RichTextEditor
label="Note for the copyists"
placeholder="What should they know before they start?"
maxLength={280}
bind:html
/>
<details>
<summary>HTML it sends</summary>
<pre><code>{html || '(empty)'}</code></pre>
</details>
</div>
<style>
.demo {
display: grid;
gap: 0.75rem;
inline-size: min(40rem, 100%);
}
summary {
color: var(--ui-muted);
font-size: 0.875rem;
cursor: pointer;
}
pre {
margin: 0.5rem 0 0;
padding: 0.75rem;
border-radius: var(--ui-radius-control);
background: var(--ui-subtle);
font-size: 0.8125rem;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
</style>Props
| Prop | Type | Default |
|---|---|---|
label | string (required) | |
hideLabel | boolean | false |
html | string (bindable) | '' |
placeholder | string | 'Write something…' |
maxLength | number: shows a character count |
Keyboard
On Windows and Linux, use Ctrl for ⌘ and Alt for ⌥.
| Key | Does |
|---|---|
| ⌘ B / I / E | Bold, italic, code |
| ⌘ ⇧ S | Strikethrough |
| ⌘ ⌥ 2 / 3 | Heading, subheading |
| ⌘ ⇧ 8 / 7 | Bulleted, numbered list |
| ⌘ ⇧ B | Quote |
| ⌘ K | Add or edit a link |
| ⌘ Z / ⌘ ⇧ Z | Undo, redo |
| ← → | Move along the toolbar |
| Escape | Close the link field |
Accessibility
- The writing area is a multi-line text box named by the label.
- The toolbar is one Tab stop; arrow keys move between its buttons, and each says whether its style is on.
- Every button's shortcut is in its tooltip, shown on hover and keyboard focus.
- With a limit, the count is read with the text box.
- With reduced motion, the menu over a selection fades in without moving.