feather-editor-vue
πͺΆ Feather Editor
The most lightweight rich text editor for Vue 3 β zero dependencies, headless, modular, and fast.
Getting Started Β· Vue 3 Integration Β· API Docs Β· Configuration Β· Installation Guide
β¦ Why Feather Editor?
Most rich text editors are either too heavy (ProseMirror, Slate) or too opinionated (Quill). Feather Editor is the most lightweight rich text editor for Vue 3 β a zero-dependency, headless WYSIWYG editor that provides absolute control without the bloat.
- πͺΆ Ultra-Lightweight β zero runtime dependencies, pure vanilla JS core, minimal bundle footprint
- π Dedicated Vue 3 Support β direct root import of
FeatherEditorcomponent anduseFeathercomposable - π Config-Driven β enable/disable every block, mark, and plugin from a single
feather.config.js - π¨ Headless by Design β 100% styled via CSS custom properties (
styles/feather.css) - π Extensible Architecture β add custom blocks, marks, and plugins with plain JavaScript objects
- π Paper Sizing & Print-Ready β built-in A4, Letter, Legal, A5, and fluid canvas formats with clean PDF printing
- π Security-First β sanitized paste, blocked
javascript:URLs, safe HTML output
π¦ Installation
# npm
npm install feather-editor-vue
# yarn
yarn add feather-editor-vue
# pnpm
pnpm add feather-editor-vue
Import the stylesheet once in your app entry point (e.g. main.js):
import 'feather-editor-vue/styles';
β‘ Vue 3 Quick Start
Component (FeatherEditor)
<script setup>
import { ref } from 'vue';
import { FeatherEditor, StarterKit } from 'feather-editor-vue';
import 'feather-editor-vue/styles';
const content = ref('<p>Hello from Feather Editor in Vue 3!</p>');
function handleChange(html) {
content.value = html;
}
</script>
<template>
<FeatherEditor
:extensions="StarterKit"
:content="content"
placeholder="Start typing your documentβ¦"
@change="handleChange"
/>
</template>
Composable (useFeather)
<script setup>
import { useFeather, StarterKit } from 'feather-editor-vue';
import 'feather-editor-vue/styles';
const { el, editor, getHtml, setHtml, cmd, focus } = useFeather({
extensions: StarterKit,
content: '<p>Custom canvas layout</p>',
onChange: (html) => console.log(html),
});
</script>
<template>
<div class="custom-editor-layout">
<div class="toolbar">
<button @click="cmd('toggleBold')">Bold</button>
<button @click="cmd('toggleItalic')">Italic</button>
<button @click="cmd('setHeading', 2)">H2</button>
</div>
<div ref="el" class="editor-mount" />
</div>
</template>
Vanilla JS (if needed)
import { createFromConfig } from 'feather-editor';
import config from './feather.config.js';
import 'feather-editor/styles';
const editor = createFromConfig('#app', config, {
content: '<p>Start writingβ¦</p>',
onChange(html) { console.log(html); },
});
β¨ Features
π§± Block Types
| Block | Tag | Slash Command |
|---|---|---|
| Paragraph | <p> |
β |
| Heading | <h1> β <h3> |
/h1 /h2 /h3 |
| Bullet List | <ul> |
/bullet |
| Ordered List | <ol> |
/ordered |
| Blockquote | <blockquote> |
/quote |
| Code Block | <pre><code> |
/code |
| Horizontal Rule | <hr> |
/divider |
| Callout | custom <div> |
/callout |
| Task List | <ul data-type> |
/task |
| Video Embed | <figure> iframe |
/video |
| Image | <figure><img> |
/image |
| Table | <table> |
/table |
βοΈ Inline Marks
Bold Β· Italic Β· Underline Β· Strikethrough Β· Inline Code Β· Link Β· Superscript Β· Subscript Β· Font Size Β· Font Family Β· Text Color Β· Text Background Β· Highlight
π Formatting
Text Alignment Β· Line Height Β· Indent Β· Outdent Β· Clear Format
π Plugins
| Plugin | Trigger | Description |
|---|---|---|
| Markdown Shortcuts | # > - etc. |
Converts Markdown syntax on the fly |
| Find & Replace | βF / Ctrl+F |
Floating panel with regex and case match |
| Drag to Reorder | Drag handle β Ώ |
Reorder any block smoothly by dragging |
| Format Painter | Toolbar π |
Copy & paste formatting between selections |
| Emoji & Icons | Toolbar π Β· :shortcode: |
Insert emojis inline at the caret or block callouts |
π€ Export & Import
editor.getHtml() // β sanitized HTML string
editor.setHtml('<p>β¦</p>')// β replace content from HTML
editor.getText() // β plain text string
editor.getMarkdown() // β Markdown string
editor.setMarkdown(md) // β replace content from Markdown
editor.insertMarkdown(md) // β insert Markdown at caret
editor.getJSON() // β portable JSON document
editor.setJSON(doc) // β replace content from JSON
editor.print() // β opens clean print dialog (paper formats supported)
βοΈ Configuration
All features are toggled from feather.config.js. A change here automatically updates the toolbar, bubble menu, slash menu, and keyboard shortcuts β no other files need editing.
// feather.config.js
const config = {
blocks: {
paragraph: true,
heading: true, // H1βH3
bulletList: true,
orderedList: true,
blockquote: true,
codeBlock: true,
horizontalRule: true,
callout: true,
taskList: true,
videoEmbed: true,
image: true,
table: true,
},
marks: {
bold: true, // βB
italic: true, // βI
underline: true, // βU
strike: true, // ββ§S
code: true, // βE
link: true, // βK
superscript: true,
subscript: true,
fontSize: true,
fontFamily: true,
textColor: true,
textBackground: true,
highlight: true,
},
formatting: {
textAlign: true,
lineHeight: true,
indent: true,
outdent: true,
clearFormat: true,
},
plugins: {
markdownShortcuts: true,
findReplace: true,
dragReorder: true,
formatPainter: true,
emoji: true,
},
toolbar: {
enabled: true,
items: [
'bold', 'italic', 'underline', 'strike', '|',
'heading', 'bulletList', 'orderedList', '|',
'link', 'image', 'table', 'emoji', '|',
'clearFormat', 'formatPainter',
],
},
bubbleMenu: {
enabled: true,
items: ['bold', 'italic', 'underline', 'strike', '|', 'link'],
},
editor: {
placeholder: "Write something, or type '/' for commandsβ¦",
spellcheck: true,
autofocus: false,
readOnly: false,
attribution: true, // "Made with Feather" credit; set false to remove
},
history: {
enabled: true,
maxSteps: 100,
},
};
export default config;
π API
Content & Inspection
editor.getHtml() // β HTML string
editor.setHtml('<p>β¦</p>') // set content
editor.getText() // β plain text
editor.getMarkdown() // β Markdown string
editor.isEmpty() // β boolean
Commands
editor.cmd('toggleBold')
editor.cmd('setTextColor', '#ef4444')
editor.cmd('insertBlock', 'callout')
// Chainable API
editor.chain().toggleBold().toggleItalic().run()
State & Lifecycle
editor.focus()
editor.blur()
editor.enable()
editor.disable()
editor.isActive('bold') // β boolean
editor.destroy()
Events
editor.events.on('change', ({ html }) => { β¦ })
editor.events.on('selectionchange', ({ editor }) => { β¦ })
editor.events.on('keydown', ({ event }) => { β¦ })
editor.events.on('paste', ({ editor }) => { β¦ })
β¨οΈ Keyboard Shortcuts
| Mac | Windows / Linux | Action |
|---|---|---|
βB |
Ctrl+B |
Bold |
βI |
Ctrl+I |
Italic |
βU |
Ctrl+U |
Underline |
ββ§S |
Ctrl+Shift+S |
Strikethrough |
βE |
Ctrl+E |
Inline code |
βK |
Ctrl+K |
Insert / edit link |
βZ |
Ctrl+Z |
Undo |
ββ§Z |
Ctrl+Shift+Z |
Redo |
βF |
Ctrl+F |
Find & Replace |
/ |
/ |
Slash command menu |
π Markdown Shortcuts
Type at the start of a line followed by Space:
| Input | Result |
|---|---|
# |
Heading 1 |
## |
Heading 2 |
### |
Heading 3 |
- or * |
Bullet list |
1. |
Ordered list |
> |
Blockquote |
``` |
Code block |
--- |
Horizontal rule |
Inline marks (wrap text):
| Input | Result |
|---|---|
**text** |
Bold |
*text* |
Italic |
`code` |
Code |
~~text~~ |
π¨ Theming
All colours, sizes, and typography are CSS custom properties defined in styles/feather.css. Override them on :root:
:root {
--feather-bg: #ffffff;
--feather-fg: #09090b;
--feather-border: #e4e4e7;
--feather-primary: #18181b;
--feather-muted: #f4f4f5;
--feather-muted-fg: #71717a;
--feather-accent: #f4f4f5;
--feather-radius: 6px;
--feather-font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--feather-font-mono: 'JetBrains Mono', ui-monospace, monospace;
}
Dark mode β add data-theme="dark" to <html> or any ancestor container:
document.documentElement.dataset.theme = 'dark';
π Writing Extensions
Extensions can declare a manifest for ordering and validation: dependsOn, conflictsWith, version, and lazy: () => import('β¦'). Register at runtime with editor.use(ext).
export const MyExt = {
name: 'myExt', type: 'plugin', version: '1.0.0',
dependsOn: ['link'], conflictsWith: ['otherExt'],
commands(editor) { return { /* β¦ */ }; },
};
editor.use(MyExt);
π Project Structure
feather-editor/
βββ src/
β βββ core/ β Editor, Schema, Commands, EventBus, History, Selection
β βββ extensions/ β blocks, marks, formatting, plugins
β βββ ui/ β Toolbar, BubbleMenu, SlashMenu, PresenceBar
β βββ utils/ β dom, html (sanitizer), markdown, json
β βββ createFromConfig.js β factory for feather.config.js
βββ adapters/
β βββ vue/ β useFeather composable + FeatherEditor component
βββ docs/ β guides and documentation
βββ styles/
β βββ feather.css β core theme and paper canvas styles
βββ feather.config.js β feature flags and configuration
βββ package.json
π Security
Security is foundational to Feather Editor. Read our Security Policy for details on HTML sanitization, URL validation, and reporting vulnerabilities.
π License
Feather Editor is free and MIT-licensed β use it anywhere, commercially too. By default, the editor displays a subtle βMade with Featherβ credit; you can remove it anytime with attribution: false in feather.config.js.
Related Packages
Vue block editor β official Vue 3 bindings for Blok, the headless Notion-like ri...
Vue 3 bindings for RichKit: useEditor composable, EditorContent component and pr...
A complete rich text editor. Everything included, ready in minutes. Open-source...
Notion-like block editor for Vue 3 β supports a sticky format toolbar and/or a f...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.2.7 | >=3.2 | MIT | |
| 1.2.5 | >=3.2 | MIT | |
| 1.2.4 | >=3.2 | MIT | |
| 1.2.3 | >=3.2 | MIT | |
| 1.2.2 | >=3.2 | MIT |