notionuxt
notionuxt
A modern and beautiful Notion-style rich text editor for Vue 3, powered by Matra.
✨ Features
Rich Text Editing
- Headings (H1, H2, H3) with proper hierarchy
- Text Formatting: Bold, italic, underline, strikethrough, highlight, superscript, subscript
- Lists: Bullet lists, numbered lists, and nested task lists with checkboxes
- Code Blocks: Syntax highlighting for multiple languages (JavaScript, TypeScript, HTML, CSS)
- Blockquotes and horizontal rules
- Text Alignment: Left, center, right, justify
- Typography: Smart quotes, dashes, and ellipses
Media & Embeds
- Image Upload: Drag & drop or paste images with resize capabilities
- YouTube Embeds: Embed videos with customizable controls
- File Handling: Support for PNG, JPEG, GIF, and WebP images
Interactive Elements
- Mentions: @mention system with suggestions
- Emojis: Emoji picker with
:shortcode:and emoticon support - Slash Commands: Quick access to all editor features via
/commands - Collapsible Details: Expandable content sections
- Mathematics: LaTeX math expressions (inline and block)
- Drag & Drop: Reorder content blocks with drag handles
Storage
- Auto-save: Content automatically saved to localStorage
- Persistent State: Content restored on page reload
UI/UX
- Modern Design: Clean, minimal interface
- Dark/Light Theme: Theme toggle with system preference detection
- Responsive: Works seamlessly on desktop and mobile devices
- Keyboard Shortcuts: Full keyboard navigation support
- Floating Toolbar: Context-aware formatting toolbar
🚀 Installation
Prerequisites
- Nuxt 3.0+
- Node.js 16+
Install the package
npm install notionuxt
# or
yarn add notionuxt
# or
pnpm add notionuxt
That's it! No additional dependencies required - everything is bundled.
📦 Package: npmjs.com/package/notionuxt
Tailwind CSS Configuration
The package automatically configures Tailwind CSS for you! Just use the provided helper:
For Tailwind CSS v3
Wrap your Tailwind config with the withNotionUxt helper:
// tailwind.config.js
const { withNotionUxt } = require('notionuxt/lib/tailwind-config')
module.exports = withNotionUxt({
content: [
'./components/**/*.{js,vue,ts}',
'./layouts/**/*.vue',
'./pages/**/*.vue',
// notionuxt paths are automatically added!
],
theme: {
extend: {},
},
plugins: [],
})
For Tailwind CSS v4
The @source directive is automatically included in the package styles. Just import the styles:
@import 'tailwindcss';
@import 'notionuxt/styles';
/* notionuxt content paths are automatically included! */
📖 Usage
Basic Setup
<script setup>
import { NotionEditor } from 'notionuxt'
// Styles are automatically imported
</script>
<template>
<div>
<NotionEditor />
</div>
</template>
With Options
<script setup>
import { NotionEditor } from 'notionuxt'
const editorOptions = {
content: '<p>Start writing...</p>',
editable: true,
autofocus: true,
placeholder: 'Type something...'
}
</script>
<template>
<div>
<NotionEditor
:options="editorOptions"
class="my-custom-editor"
/>
</div>
</template>
Advanced Usage with Composables
<script setup>
import { NotionEditor, useEditor } from 'notionuxt'
import { ref } from 'vue'
const editorRef = ref()
const { editor } = useEditor({
content: '<p>Hello World!</p>',
editable: true
})
function getContent() {
if (editor.value) {
console.log(editor.value.getHTML())
}
}
function setContent() {
if (editor.value) {
editor.value.setContent('<p>New content!</p>')
}
}
</script>
<template>
<div>
<NotionEditor ref="editorRef" />
<button @click="getContent">
Get Content
</button>
<button @click="setContent">
Set Content
</button>
</div>
</template>
🎨 Styling
Default Styles
The package includes default styles that work out of the box. For full functionality, make sure to import the styles:
import 'notionuxt/styles'
Custom Styling
You can customize the appearance by overriding CSS variables. Important: Define your custom CSS variables after importing notionuxt/styles to ensure they override the defaults:
/* Import notionuxt styles first */
@import 'tailwindcss';
@import 'notionuxt/styles';
/* Then define your custom variables - they will override the defaults */
:root {
--background: #ffffff;
--foreground: #000000;
--card: #ffffff;
--card-foreground: #000000;
--popover: #ffffff;
--popover-foreground: #000000;
--primary: #3b82f6;
--primary-foreground: #ffffff;
--secondary: #f1f5f9;
--secondary-foreground: #000000;
--accent: #f1f5f9;
--accent-foreground: #000000;
--muted: #f8fafc;
--muted-foreground: #64748b;
--border: #e2e8f0;
--input: #e2e8f0;
--ring: #3b82f6;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
--radius: 0.75rem;
}
/* Override dark mode variables */
.dark {
--background: #1a1a1a;
--foreground: #ffffff;
--card: #1a1a1a;
--card-foreground: #ffffff;
--popover: #1a1a1a;
--popover-foreground: #ffffff;
--primary: #3b82f6;
--primary-foreground: #ffffff;
--secondary: #2a2a2a;
--secondary-foreground: #ffffff;
--accent: #2a2a2a;
--accent-foreground: #ffffff;
--muted: #2a2a2a;
--muted-foreground: #a0a0a0;
--border: #3a3a3a;
--input: #3a3a3a;
--ring: #3b82f6;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
}
body {
@apply bg-background text-foreground;
}
Alternatively, you can scope variables to a specific class:
<template>
<NotionEditor class="my-editor" />
</template>
<style>
.my-editor {
--background: #ffffff;
--foreground: #000000;
/* Add more custom variables */
}
</style>
CSS Variables
The editor uses the following CSS variables for theming. Default values are defined in the defaults layer and can be overridden:
:root {
--background: #ffffff;
--foreground: #000000;
--primary: #3b82f6;
--secondary: #f1f5f9;
--border: #e2e8f0;
--muted: #f8fafc;
--muted-foreground: #64748b;
--card: #ffffff;
--card-foreground: #000000;
--popover: #ffffff;
--popover-foreground: #000000;
--primary-foreground: #ffffff;
--secondary-foreground: #000000;
--accent: #f1f5f9;
--accent-foreground: #000000;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
--input: #e2e8f0;
--ring: #3b82f6;
--radius: 0.75rem;
/* ... and more */
}
⚙️ Configuration
Editor Options
interface EditorOptions {
content?: string // Initial HTML content
editable?: boolean // Whether the editor is editable (default: true)
autofocus?: boolean // Auto-focus on mount (default: true)
placeholder?: string // Placeholder text
}
Using Composables
import {
createEditorExtensions,
useEditor,
useEditorActions
} from 'notionuxt'
// Create a custom editor instance
const { editor } = useEditor({
content: '<p>Custom content</p>',
editable: true
})
// Access editor actions
const { toggleBold, toggleItalic } = useEditorActions(editor)
// Create custom extensions
const extensions = createEditorExtensions(lowlight)
🎯 Features & Shortcuts
Keyboard Shortcuts
Ctrl/Cmd + B- BoldCtrl/Cmd + I- ItalicCtrl/Cmd + U- UnderlineCtrl/Cmd + Shift + X- StrikethroughCtrl/Cmd + Shift + 7- To-do listCtrl/Cmd + Shift + 8- Bullet listCtrl/Cmd + Shift + 9- Numbered listCtrl/Cmd + Shift + B- Blockquote
Slash Commands
Type / followed by:
/h1,/h2,/h3- Headings/code- Code block/image- Image upload/youtube- YouTube embed/math- Math expression/todo- Task list/quote- Blockquote/divider- Horizontal rule
🔧 Advanced Configuration
Custom Extensions
import { createEditor } from '@matrajs/core'
import { createEditorExtensions } from 'notionuxt'
import { all, createLowlight } from 'lowlight'
import { customExtension } from './my-extensions'
const lowlight = createLowlight(all)
// Matra extensions are plain objects in a plain array
const extensions = [...createEditorExtensions(lowlight), customExtension]
const editor = createEditor({
extensions,
// ... other options
})
Collaborative Editing
Real-time collaboration is available through Matra's @matrajs/collab package (step exchange, rebasing and presence over any transport). It is not bundled with notionuxt; see the Matra collaboration docs to wire it up.
📱 Responsive Design
The editor is fully responsive and optimized for:
- Desktop: Full feature set with floating toolbar
- Tablet: Adapted touch interactions
- Mobile: Optimized mobile editing experience
🤝 Contributing
We welcome contributions! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Make your changes and test thoroughly
- Run linting:
npm run lint:fixorpnpm lint:fix - Commit your changes:
git commit -m 'Add some feature' - Push to the branch:
git push origin feature/your-feature-name - Open a Pull Request
Guidelines
- Follow Vue 3 Composition API patterns
- Use TypeScript for type safety
- Follow the existing code style
- Add tests for new features
- Update documentation as needed
For more details, see the Contributing Guide (if available).
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
👤 Author
Nahim Hossain Shohan
- GitHub: @nh-shohan
- LinkedIn: Nahim Hossain Shohan
🙏 Acknowledgments
- Matra - The headless editor framework
- Vue.js - The progressive JavaScript framework
- Nuxt.js - The Vue.js framework
- shadcn-vue - Beautiful Vue UI components
- Tailwind CSS - Utility-first CSS framework
🔗 Links
Made with ❤️ and lots of ☕
Related Packages
Headless WYSIWYG editor for Vue 3 built on Tiptap 3, with slash commands, mentio...
Notion-like block editor for Vue 3 — supports a sticky format toolbar and/or a f...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 2.0.0 | MIT | ||
| 1.0.1 | MIT | ||
| 1.0.0 | MIT | ||
| 0.1.2 | ^3.0.0 | MIT | |
| 0.1.1 | ^3.0.0 | MIT | |
| 0.1.0 | ^3.0.0 |