├── .github
├── FUNDING.yml
└── copilot-instructions.md
├── nuxt
├── public
│ ├── robots.txt
│ └── favicon.ico
├── app
│ ├── app.vue
│ └── components
│ │ └── CompleteEditor.vue
├── nuxt.config.ts
├── .gitignore
├── tsconfig.json
├── package.json
└── README.md
├── src
├── vite-env.d.ts
├── index.ts
└── components
│ └── QuillyEditor.vue
├── demo
├── src
│ ├── vite-env.d.ts
│ ├── window.d.ts
│ ├── main.ts
│ ├── assets
│ │ └── vue.svg
│ ├── components
│ │ ├── SemanticHTMLEditor.vue
│ │ ├── CustomEditor.vue
│ │ ├── DefaultEditorSnow.vue
│ │ ├── DefaultEditorBubble.vue
│ │ └── ImageResizeEditor.vue
│ └── App.vue
├── .vscode
│ └── extensions.json
├── vite.config.ts
├── tsconfig.node.json
├── .gitignore
├── README.md
├── package.json
├── tsconfig.json
├── index.html
├── public
│ └── vite.svg
└── pnpm-lock.yaml
├── docs
├── .vitepress
│ ├── cache
│ │ └── deps
│ │ │ ├── package.json
│ │ │ ├── vue.js.map
│ │ │ ├── _metadata.json
│ │ │ └── vue.js
│ └── config.ts
├── markdown-examples.md
├── examples
│ ├── bubble-theme.md
│ ├── index.md
│ ├── snow-theme.md
│ ├── image-resize.md
│ ├── semantic-html.md
│ └── custom-editor.md
├── index.md
├── api
│ ├── component.md
│ ├── events.md
│ └── types.md
├── guide
│ ├── getting-started.md
│ ├── installation.md
│ └── basic-usage.md
└── api-examples.md
├── tsconfig.node.json
├── index.html
├── vite.config.ts
├── tsconfig.json
├── LICENSE
├── package.json
├── .gitignore
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: oleksandrshevchuk
2 |
--------------------------------------------------------------------------------
/nuxt/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-Agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/demo/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module"
3 | }
4 |
--------------------------------------------------------------------------------
/demo/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar"]
3 | }
4 |
--------------------------------------------------------------------------------
/demo/src/window.d.ts:
--------------------------------------------------------------------------------
1 | export declare global {
2 | interface Window {
3 | Quill: any
4 | }
5 | }
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import QuillyEditor from './components/QuillyEditor.vue'
2 | export { QuillyEditor }
3 |
--------------------------------------------------------------------------------
/nuxt/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alekswebnet/vue-quilly/HEAD/nuxt/public/favicon.ico
--------------------------------------------------------------------------------
/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | createApp(App).mount('#app')
5 |
--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/vue.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "sources": [],
4 | "sourcesContent": [],
5 | "mappings": "",
6 | "names": []
7 | }
8 |
--------------------------------------------------------------------------------
/nuxt/app/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [vue()]
7 | })
8 |
--------------------------------------------------------------------------------
/nuxt/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | // https://nuxt.com/docs/api/configuration/nuxt-config
2 | export default defineNuxtConfig({
3 | compatibilityDate: '2025-07-15',
4 | devtools: { enabled: true },
5 | ssr: true
6 | })
7 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true,
8 | "strict": true
9 | },
10 | "include": ["vite.config.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/demo/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true,
8 | "strict": true
9 | },
10 | "include": ["vite.config.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/nuxt/.gitignore:
--------------------------------------------------------------------------------
1 | # Nuxt dev/build outputs
2 | .output
3 | .data
4 | .nuxt
5 | .nitro
6 | .cache
7 | dist
8 |
9 | # Node dependencies
10 | node_modules
11 |
12 | # Logs
13 | logs
14 | *.log
15 |
16 | # Misc
17 | .DS_Store
18 | .fleet
19 | .idea
20 |
21 | # Local env files
22 | .env
23 | .env.*
24 | !.env.example
25 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # vue-quilly demo
2 |
3 | This demo project is created to show how to build editor on top of `QullyEditor` component.
4 |
5 | ## Project Setup
6 |
7 | ```sh
8 | pnpm install
9 | ```
10 |
11 | ### Compile and Hot-Reload for Development
12 |
13 | ```sh
14 | pnpm dev
15 | ```
16 |
17 | ### Type-Check, Compile and Minify for Production
18 |
19 | ```sh
20 | pnpm build
21 | ```
--------------------------------------------------------------------------------
/nuxt/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // https://nuxt.com/docs/guide/concepts/typescript
3 | "files": [],
4 | "references": [
5 | {
6 | "path": "./.nuxt/tsconfig.app.json"
7 | },
8 | {
9 | "path": "./.nuxt/tsconfig.server.json"
10 | },
11 | {
12 | "path": "./.nuxt/tsconfig.shared.json"
13 | },
14 | {
15 | "path": "./.nuxt/tsconfig.node.json"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/nuxt/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nuxt-app",
3 | "private": true,
4 | "type": "module",
5 | "scripts": {
6 | "build": "nuxt build",
7 | "dev": "nuxt dev",
8 | "generate": "nuxt generate",
9 | "preview": "nuxt preview",
10 | "postinstall": "nuxt prepare"
11 | },
12 | "dependencies": {
13 | "katex": "^0.16.25",
14 | "nuxt": "^4.2.1",
15 | "vue": "^3.5.25",
16 | "vue-quilly": "^1.1.6",
17 | "vue-router": "^4.6.3"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demo/src/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vue-tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@vueuse/core": "^14.1.0",
13 | "katex": "^0.16.25",
14 | "parchment": "^3.0.0",
15 | "quill": "^2.0.3",
16 | "quill-image-resize-module": "^3.0.0",
17 | "vue": "^3.5.25",
18 | "vue-markdown-render": "^2.3.0",
19 | "vue-quilly": "^1.1.6"
20 | },
21 | "devDependencies": {
22 | "@vitejs/plugin-vue": "^6.0.2",
23 | "typescript": "^5.9.3",
24 | "vite": "^7.2.6",
25 | "vue-tsc": "^3.1.6"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import dts from 'vite-plugin-dts'
4 | import path from 'path'
5 |
6 | // https://vitejs.dev/config/
7 | export default defineConfig({
8 | plugins: [
9 | vue(),
10 | dts()
11 | ],
12 | build: {
13 | lib: {
14 | entry: path.resolve(__dirname, 'src/index.ts'),
15 | name: 'VueQuilly',
16 | fileName: 'vue-quilly'
17 | },
18 | rollupOptions: {
19 | external: ['vue'],
20 | output: {
21 | globals: {
22 | vue: 'Vue'
23 | }
24 | }
25 | }
26 | },
27 | resolve: {
28 | alias: {
29 | '@': path.resolve(__dirname, 'src')
30 | }
31 | }
32 | })
33 |
--------------------------------------------------------------------------------
/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "preserve",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "paths": {
16 | "@/*": [
17 | "./src/*"
18 | ]
19 | },
20 | "jsx": "preserve",
21 |
22 | /* Linting */
23 | "strict": true,
24 | "noUnusedLocals": true,
25 | "noUnusedParameters": true,
26 | "noFallthroughCasesInSwitch": true
27 | },
28 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
29 | "references": [{ "path": "./tsconfig.node.json" }]
30 | }
31 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | QuillyEditor demo - vue-quilly
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Oleksandr Shevchuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/_metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "hash": "c335150a",
3 | "configHash": "2329454d",
4 | "lockfileHash": "e821ab6a",
5 | "browserHash": "a2244759",
6 | "optimized": {
7 | "vue": {
8 | "src": "../../../../node_modules/.pnpm/vue@3.5.25_typescript@5.9.3/node_modules/vue/dist/vue.runtime.esm-bundler.js",
9 | "file": "vue.js",
10 | "fileHash": "8d3c7f1f",
11 | "needsInterop": false
12 | },
13 | "vitepress > @vue/devtools-api": {
14 | "src": "../../../../node_modules/.pnpm/@vue+devtools-api@8.0.5/node_modules/@vue/devtools-api/dist/index.js",
15 | "file": "vitepress___@vue_devtools-api.js",
16 | "fileHash": "128b0156",
17 | "needsInterop": false
18 | },
19 | "vitepress > @vueuse/core": {
20 | "src": "../../../../node_modules/.pnpm/@vueuse+core@14.1.0_vue@3.5.25_typescript@5.9.3_/node_modules/@vueuse/core/dist/index.js",
21 | "file": "vitepress___@vueuse_core.js",
22 | "fileHash": "284b2707",
23 | "needsInterop": false
24 | }
25 | },
26 | "chunks": {
27 | "chunk-GKNP4RGU": {
28 | "file": "chunk-GKNP4RGU.js"
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/nuxt/README.md:
--------------------------------------------------------------------------------
1 | # Nuxt Minimal Starter
2 |
3 | Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
4 |
5 | ## Setup
6 |
7 | Make sure to install dependencies:
8 |
9 | ```bash
10 | # npm
11 | npm install
12 |
13 | # pnpm
14 | pnpm install
15 |
16 | # yarn
17 | yarn install
18 |
19 | # bun
20 | bun install
21 | ```
22 |
23 | ## Development Server
24 |
25 | Start the development server on `http://localhost:3000`:
26 |
27 | ```bash
28 | # npm
29 | npm run dev
30 |
31 | # pnpm
32 | pnpm dev
33 |
34 | # yarn
35 | yarn dev
36 |
37 | # bun
38 | bun run dev
39 | ```
40 |
41 | ## Production
42 |
43 | Build the application for production:
44 |
45 | ```bash
46 | # npm
47 | npm run build
48 |
49 | # pnpm
50 | pnpm build
51 |
52 | # yarn
53 | yarn build
54 |
55 | # bun
56 | bun run build
57 | ```
58 |
59 | Locally preview production build:
60 |
61 | ```bash
62 | # npm
63 | npm run preview
64 |
65 | # pnpm
66 | pnpm preview
67 |
68 | # yarn
69 | yarn preview
70 |
71 | # bun
72 | bun run preview
73 | ```
74 |
75 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
76 |
--------------------------------------------------------------------------------
/docs/markdown-examples.md:
--------------------------------------------------------------------------------
1 | # Markdown Extension Examples
2 |
3 | This page demonstrates some of the built-in markdown extensions provided by VitePress.
4 |
5 | ## Syntax Highlighting
6 |
7 | VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
8 |
9 | **Input**
10 |
11 | ````md
12 | ```js{4}
13 | export default {
14 | data () {
15 | return {
16 | msg: 'Highlighted!'
17 | }
18 | }
19 | }
20 | ```
21 | ````
22 |
23 | **Output**
24 |
25 | ```js{4}
26 | export default {
27 | data () {
28 | return {
29 | msg: 'Highlighted!'
30 | }
31 | }
32 | }
33 | ```
34 |
35 | ## Custom Containers
36 |
37 | **Input**
38 |
39 | ```md
40 | ::: info
41 | This is an info box.
42 | :::
43 |
44 | ::: tip
45 | This is a tip.
46 | :::
47 |
48 | ::: warning
49 | This is a warning.
50 | :::
51 |
52 | ::: danger
53 | This is a dangerous warning.
54 | :::
55 |
56 | ::: details
57 | This is a details block.
58 | :::
59 | ```
60 |
61 | **Output**
62 |
63 | ::: info
64 | This is an info box.
65 | :::
66 |
67 | ::: tip
68 | This is a tip.
69 | :::
70 |
71 | ::: warning
72 | This is a warning.
73 | :::
74 |
75 | ::: danger
76 | This is a dangerous warning.
77 | :::
78 |
79 | ::: details
80 | This is a details block.
81 | :::
82 |
83 | ## More
84 |
85 | Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
86 |
--------------------------------------------------------------------------------
/demo/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-quilly",
3 | "version": "1.1.6",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vue-tsc && vite build",
8 | "preview": "vite preview",
9 | "docs:dev": "vitepress dev docs",
10 | "docs:build": "vitepress build docs",
11 | "docs:preview": "vitepress preview docs"
12 | },
13 | "files": [
14 | "dist",
15 | "src/components/"
16 | ],
17 | "author": {
18 | "name": "Oleksandr Shevchuk",
19 | "email": "alekswebnet@gmail.com"
20 | },
21 | "license": "MIT",
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/alekswebnet/vue-quilly.git"
25 | },
26 | "homepage": "https://github.com/alekswebnet/vue-quilly",
27 | "bugs": {
28 | "url": "https://github.com/alekswebnet/vue-quilly/issues"
29 | },
30 | "keywords": [
31 | "quill",
32 | "quill2",
33 | "wysiwyg",
34 | "rich-text",
35 | "html-editor",
36 | "vue3",
37 | "vue",
38 | "vuejs",
39 | "vue-component",
40 | "vue-quill",
41 | "nuxt",
42 | "nuxt4"
43 | ],
44 | "main": "./dist/vue-quilly.umd.cjs",
45 | "module": "./dist/vue-quilly.js",
46 | "types": "./dist/index.d.ts",
47 | "exports": {
48 | ".": {
49 | "import": {
50 | "types": "./dist/index.d.ts",
51 | "default": "./dist/vue-quilly.js"
52 | },
53 | "require": {
54 | "types": "./dist/index.d.ts",
55 | "default": "./dist/vue-quilly.umd.cjs"
56 | }
57 | }
58 | },
59 | "devDependencies": {
60 | "@types/node": "^24.10.1",
61 | "@vitejs/plugin-vue": "^6.0.2",
62 | "typescript": "^5.9.3",
63 | "vite": "^7.2.6",
64 | "vite-plugin-dts": "^4.5.4",
65 | "vitepress": "2.0.0-alpha.15",
66 | "vue-tsc": "^3.1.6"
67 | },
68 | "dependencies": {
69 | "quill": "^2.0.3",
70 | "vue": "^3.5.25"
71 | },
72 | "packageManager": "pnpm@10.25.0"
73 | }
--------------------------------------------------------------------------------
/docs/examples/bubble-theme.md:
--------------------------------------------------------------------------------
1 | # Bubble Theme Editor
2 |
3 | Lightweight editor with the Bubble theme that shows toolbar on text selection.
4 |
5 | ## Features
6 |
7 | - Medium-style inline toolbar
8 | - Appears on text selection
9 | - Same formatting capabilities as Snow theme
10 | - Cleaner, more minimalist interface
11 |
12 | ## Code Example
13 |
14 | ```vue
15 |
48 |
49 |
50 |
55 |
56 | ```
57 |
58 | ## Installation
59 |
60 | Install the required dependencies:
61 |
62 | ```bash
63 | pnpm add vue-quilly quill@2 katex
64 | ```
65 |
66 | ## Usage Tips
67 |
68 | The bubble theme is perfect for:
69 | - Minimal, distraction-free writing interfaces
70 | - Mobile-friendly editors
71 | - Inline content editing
72 | - Medium-style blogging platforms
73 |
74 | ## Resources
75 |
76 | - [View Full Source Code](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/DefaultEditorBubble.vue)
77 | - [Try Live Demo](https://vue-quilly.vercel.app/)
78 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitepress'
2 |
3 | // https://vitepress.dev/reference/site-config
4 | export default defineConfig({
5 | title: "Vue Quilly Docs",
6 | description: "Documentation for vue-quilly",
7 | head: [
8 | ['link', { rel: 'icon', href: 'data:image/svg+xml,' }]
9 | ],
10 | themeConfig: {
11 | // https://vitepress.dev/reference/default-theme-config
12 | logo: 'data:image/svg+xml,',
13 | nav: [
14 | { text: 'Home', link: '/' },
15 | { text: 'Guide', link: '/guide/getting-started' },
16 | { text: 'API', link: '/api/component' },
17 | { text: 'Examples', link: '/examples/' },
18 | { text: 'Support', link: 'https://ko-fi.com/oleksandrshevchuk' }
19 | ],
20 |
21 | sidebar: [
22 | {
23 | text: 'Guide',
24 | items: [
25 | { text: 'Getting Started', link: '/guide/getting-started' },
26 | { text: 'Installation', link: '/guide/installation' },
27 | { text: 'Basic Usage', link: '/guide/basic-usage' }
28 | ]
29 | },
30 | {
31 | text: 'API Reference',
32 | items: [
33 | { text: 'Component API', link: '/api/component' },
34 | { text: 'Events', link: '/api/events' },
35 | { text: 'TypeScript Types', link: '/api/types' }
36 | ]
37 | },
38 | {
39 | text: 'Examples',
40 | items: [
41 | { text: 'Overview', link: '/examples/' },
42 | { text: 'Snow Theme', link: '/examples/snow-theme' },
43 | { text: 'Bubble Theme', link: '/examples/bubble-theme' },
44 | { text: 'Semantic HTML', link: '/examples/semantic-html' },
45 | { text: 'Image Resize', link: '/examples/image-resize' },
46 | { text: 'Custom Editor', link: '/examples/custom-editor' }
47 | ]
48 | }
49 | ],
50 |
51 | socialLinks: [
52 | { icon: 'github', link: 'https://github.com/alekswebnet/vue-quilly' }
53 | ]
54 | }
55 | })
56 |
--------------------------------------------------------------------------------
/docs/examples/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: deep
3 | ---
4 |
5 | # Examples
6 |
7 | This section showcases different editor configurations and use cases built with vue-quilly. Each example demonstrates specific features and integration patterns you can use in your projects.
8 |
9 | ## Available Examples
10 |
11 | ### [Snow Theme Editor](/examples/snow-theme)
12 | The classic Quill editor with the Snow theme, featuring a full toolbar with all formatting options.
13 |
14 | **Features:**
15 | - Complete toolbar with all formatting options
16 | - Formula support with KaTeX
17 | - Image and video embedding
18 | - Font, size, and color customization
19 |
20 | ### [Bubble Theme Editor](/examples/bubble-theme)
21 | Lightweight editor with the Bubble theme that shows toolbar on text selection.
22 |
23 | **Features:**
24 | - Medium-style inline toolbar
25 | - Appears on text selection
26 | - Same formatting capabilities as Snow theme
27 | - Cleaner, more minimalist interface
28 |
29 | ### [Semantic HTML Editor](/examples/semantic-html)
30 | Editor configured to output clean, semantic HTML without Quill-specific classes.
31 |
32 | **Features:**
33 | - Clean HTML output (e.g., `` instead of `
` instead of `
63 |
66 | ```
67 |
68 | ```html [Semantic HTML]
69 | Heading
70 |
73 | ```
74 |
75 | :::
76 |
77 | ## Benefits
78 |
79 | ### SEO Advantages
80 | - Search engines better understand semantic markup
81 | - Proper heading hierarchy improves content structure
82 | - Clean HTML signals content quality
83 |
84 | ### Accessibility
85 | - Screen readers work better with semantic HTML
86 | - Proper heading tags create better navigation
87 | - Better ARIA compatibility
88 |
89 | ### Maintainability
90 | - Cleaner code without framework-specific classes
91 | - Easier to style with custom CSS
92 | - Better compatibility with other systems
93 |
94 | ## Use Cases
95 |
96 | - Blog posts
97 | - CMS content
98 | - Email templates
99 | - Exported documents
100 |
101 | ## Installation
102 |
103 | ```bash
104 | pnpm add vue-quilly quill@2
105 | ```
106 |
107 | ## Resources
108 |
109 | - [View Full Source Code](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/SemanticHTMLEditor.vue)
110 | - [Try Live Demo](https://vue-quilly.vercel.app/)
111 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Created by https://www.toptal.com/developers/gitignore/api/vue,vuejs,node
4 | # Edit at https://www.toptal.com/developers/gitignore?templates=vue,vuejs,node
5 |
6 | ### Node ###
7 | # Logs
8 | logs
9 | *.log
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | lerna-debug.log*
14 |
15 | # Diagnostic reports (https://nodejs.org/api/report.html)
16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
17 |
18 | # Runtime data
19 | pids
20 | *.pid
21 | *.seed
22 | *.pid.lock
23 |
24 | # Directory for instrumented libs generated by jscoverage/JSCover
25 | lib-cov
26 |
27 | # Coverage directory used by tools like istanbul
28 | coverage
29 | *.lcov
30 |
31 | # nyc test coverage
32 | .nyc_output
33 |
34 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
35 | .grunt
36 |
37 | # Bower dependency directory (https://bower.io/)
38 | bower_components
39 |
40 | # node-waf configuration
41 | .lock-wscript
42 |
43 | # Compiled binary addons (https://nodejs.org/api/addons.html)
44 | build/Release
45 |
46 | # Dependency directories
47 | node_modules/
48 | jspm_packages/
49 |
50 | # TypeScript v1 declaration files
51 | typings/
52 |
53 | # TypeScript cache
54 | *.tsbuildinfo
55 |
56 | # Optional npm cache directory
57 | .npm
58 |
59 | # Optional eslint cache
60 | .eslintcache
61 |
62 | # Microbundle cache
63 | .rpt2_cache/
64 | .rts2_cache_cjs/
65 | .rts2_cache_es/
66 | .rts2_cache_umd/
67 |
68 | # Optional REPL history
69 | .node_repl_history
70 |
71 | # Output of 'npm pack'
72 | *.tgz
73 |
74 | # Yarn Integrity file
75 | .yarn-integrity
76 |
77 | # dotenv environment variables file
78 | .env
79 | .env.test
80 | .env*.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 |
89 | # Nuxt.js build / generate output
90 | .nuxt
91 | dist
92 |
93 | # Gatsby files
94 | .cache/
95 | # Comment in the public line in if your project uses Gatsby and not Next.js
96 | # https://nextjs.org/blog/next-9-1#public-directory-support
97 | # public
98 |
99 | # vuepress build output
100 | .vuepress/dist
101 |
102 | # Serverless directories
103 | .serverless/
104 |
105 | # FuseBox cache
106 | .fusebox/
107 |
108 | # DynamoDB Local files
109 | .dynamodb/
110 |
111 | # TernJS port file
112 | .tern-port
113 |
114 | # Stores VSCode versions used for testing VSCode extensions
115 | .vscode-test
116 |
117 | ### Vue ###
118 | # gitignore template for Vue.js projects
119 | #
120 | # Recommended template: Node.gitignore
121 |
122 | # TODO: where does this rule come from?
123 | docs/_book
124 |
125 | # TODO: where does this rule come from?
126 | test/
127 |
128 | ### Vuejs ###
129 | # Recommended template: Node.gitignore
130 |
131 | dist/
132 | npm-debug.log
133 | yarn-error.log
134 |
135 | # End of https://www.toptal.com/developers/gitignore/api/vue,vuejs,node
--------------------------------------------------------------------------------
/.github/copilot-instructions.md:
--------------------------------------------------------------------------------
1 | # AI Coding Assistant Instructions for vue-quilly
2 |
3 | ## Project Overview
4 | vue-quilly is a Vue 3 component wrapper for Quill v2, providing a WYSIWYG editor with the following key features:
5 | - Uses `quill/core` for minimal bundle size, allowing selective module imports
6 | - Supports both HTML and Delta formats for content manipulation
7 | - TypeScript support with full type definitions
8 | - Nuxt 4 compatibility
9 |
10 | ## Architecture
11 |
12 | ### Core Component
13 | The main `QuillyEditor.vue` component follows these patterns:
14 | - Uses Vue 3 `
43 |
44 |
45 |
55 | MODEL:
56 | {{ model }}
57 |
58 |
59 | CONTENTS:
60 | {{ quill?.getContents() }}
61 |
78 |
79 | LAST CHANGE:
80 | {{ editorDelta }}
81 | CURRENT SELECTION:
82 | {{ editorRange }}
83 |
84 | CONTENT LENGTH:
85 | {{ quill?.getLength() }}
86 | Readonly:
87 |
88 |
89 |
--------------------------------------------------------------------------------
/docs/examples/custom-editor.md:
--------------------------------------------------------------------------------
1 | # Custom Editor (Core Build)
2 |
3 | Minimal custom editor using `quill/core` with only specific blots registered.
4 |
5 | ## Features
6 |
7 | - Minimal bundle size (uses `quill/core`)
8 | - Custom blots (Bold, Italic, Headers)
9 | - External toolbar controls
10 | - Perfect for custom implementations
11 |
12 | ## Code Example
13 |
14 | ```vue
15 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
76 |
77 | ```
78 |
79 | ## Why Use Core Build?
80 |
81 | ### Bundle Size Benefits
82 |
83 | The core build significantly reduces bundle size by excluding unused modules:
84 |
85 | - **Full build**: ~250KB minified
86 | - **Core build**: ~100KB minified
87 |
88 | You only import what you need!
89 |
90 | ### Use Cases
91 |
92 | Perfect for:
93 | - Custom editor implementations
94 | - Mobile-first applications where size matters
95 | - Embedded widgets with limited features
96 | - Learning Quill internals
97 |
98 | ## Creating Custom Blots
99 |
100 | Custom blots give you complete control over formatting:
101 |
102 | ```typescript
103 | class CustomBlot extends Inline {
104 | static blotName = 'custom'
105 | static tagName = 'span'
106 | static className = 'my-custom-class'
107 | }
108 |
109 | Quill.register(CustomBlot)
110 | ```
111 |
112 | ## Installation
113 |
114 | ```bash
115 | pnpm add vue-quilly quill@2 parchment
116 | ```
117 |
118 | ## Resources
119 |
120 | - [View Full Source Code](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/CustomEditor.vue)
121 | - [Quill Core Build Documentation](https://quilljs.com/docs/installation#core-build)
122 | - [Parchment Documentation](https://github.com/quilljs/parchment) - Blot framework
123 | - [Try Live Demo](https://vue-quilly.vercel.app/)
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-quilly
2 |
3 | Tiny Vue component, that helps to create [Quill v2](https://quilljs.com/) based WYSIWYG editors in Vue-powered apps.
4 |
5 | [](https://www.npmjs.com/package/vue-quilly)
6 | [](https://www.npmjs.com/package/vue-quilly?activeTab=code)
7 | [](https://www.npmjs.com/package/vue-quilly?activeTab=code)
8 | [](https://github.com/alekswebnet/vue-quilly?tab=readme-ov-file#license)
9 |
10 | ## Features
11 |
12 | - 🚀 Built on top of [Quill v2](https://github.com/quilljs/quill) and Vue 3
13 | - 📦 Uses `quill/core` to prevent importing all Quill modules (minimal bundle size)
14 | - 🔄 Works with both HTML and Quill Delta format
15 | - 🔷 TypeScript support
16 | - ⚙️ Highly customizable - build your own editor
17 | - ⚡ Framework ready - works with Vue 3 and Nuxt 4
18 |
19 | ## Documentation
20 |
21 | 📖 **[Full Documentation](https://vue-quilly-docs.vercel.app/)**
22 |
23 | - [Getting Started](https://vue-quilly-docs.vercel.app/guide/getting-started)
24 | - [Installation Guide](https://vue-quilly-docs.vercel.app/guide/installation)
25 | - [Basic Usage](https://vue-quilly-docs.vercel.app/guide/basic-usage)
26 | - [API Reference](https://vue-quilly-docs.vercel.app/api/component)
27 | - [Examples](https://vue-quilly-docs.vercel.app/examples/)
28 |
29 | ## Quick Start
30 |
31 | ### Installation
32 |
33 | ```bash
34 | npm install vue-quilly quill@2
35 | # or
36 | pnpm add vue-quilly quill@2
37 | # or
38 | yarn add vue-quilly quill@2
39 | ```
40 |
41 | ### Basic Usage
42 |
43 | ```vue
44 |
69 |
70 |
71 |
72 |
73 | ```
74 |
75 | ## Live Demo
76 |
77 | 🎯 **[Try it live](https://vue-quilly.vercel.app/)** - See various editors built with `vue-quilly`
78 |
79 | ## Examples
80 |
81 | - [Demo Source Code](https://github.com/alekswebnet/vue-quilly/tree/main/demo) - Complete examples with different configurations
82 | - [Nuxt 4 Integration](https://github.com/alekswebnet/vue-quilly/tree/main/nuxt) - SSR setup example
83 | - [Browser CDN Setup](https://codepen.io/redrobot753/pen/VwJwPLP) - CodePen example
84 |
85 | ## Star History
86 |
87 | [](https://www.star-history.com/#alekswebnet/vue-quilly&type=date&legend=top-left)
88 |
89 | ## Support
90 |
91 | If you find `vue-quilly` useful and want to support its development:
92 |
93 | [](https://ko-fi.com/oleksandrshevchuk)
94 |
95 | ❤️ Your support helps with maintenance, bug fixes, and long-term improvements.
96 |
97 | ## License
98 |
99 | [MIT](https://choosealicense.com/licenses/mit/)
100 |
--------------------------------------------------------------------------------
/src/components/QuillyEditor.vue:
--------------------------------------------------------------------------------
1 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "vue-quilly"
7 | text: ""
8 | tagline: Tiny Vue component for creating Quill v2 based WYSIWYG editors
9 | actions:
10 | - theme: brand
11 | text: Get Started
12 | link: /guide/getting-started
13 | - theme: alt
14 | text: View on GitHub
15 | link: https://github.com/alekswebnet/vue-quilly
16 |
17 | features:
18 | - title: 🚀 Quill v2 Support
19 | details: Built on top of Quill v2 and Vue 3, providing modern rich text editing capabilities with the latest features.
20 | - title: 📦 Minimal Bundle Size
21 | details: Uses quill/core to prevent importing all Quill modules. Import only what you need to keep your bundle small.
22 | - title: 🔷 TypeScript Support
23 | details: Full TypeScript definitions included for better development experience, type safety, and IntelliSense support.
24 | - title: 🔄 Dual Format Support
25 | details: Works with both HTML and Quill Delta format. Use one or both formats to manipulate editor content.
26 | - title: ⚙️ Customizable
27 | details: Not an all-in-one solution. Build your own editor that matches your exact needs with flexible configuration.
28 | - title: ⚡ Framework Ready
29 | details: Works seamlessly with Vue 3 and Nuxt 4. SSR compatible with proper client-side initialization setup.
30 | ---
31 |
32 | ## Quick Start
33 |
34 | Install vue-quilly and Quill v2:
35 |
36 | ::: code-group
37 |
38 | ```bash [npm]
39 | npm install vue-quilly quill@2
40 | ```
41 |
42 | ```bash [pnpm]
43 | pnpm add vue-quilly quill@2
44 | ```
45 |
46 | ```bash [yarn]
47 | yarn add vue-quilly quill@2
48 | ```
49 |
50 | :::
51 |
52 | Use in your Vue component:
53 |
54 | ```vue
55 |
80 |
81 |
82 |
83 |
84 | ```
85 |
86 | ## Why vue-quilly?
87 |
88 | vue-quilly is designed to be a flexible foundation for building custom Quill editors in Vue applications:
89 |
90 | - **Customizable** - Requires Quill configuration, giving you full control over features.
91 | - **Minimal footprint** - Import only the Quill modules you need to keep bundle size small
92 | - **Flexible formats** - Work with HTML or Delta format, or use both for maximum flexibility
93 | - **Full control** - Access the Quill instance directly for advanced customization and features
94 |
95 | ## Examples
96 |
97 | Check out live examples and learn from real implementations:
98 |
99 | - 🚀 [Live Demo](https://vue-quilly.vercel.app/) - See various editors built with vue-quilly
100 | - 📚 [Demo Source Code](https://github.com/alekswebnet/vue-quilly/tree/main/demo) - Complete examples with source code
101 | - ⚡ [Nuxt 4 Example](https://github.com/alekswebnet/vue-quilly/tree/main/nuxt) - SSR integration guide
102 |
103 | ## Star History
104 |
105 | [](https://www.star-history.com/#alekswebnet/vue-quilly&type=date&legend=top-left)
106 |
107 | ## Support the Project
108 |
109 | If you find vue-quilly useful and want to support its development:
110 |
111 | [](https://ko-fi.com/oleksandrshevchuk)
112 |
113 | ❤️ Your support helps with maintenance, bug fixes, and long-term improvements.
114 |
115 |
--------------------------------------------------------------------------------
/demo/src/components/CustomEditor.vue:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
69 | Model value:
70 | {{ model }}
71 |
72 |
73 | Contents:
74 | {{ quill?.getContents() }}
75 |
92 |
93 | SEMANTIC HTML:
94 | {{ quill?.getSemanticHTML() }}
95 | Last change:
96 | {{ editorDelta }}
97 | Current selection:
98 | {{ editorRange }}
99 |
100 | Content lenght:
101 | {{ quill?.getLength() }}
102 | Readonly:
103 |
104 |
105 |
--------------------------------------------------------------------------------
/demo/src/App.vue:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
58 |
vue-quilly
59 |
Tiny Vue component, that helps to create Quill v2 based WYSIWYG editors
60 |
61 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/demo/src/components/DefaultEditorSnow.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
57 | MODEL:
58 | {{ model }}
59 |
60 |
61 | CONTENTS:
62 | {{ quill?.getContents() }}
63 |
80 |
81 | SEMANTIC HTML:
82 | {{ quill?.getSemanticHTML() }}
83 | LAST CHANGE:
84 | {{ editorDelta }}
85 | CURRENT SELECTION:
86 | {{ editorRange }}
87 |
88 | CONTENT LENGTH:
89 | {{ quill?.getLength() }}
90 | Readonly:
91 |
92 |
93 |
--------------------------------------------------------------------------------
/demo/src/components/DefaultEditorBubble.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
57 | MODEL:
58 | {{ model }}
59 |
60 |
61 | CONTENTS:
62 | {{ quill?.getContents() }}
63 |
80 |
81 | SEMANTIC HTML:
82 | {{ quill?.getSemanticHTML() }}
83 | LAST CHANGE:
84 | {{ editorDelta }}
85 | CURRENT SELECTION:
86 | {{ editorRange }}
87 |
88 | CONTENT LENGTH:
89 | {{ quill?.getLength() }}
90 | Readonly:
91 |
92 |
93 |
--------------------------------------------------------------------------------
/nuxt/app/components/CompleteEditor.vue:
--------------------------------------------------------------------------------
1 |
48 |
49 |
50 |
59 |
60 | MODEL:
61 | {{ model }}
62 |
63 |
64 | CONTENTS:
65 | {{ quill?.getContents() }}
66 |
83 |
84 | LAST CHANGE:
85 | {{ editorDelta }}
86 | CURRENT SELECTION:
87 | {{ editorRange }}
88 |
89 | CONTENT LENGTH:
90 | {{ quill?.getLength() }}
91 | Readonly:
92 |
93 |
--------------------------------------------------------------------------------
/docs/api/component.md:
--------------------------------------------------------------------------------
1 | # Component API
2 |
3 | The `QuillyEditor` component provides a Vue 3 wrapper for Quill v2 with full TypeScript support.
4 |
5 | ## Props
6 |
7 | ### modelValue
8 |
9 | - **Type:** `string | null`
10 | - **Default:** `null`
11 | - **Required:** No
12 |
13 | The HTML content of the editor. Used with `v-model` for two-way data binding.
14 |
15 | ```vue
16 |
17 | ```
18 |
19 | The content is automatically synced bidirectionally:
20 | - Changes in the editor update the `modelValue`
21 | - External changes to `modelValue` update the editor content
22 |
23 | ### options
24 |
25 | - **Type:** `QuillOptions`
26 | - **Default:** `{}`
27 | - **Required:** No
28 |
29 | Quill editor initialization options. Supports all [Quill configuration options](https://quilljs.com/docs/configuration/).
30 |
31 | ```vue
32 |
47 |
48 |
49 |
50 |
51 | ```
52 |
53 | **Common options:**
54 |
55 | | Option | Type | Description |
56 | |--------|------|-------------|
57 | | `theme` | `string` | Theme name (`'snow'`, `'bubble'`, or custom) |
58 | | `placeholder` | `string` | Placeholder text when editor is empty |
59 | | `readOnly` | `boolean` | Whether editor is read-only |
60 | | `modules` | `object` | Quill modules configuration (toolbar, clipboard, etc.) |
61 | | `formats` | `string[]` | Allowed formats whitelist |
62 | | `bounds` | `HTMLElement \| string` | DOM boundary for editor |
63 | | `scrollingContainer` | `HTMLElement \| string` | Scrolling container element |
64 |
65 | ### isSemanticHtmlModel
66 |
67 | - **Type:** `boolean`
68 | - **Default:** `false`
69 | - **Required:** No
70 |
71 | When `true`, the component outputs clean semantic HTML without Quill-specific classes.
72 |
73 | ```vue
74 |
78 | ```
79 |
80 | **Comparison:**
81 |
82 | ::: code-group
83 |
84 | ```html [Regular HTML]
85 |
86 | Text
87 |
88 | ```
89 |
90 | ```html [Semantic HTML]
91 |
92 | Text
93 |
94 | ```
95 |
96 | :::
97 |
98 | **Benefits:**
99 | - Better SEO
100 | - Improved accessibility
101 | - Cleaner HTML for external use
102 | - Easier to style with custom CSS
103 |
104 | ## Methods
105 |
106 | The component exposes methods via template refs.
107 |
108 | ### initialize(QuillClass)
109 |
110 | Initializes the Quill editor instance. Must be called after component mount.
111 |
112 | **Parameters:**
113 | - `QuillClass`: `typeof Quill` - The Quill constructor class
114 |
115 | **Returns:** `Quill` - The initialized Quill instance
116 |
117 | **Example:**
118 |
119 | ```vue
120 |
136 |
137 |
138 |
139 |
140 | ```
141 |
142 | ## Usage Example
143 |
144 | Complete example with all features:
145 |
146 | ```vue
147 |
216 |
217 |
218 |
229 |
230 | ```
231 |
232 | ## TypeScript Support
233 |
234 | The component is fully typed with TypeScript:
235 |
236 | ```typescript
237 | import type { QuillyEditor } from 'vue-quilly'
238 | import type { QuillOptions, Delta, Range, EmitterSource } from 'quill/core'
239 |
240 | // Component type
241 | const editor = ref>()
242 |
243 | // Quill instance type
244 | let quill: Quill | undefined
245 | ```
246 |
247 | ## See Also
248 |
249 | - [Events](/api/events) - All available events
250 | - [TypeScript Types](/api/types) - Type definitions
251 | - [Examples](/examples/) - Practical examples
252 |
--------------------------------------------------------------------------------
/demo/src/components/ImageResizeEditor.vue:
--------------------------------------------------------------------------------
1 |
57 |
58 |
59 |
68 | MODEL:
69 | {{ model }}
70 |
71 |
72 | CONTENTS:
73 | {{ quill?.getContents() }}
74 |
91 |
92 | SEMANTIC HTML:
93 | {{ quill?.getSemanticHTML() }}
94 | LAST CHANGE:
95 | {{ editorDelta }}
96 | CURRENT SELECTION:
97 | {{ editorRange }}
98 |
99 | CONTENT LENGTH:
100 | {{ quill?.getLength() }}
101 | Readonly:
102 |
103 |
104 |
--------------------------------------------------------------------------------
/docs/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | Welcome to vue-quilly! This guide will help you get started with building rich text editors in your Vue 3 applications.
4 |
5 | ## What is vue-quilly?
6 |
7 | vue-quilly is a lightweight Vue 3 component that wraps [Quill v2](https://quilljs.com/), the powerful rich text editor. It provides:
8 |
9 | - 🎯 **Simple integration** - Easy to add to any Vue 3 project
10 | - 📦 **Minimal bundle** - Uses `quill/core` for tree-shaking
11 | - 🔷 **TypeScript support** - Full type definitions included
12 | - 🔄 **Dual format** - Works with HTML and Delta formats
13 | - ⚙️ **Highly customizable** - Build exactly what you need
14 |
15 | ## Philosophy
16 |
17 | vue-quilly is **not** an all-in-one editor solution. Instead, it's a flexible foundation that lets you:
18 |
19 | - Import only the Quill modules you need
20 | - Build custom editors tailored to your use case
21 | - Maintain full control over features and styling
22 | - Keep your bundle size minimal
23 |
24 | ## Quick Example
25 |
26 | Here's a minimal example to get you started:
27 |
28 | ```vue
29 |
53 |
54 |
55 |
60 |
61 | ```
62 |
63 | That's it! You now have a working rich text editor.
64 |
65 | ## Core Concepts
66 |
67 | ### 1. Quill Initialization
68 |
69 | The editor requires explicit initialization:
70 |
71 | ```typescript
72 | const editor = ref>()
73 | let quill: Quill | undefined
74 |
75 | onMounted(() => {
76 | quill = editor.value?.initialize(Quill)
77 | })
78 | ```
79 |
80 | This gives you control over when and how Quill is initialized.
81 |
82 | **Accessing Quill instance:**
83 |
84 | Once initialized, you can access the full Quill API:
85 |
86 | ```typescript
87 | onMounted(() => {
88 | quill = editor.value?.initialize(Quill)
89 |
90 | // Use Quill methods
91 | quill?.focus()
92 | quill?.setSelection(0, 0)
93 |
94 | // Get content
95 | const text = quill?.getText()
96 | const delta = quill?.getContents()
97 |
98 | // Format text
99 | quill?.formatText(0, 5, 'bold', true)
100 | })
101 | ```
102 |
103 | **Using Quill plugins:**
104 |
105 | You can register and use Quill plugins by registering them before initialization:
106 |
107 | ```typescript
108 | import Quill from 'quill'
109 | import ImageResize from 'quill-resize-module'
110 |
111 | onMounted(() => {
112 | // Register image resize plugin
113 | Quill.register('modules/ImageResize', ImageResize)
114 |
115 | // Initialize editor with the plugin
116 | quill = editor.value?.initialize(Quill)
117 | })
118 | ```
119 |
120 | **Plugin configuration in options:**
121 |
122 | ```typescript
123 | const options = {
124 | theme: 'snow',
125 | modules: {
126 | toolbar: [['bold', 'italic'], ['image']],
127 | ImageResize: {
128 | modules: ['Resize', 'DisplaySize']
129 | }
130 | }
131 | }
132 | ```
133 |
134 | **Example with KaTeX (formula support):**
135 |
136 | ```typescript
137 | import Quill from 'quill'
138 | import katex from 'katex'
139 | import 'katex/dist/katex.min.css'
140 |
141 | onMounted(() => {
142 | // Make KaTeX available globally for Quill
143 | (window.katex as typeof katex) = katex
144 |
145 | // Initialize editor - formula module is built-in
146 | quill = editor.value?.initialize(Quill)
147 | })
148 | ```
149 |
150 | **Example with custom formats/blots:**
151 |
152 | ```typescript
153 | import Quill from 'quill/core'
154 | import { type BlotConstructor } from 'parchment'
155 |
156 | const Inline = Quill.import('blots/inline') as BlotConstructor
157 |
158 | // Create custom blot
159 | class CustomBlot extends Inline {
160 | static blotName = 'custom'
161 | static tagName = 'span'
162 | static className = 'my-custom-class'
163 | }
164 |
165 | // Register before initialization
166 | Quill.register(CustomBlot)
167 |
168 | onMounted(() => {
169 | quill = editor.value?.initialize(Quill)
170 | })
171 | ```
172 |
173 | ### 2. Content Formats
174 |
175 | vue-quilly supports two content formats:
176 |
177 | **HTML Format (v-model):**
178 | ```vue
179 |
180 | ```
181 |
182 | **Delta Format (Quill API):**
183 | ```typescript
184 | import { Delta } from 'quill/core'
185 |
186 | quill.setContents(
187 | new Delta()
188 | .insert('Hello ')
189 | .insert('World', { bold: true })
190 | )
191 | ```
192 |
193 | ### 3. Configuration
194 |
195 | Configure the editor using Quill's options:
196 |
197 | ```typescript
198 | const options = {
199 | theme: 'snow', // or 'bubble'
200 | placeholder: 'Write...',
201 | readOnly: false,
202 | modules: {
203 | toolbar: [/* ... */] // Customize toolbar
204 | }
205 | }
206 | ```
207 |
208 | ### 4. Event Handling
209 |
210 | Listen to editor events:
211 |
212 | ```vue
213 |
219 | ```
220 |
221 | ## Next Steps
222 |
223 | Now that you understand the basics, continue with:
224 |
225 | 1. **[Installation](/guide/installation)** - Set up vue-quilly in your project
226 | 2. **[Basic Usage](/guide/basic-usage)** - Learn common patterns and features
227 | 3. **[Examples](/examples/)** - See practical implementations
228 | 4. **[API Reference](/api/component)** - Detailed API documentation
229 |
230 | ## Learning Resources
231 |
232 | - [Quill Documentation](https://quilljs.com/docs/) - Official Quill docs
233 | - [Live Demo](https://vue-quilly.vercel.app/) - Try vue-quilly online
234 | - [GitHub Repository](https://github.com/alekswebnet/vue-quilly) - Source code and issues
235 | - [Demo Source](https://github.com/alekswebnet/vue-quilly/tree/main/demo) - Example implementations
236 |
237 | ## Browser Support
238 |
239 | vue-quilly supports the same browsers as Vue 3 and Quill v2:
240 |
241 | - Chrome (latest)
242 | - Firefox (latest)
243 | - Safari (latest)
244 | - Edge (latest)
245 |
246 | ## Requirements
247 |
248 | - Vue 3.0+
249 | - Quill 2.0+
250 |
251 | ## Get Help
252 |
253 | If you need help:
254 |
255 | - 📖 Check the [API documentation](/api/component)
256 | - 💡 Browse [examples](/examples/)
257 | - 🐛 Report issues on [GitHub](https://github.com/alekswebnet/vue-quilly/issues)
258 |
259 | Ready to install? Head to the [Installation guide](/guide/installation)!
260 |
--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/vue.js:
--------------------------------------------------------------------------------
1 | import {
2 | BaseTransition,
3 | BaseTransitionPropsValidators,
4 | Comment,
5 | DeprecationTypes,
6 | EffectScope,
7 | ErrorCodes,
8 | ErrorTypeStrings,
9 | Fragment,
10 | KeepAlive,
11 | ReactiveEffect,
12 | Static,
13 | Suspense,
14 | Teleport,
15 | Text,
16 | TrackOpTypes,
17 | Transition,
18 | TransitionGroup,
19 | TriggerOpTypes,
20 | VueElement,
21 | assertNumber,
22 | callWithAsyncErrorHandling,
23 | callWithErrorHandling,
24 | camelize,
25 | capitalize,
26 | cloneVNode,
27 | compatUtils,
28 | compile,
29 | computed,
30 | createApp,
31 | createBaseVNode,
32 | createBlock,
33 | createCommentVNode,
34 | createElementBlock,
35 | createHydrationRenderer,
36 | createPropsRestProxy,
37 | createRenderer,
38 | createSSRApp,
39 | createSlots,
40 | createStaticVNode,
41 | createTextVNode,
42 | createVNode,
43 | customRef,
44 | defineAsyncComponent,
45 | defineComponent,
46 | defineCustomElement,
47 | defineEmits,
48 | defineExpose,
49 | defineModel,
50 | defineOptions,
51 | defineProps,
52 | defineSSRCustomElement,
53 | defineSlots,
54 | devtools,
55 | effect,
56 | effectScope,
57 | getCurrentInstance,
58 | getCurrentScope,
59 | getCurrentWatcher,
60 | getTransitionRawChildren,
61 | guardReactiveProps,
62 | h,
63 | handleError,
64 | hasInjectionContext,
65 | hydrate,
66 | hydrateOnIdle,
67 | hydrateOnInteraction,
68 | hydrateOnMediaQuery,
69 | hydrateOnVisible,
70 | initCustomFormatter,
71 | initDirectivesForSSR,
72 | inject,
73 | isMemoSame,
74 | isProxy,
75 | isReactive,
76 | isReadonly,
77 | isRef,
78 | isRuntimeOnly,
79 | isShallow,
80 | isVNode,
81 | markRaw,
82 | mergeDefaults,
83 | mergeModels,
84 | mergeProps,
85 | nextTick,
86 | nodeOps,
87 | normalizeClass,
88 | normalizeProps,
89 | normalizeStyle,
90 | onActivated,
91 | onBeforeMount,
92 | onBeforeUnmount,
93 | onBeforeUpdate,
94 | onDeactivated,
95 | onErrorCaptured,
96 | onMounted,
97 | onRenderTracked,
98 | onRenderTriggered,
99 | onScopeDispose,
100 | onServerPrefetch,
101 | onUnmounted,
102 | onUpdated,
103 | onWatcherCleanup,
104 | openBlock,
105 | patchProp,
106 | popScopeId,
107 | provide,
108 | proxyRefs,
109 | pushScopeId,
110 | queuePostFlushCb,
111 | reactive,
112 | readonly,
113 | ref,
114 | registerRuntimeCompiler,
115 | render,
116 | renderList,
117 | renderSlot,
118 | resolveComponent,
119 | resolveDirective,
120 | resolveDynamicComponent,
121 | resolveFilter,
122 | resolveTransitionHooks,
123 | setBlockTracking,
124 | setDevtoolsHook,
125 | setTransitionHooks,
126 | shallowReactive,
127 | shallowReadonly,
128 | shallowRef,
129 | ssrContextKey,
130 | ssrUtils,
131 | stop,
132 | toDisplayString,
133 | toHandlerKey,
134 | toHandlers,
135 | toRaw,
136 | toRef,
137 | toRefs,
138 | toValue,
139 | transformVNodeArgs,
140 | triggerRef,
141 | unref,
142 | useAttrs,
143 | useCssModule,
144 | useCssVars,
145 | useHost,
146 | useId,
147 | useModel,
148 | useSSRContext,
149 | useShadowRoot,
150 | useSlots,
151 | useTemplateRef,
152 | useTransitionState,
153 | vModelCheckbox,
154 | vModelDynamic,
155 | vModelRadio,
156 | vModelSelect,
157 | vModelText,
158 | vShow,
159 | version,
160 | warn,
161 | watch,
162 | watchEffect,
163 | watchPostEffect,
164 | watchSyncEffect,
165 | withAsyncContext,
166 | withCtx,
167 | withDefaults,
168 | withDirectives,
169 | withKeys,
170 | withMemo,
171 | withModifiers,
172 | withScopeId
173 | } from "./chunk-GKNP4RGU.js";
174 | export {
175 | BaseTransition,
176 | BaseTransitionPropsValidators,
177 | Comment,
178 | DeprecationTypes,
179 | EffectScope,
180 | ErrorCodes,
181 | ErrorTypeStrings,
182 | Fragment,
183 | KeepAlive,
184 | ReactiveEffect,
185 | Static,
186 | Suspense,
187 | Teleport,
188 | Text,
189 | TrackOpTypes,
190 | Transition,
191 | TransitionGroup,
192 | TriggerOpTypes,
193 | VueElement,
194 | assertNumber,
195 | callWithAsyncErrorHandling,
196 | callWithErrorHandling,
197 | camelize,
198 | capitalize,
199 | cloneVNode,
200 | compatUtils,
201 | compile,
202 | computed,
203 | createApp,
204 | createBlock,
205 | createCommentVNode,
206 | createElementBlock,
207 | createBaseVNode as createElementVNode,
208 | createHydrationRenderer,
209 | createPropsRestProxy,
210 | createRenderer,
211 | createSSRApp,
212 | createSlots,
213 | createStaticVNode,
214 | createTextVNode,
215 | createVNode,
216 | customRef,
217 | defineAsyncComponent,
218 | defineComponent,
219 | defineCustomElement,
220 | defineEmits,
221 | defineExpose,
222 | defineModel,
223 | defineOptions,
224 | defineProps,
225 | defineSSRCustomElement,
226 | defineSlots,
227 | devtools,
228 | effect,
229 | effectScope,
230 | getCurrentInstance,
231 | getCurrentScope,
232 | getCurrentWatcher,
233 | getTransitionRawChildren,
234 | guardReactiveProps,
235 | h,
236 | handleError,
237 | hasInjectionContext,
238 | hydrate,
239 | hydrateOnIdle,
240 | hydrateOnInteraction,
241 | hydrateOnMediaQuery,
242 | hydrateOnVisible,
243 | initCustomFormatter,
244 | initDirectivesForSSR,
245 | inject,
246 | isMemoSame,
247 | isProxy,
248 | isReactive,
249 | isReadonly,
250 | isRef,
251 | isRuntimeOnly,
252 | isShallow,
253 | isVNode,
254 | markRaw,
255 | mergeDefaults,
256 | mergeModels,
257 | mergeProps,
258 | nextTick,
259 | nodeOps,
260 | normalizeClass,
261 | normalizeProps,
262 | normalizeStyle,
263 | onActivated,
264 | onBeforeMount,
265 | onBeforeUnmount,
266 | onBeforeUpdate,
267 | onDeactivated,
268 | onErrorCaptured,
269 | onMounted,
270 | onRenderTracked,
271 | onRenderTriggered,
272 | onScopeDispose,
273 | onServerPrefetch,
274 | onUnmounted,
275 | onUpdated,
276 | onWatcherCleanup,
277 | openBlock,
278 | patchProp,
279 | popScopeId,
280 | provide,
281 | proxyRefs,
282 | pushScopeId,
283 | queuePostFlushCb,
284 | reactive,
285 | readonly,
286 | ref,
287 | registerRuntimeCompiler,
288 | render,
289 | renderList,
290 | renderSlot,
291 | resolveComponent,
292 | resolveDirective,
293 | resolveDynamicComponent,
294 | resolveFilter,
295 | resolveTransitionHooks,
296 | setBlockTracking,
297 | setDevtoolsHook,
298 | setTransitionHooks,
299 | shallowReactive,
300 | shallowReadonly,
301 | shallowRef,
302 | ssrContextKey,
303 | ssrUtils,
304 | stop,
305 | toDisplayString,
306 | toHandlerKey,
307 | toHandlers,
308 | toRaw,
309 | toRef,
310 | toRefs,
311 | toValue,
312 | transformVNodeArgs,
313 | triggerRef,
314 | unref,
315 | useAttrs,
316 | useCssModule,
317 | useCssVars,
318 | useHost,
319 | useId,
320 | useModel,
321 | useSSRContext,
322 | useShadowRoot,
323 | useSlots,
324 | useTemplateRef,
325 | useTransitionState,
326 | vModelCheckbox,
327 | vModelDynamic,
328 | vModelRadio,
329 | vModelSelect,
330 | vModelText,
331 | vShow,
332 | version,
333 | warn,
334 | watch,
335 | watchEffect,
336 | watchPostEffect,
337 | watchSyncEffect,
338 | withAsyncContext,
339 | withCtx,
340 | withDefaults,
341 | withDirectives,
342 | withKeys,
343 | withMemo,
344 | withModifiers,
345 | withScopeId
346 | };
347 |
--------------------------------------------------------------------------------
/docs/guide/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | This guide covers installing vue-quilly in different environments and setups.
4 |
5 | ## Package Managers
6 |
7 | Install vue-quilly and Quill using your preferred package manager:
8 |
9 | ::: code-group
10 |
11 | ```bash [npm]
12 | npm install vue-quilly quill@2
13 | ```
14 |
15 | ```bash [pnpm]
16 | pnpm add vue-quilly quill@2
17 | ```
18 |
19 | ```bash [yarn]
20 | yarn add vue-quilly quill@2
21 | ```
22 |
23 | :::
24 |
25 | ## Import Methods
26 |
27 | ### Full Build
28 |
29 | Import the full Quill build if you need all modules:
30 |
31 | ```typescript
32 | import Quill from 'quill'
33 | import { QuillyEditor } from 'vue-quilly'
34 | ```
35 |
36 | **Use when:**
37 | - You need most Quill features
38 | - Bundle size is not a primary concern
39 | - Rapid prototyping
40 |
41 | ### Core Build (Recommended)
42 |
43 | Import only the core build and register modules as needed:
44 |
45 | ```typescript
46 | import Quill from 'quill/core'
47 | import { QuillyEditor } from 'vue-quilly'
48 | ```
49 |
50 | **Use when:**
51 | - You want minimal bundle size
52 | - You need specific features only
53 | - Building for production
54 |
55 | **Example with selective imports:**
56 |
57 | ```typescript
58 | import Quill from 'quill/core'
59 | import Toolbar from 'quill/modules/toolbar'
60 | import Bold from 'quill/formats/bold'
61 | import Italic from 'quill/formats/italic'
62 | import Header from 'quill/formats/header'
63 |
64 | Quill.register({
65 | 'modules/toolbar': Toolbar,
66 | 'formats/bold': Bold,
67 | 'formats/italic': Italic,
68 | 'formats/header': Header
69 | })
70 | ```
71 |
72 | ## Styles
73 |
74 | Import Quill CSS styles based on your needs:
75 |
76 | ### Core Styles (Required)
77 |
78 | Always import the core styles:
79 |
80 | ```typescript
81 | import 'quill/dist/quill.core.css'
82 | ```
83 |
84 | ### Theme Styles (Optional)
85 |
86 | Import a theme if you're using one:
87 |
88 | ::: code-group
89 |
90 | ```typescript [Snow Theme]
91 | import 'quill/dist/quill.snow.css'
92 | ```
93 |
94 | ```typescript [Bubble Theme]
95 | import 'quill/dist/quill.bubble.css'
96 | ```
97 |
98 | :::
99 |
100 | **Complete import example:**
101 |
102 | ```typescript
103 | import { QuillyEditor } from 'vue-quilly'
104 | import Quill from 'quill'
105 | import 'quill/dist/quill.snow.css'
106 | ```
107 |
108 | ## Component Registration
109 |
110 | ### Global Registration
111 |
112 | Register globally in your main app file:
113 |
114 | ```typescript
115 | // main.ts
116 | import { createApp } from 'vue'
117 | import { QuillyEditor } from 'vue-quilly'
118 | import App from './App.vue'
119 |
120 | const app = createApp(App)
121 | app.component('QuillyEditor', QuillyEditor)
122 | app.mount('#app')
123 | ```
124 |
125 | Then use it anywhere in your app:
126 |
127 | ```vue
128 |
129 |
130 |
131 | ```
132 |
133 | ### Local Registration
134 |
135 | Import and register in individual components:
136 |
137 | ```vue
138 |
152 |
153 |
154 |
155 |
156 | ```
157 |
158 | **Use local registration when:**
159 | - You only need the editor in specific components
160 | - You want to keep bundle size minimal with tree-shaking
161 | - You prefer explicit imports over global registration
162 |
163 | ### Type Declarations
164 |
165 | Types are automatically available when you import:
166 |
167 | ```typescript
168 | import type { QuillyEditor } from 'vue-quilly'
169 | import type {
170 | QuillOptions,
171 | Delta,
172 | Range
173 | } from 'quill/core'
174 | ```
175 |
176 | ### Nuxt 3/4
177 |
178 | Use dynamic imports with `import.meta.client` check since Quill is browser-only:
179 |
180 | **Component (e.g., `components/Editor.vue`):**
181 |
182 | ```vue
183 |
213 |
214 |
215 |
216 |
217 | ```
218 |
219 | **App/Page (e.g., `app.vue` or `pages/index.vue`):**
220 |
221 | ```vue
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 | ```
230 |
231 | **Key points:**
232 | - Wrap the editor component in `` in your app/page, not in the component itself
233 | - Use `import.meta.client` check before dynamic import in the component
234 | - Import Quill dynamically in `onMounted` hook
235 | - Import types from `quill/core`: `import Quill, { Delta, Range } from 'quill/core'`
236 |
237 | See our [Nuxt example](https://github.com/alekswebnet/vue-quilly/tree/main/nuxt) for a complete implementation.
238 |
239 | ## Additional Modules
240 |
241 | ### KaTeX (for formulas)
242 |
243 | Install KaTeX for formula support:
244 |
245 | ```bash
246 | pnpm add katex
247 | ```
248 |
249 | ```typescript
250 | import katex from 'katex'
251 | import 'katex/dist/katex.min.css'
252 |
253 | // Make KaTeX available globally
254 | (window.katex as typeof katex) = katex
255 | ```
256 |
257 | ### Image Resize
258 |
259 | Install the image resize module:
260 |
261 | ```bash
262 | pnpm add quill-image-resize-module
263 | ```
264 |
265 | ```typescript
266 | import 'quill-image-resize-module'
267 |
268 | const options = {
269 | modules: {
270 | imageResize: {
271 | modules: ['Resize', 'DisplaySize', 'Toolbar']
272 | }
273 | }
274 | }
275 | ```
276 |
277 | ## CDN Usage
278 |
279 | For quick prototyping or simple pages, use CDN:
280 |
281 | ```html
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
305 |
306 |
328 |
329 |
330 | ```
331 |
332 | [Try on CodePen](https://codepen.io/redrobot753/pen/VwJwPLP)
333 |
334 | ## Troubleshooting
335 |
336 | ### Module Not Found
337 |
338 | If you get module not found errors:
339 |
340 | ```bash
341 | # Clear node_modules and reinstall
342 | rm -rf node_modules package-lock.json
343 | npm install
344 | ```
345 |
346 | ## Next Steps
347 |
348 | - [Basic Usage](/guide/basic-usage) - Learn how to use the editor
349 | - [Examples](/examples/) - See practical implementations
350 | - [API Reference](/api/component) - Detailed documentation
351 |
352 | ## Version Compatibility
353 |
354 | | vue-quilly | Quill | Vue |
355 | |-----------|-------|-----|
356 | | 1.x | 2.x | 3.x |
357 |
358 | Always use Quill v2 with vue-quilly.
359 |
--------------------------------------------------------------------------------
/docs/api/events.md:
--------------------------------------------------------------------------------
1 | # Events
2 |
3 | The `QuillyEditor` component emits various events that allow you to respond to user interactions and content changes.
4 |
5 | ## Event List
6 |
7 | All events are fully typed for TypeScript support.
8 |
9 | ### update:modelValue
10 |
11 | Emitted when the editor content changes (for `v-model` binding).
12 |
13 | **Type:**
14 | ```typescript
15 | (value: string) => void
16 | ```
17 |
18 | **Parameters:**
19 | - `value`: `string` - The updated HTML content
20 |
21 | **Example:**
22 | ```vue
23 |
30 |
31 |
32 |
36 |
37 | ```
38 |
39 | ---
40 |
41 | ### text-change
42 |
43 | Emitted when the editor content changes (text, formatting, or both).
44 |
45 | **Type:**
46 | ```typescript
47 | ({
48 | delta: Delta
49 | oldContent: Delta
50 | source: EmitterSource
51 | }) => void
52 | ```
53 |
54 | **Parameters:**
55 | - `delta`: `Delta` - Change delta representing the modifications
56 | - `oldContent`: `Delta` - Previous editor content as Delta
57 | - `source`: `EmitterSource` - Source of the change (`'user'`, `'api'`, or `'silent'`)
58 |
59 | **Example:**
60 | ```vue
61 |
78 |
79 |
80 |
81 |
82 | ```
83 |
84 | **Use cases:**
85 | - Track user edits
86 | - Implement auto-save functionality
87 | - Sync content to server
88 | - Trigger validation
89 |
90 | ---
91 |
92 | ### selection-change
93 |
94 | Emitted when the user selection (cursor position or text selection) changes.
95 |
96 | **Type:**
97 | ```typescript
98 | ({
99 | range: Range
100 | oldRange: Range
101 | source: EmitterSource
102 | }) => void
103 | ```
104 |
105 | **Parameters:**
106 | - `range`: `Range` - New selection range (`null` when editor loses focus)
107 | - `oldRange`: `Range` - Previous selection range
108 | - `source`: `EmitterSource` - Source of the change
109 |
110 | **Range type:**
111 | ```typescript
112 | interface Range {
113 | index: number // Starting position
114 | length: number // Length of selection (0 for cursor)
115 | }
116 | ```
117 |
118 | **Example:**
119 | ```vue
120 |
143 |
144 |
145 |
146 |
147 | ```
148 |
149 | **Use cases:**
150 | - Show custom formatting toolbar
151 | - Display character/word count for selection
152 | - Implement custom context menus
153 | - Track cursor position
154 |
155 | ---
156 |
157 | ### editor-change
158 |
159 | Emitted for both text and selection changes. Useful when you need to respond to any editor change.
160 |
161 | **Type:**
162 | ```typescript
163 | (eventName: 'text-change' | 'selection-change') => void
164 | ```
165 |
166 | **Parameters:**
167 | - `eventName`: `'text-change' | 'selection-change'` - Type of change
168 |
169 | **Example:**
170 | ```vue
171 |
177 |
178 |
179 |
180 |
181 | ```
182 |
183 | ---
184 |
185 | ### ready
186 |
187 | Emitted when the Quill editor is fully initialized and ready to use.
188 |
189 | **Type:**
190 | ```typescript
191 | (quill: Quill) => void
192 | ```
193 |
194 | **Parameters:**
195 | - `quill`: `Quill` - The initialized Quill instance
196 |
197 | **Example:**
198 | ```vue
199 |
210 |
211 |
212 |
213 |
214 | ```
215 |
216 | **Use cases:**
217 | - Initial editor configuration
218 | - Set initial focus
219 | - Load saved selection
220 | - Register custom formats
221 |
222 | ---
223 |
224 | ### focus
225 |
226 | Emitted when the editor gains focus.
227 |
228 | **Type:**
229 | ```typescript
230 | (quill: Quill) => void
231 | ```
232 |
233 | **Parameters:**
234 | - `quill`: `Quill` - The Quill instance
235 |
236 | **Example:**
237 | ```vue
238 |
246 |
247 |
248 |
249 |
250 | ```
251 |
252 | ---
253 |
254 | ### blur
255 |
256 | Emitted when the editor loses focus.
257 |
258 | **Type:**
259 | ```typescript
260 | (quill: Quill) => void
261 | ```
262 |
263 | **Parameters:**
264 | - `quill`: `Quill` - The Quill instance
265 |
266 | **Example:**
267 | ```vue
268 |
276 |
277 |
278 |
279 |
280 | ```
281 |
282 | **Use cases:**
283 | - Auto-save on blur
284 | - Hide custom toolbars
285 | - Validate content
286 | - Update preview
287 |
288 | ---
289 |
290 | ## Complete Example
291 |
292 | Example using all events together:
293 |
294 | ```vue
295 |
351 |
352 |
353 |
354 |
355 | {{ isFocused ? '🟢 Focused' : '⚫ Not focused' }}
356 | {{ selectionInfo }}
357 |
358 |
359 |
369 |
370 |
371 | ```
372 |
373 | ## Event Sources
374 |
375 | The `source` parameter in events indicates how the change was triggered:
376 |
377 | | Source | Description |
378 | |--------|-------------|
379 | | `'user'` | User interaction (typing, clicking, etc.) |
380 | | `'api'` | Programmatic change via Quill API |
381 | | `'silent'` | Change that shouldn't trigger handlers |
382 |
383 | **Example:**
384 | ```typescript
385 | const onTextChange = ({ source }: { source: EmitterSource }) => {
386 | if (source === 'user') {
387 | // Only react to user changes
388 | autoSave()
389 | }
390 | }
391 | ```
392 |
393 | ## See Also
394 |
395 | - [Component API](/api/component) - Props and methods
396 | - [TypeScript Types](/api/types) - Type definitions
397 | - [Examples](/examples/) - Practical examples
398 |
--------------------------------------------------------------------------------
/docs/api-examples.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: deep
3 | ---
4 |
5 | # Examples
6 |
7 | This page showcases different editor configurations and use cases built with vue-quilly. Each example demonstrates specific features and integration patterns.
8 |
9 | ## Snow Theme Editor
10 |
11 | The classic Quill editor with the Snow theme, featuring a full toolbar with all formatting options.
12 |
13 | **Features:**
14 | - Complete toolbar with all formatting options
15 | - Formula support with KaTeX
16 | - Image and video embedding
17 | - Font, size, and color customization
18 | - Headers, lists, and alignment
19 |
20 | ```vue
21 |
66 |
67 |
68 |
75 |
76 | ```
77 |
78 | [View Source](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/DefaultEditorSnow.vue)
79 |
80 | ---
81 |
82 | ## Bubble Theme Editor
83 |
84 | Lightweight editor with the Bubble theme that shows toolbar on text selection.
85 |
86 | **Features:**
87 | - Medium-style inline toolbar
88 | - Appears on text selection
89 | - Same formatting capabilities as Snow theme
90 | - Cleaner, more minimalist interface
91 |
92 | ```vue
93 |
125 |
126 |
127 |
132 |
133 | ```
134 |
135 | [View Source](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/DefaultEditorBubble.vue)
136 |
137 | ---
138 |
139 | ## Semantic HTML Editor
140 |
141 | Editor configured to output clean, semantic HTML without Quill-specific classes.
142 |
143 | **Features:**
144 | - Clean HTML output (e.g., `` instead of `
194 |
197 | ```
198 |
199 | ```html [Semantic HTML]
200 | Heading
201 |
204 | ```
205 |
206 | :::
207 |
208 | [View Source](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/SemanticHTMLEditor.vue)
209 |
210 | ---
211 |
212 | ## Image Resize Editor
213 |
214 | Editor with image resize functionality using the `quill-image-resize-module`.
215 |
216 | **Features:**
217 | - Drag to resize images
218 | - Display size indicator
219 | - Resize handles on images
220 | - Image alignment toolbar
221 |
222 | ```vue
223 |
261 |
262 |
263 |
268 |
269 | ```
270 |
271 | **Installation:**
272 |
273 | ```bash
274 | pnpm add quill-image-resize-module
275 | ```
276 |
277 | [View Source](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/ImageResizeEditor.vue)
278 |
279 | ---
280 |
281 | ## Custom Editor (Core Build)
282 |
283 | Minimal custom editor using `quill/core` with only specific blots registered.
284 |
285 | **Features:**
286 | - Minimal bundle size (uses `quill/core`)
287 | - Custom blots (Bold, Italic, Headers)
288 | - External toolbar controls
289 | - Perfect for custom implementations
290 |
291 | ```vue
292 |
339 |
340 | å
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
353 |
354 | ```
355 |
356 | [View Source](https://github.com/alekswebnet/vue-quilly/blob/main/demo/src/components/CustomEditor.vue)
357 |
358 | ---
359 |
360 | ## Live Demo
361 |
362 | Try all these examples live: [vue-quilly.vercel.app](https://vue-quilly.vercel.app/)
363 |
364 | ## More Examples
365 |
366 | - [Nuxt 4 Integration](https://github.com/alekswebnet/vue-quilly/tree/main/nuxt) - SSR setup with Nuxt
367 | - [Complete Demo Source](https://github.com/alekswebnet/vue-quilly/tree/main/demo) - All examples with styling
368 |
--------------------------------------------------------------------------------
/docs/api/types.md:
--------------------------------------------------------------------------------
1 | # TypeScript Types
2 |
3 | vue-quilly provides full TypeScript support with comprehensive type definitions.
4 |
5 | ## Component Types
6 |
7 | ### QuillyEditor
8 |
9 | The main component type reference.
10 |
11 | ```typescript
12 | import type { QuillyEditor } from 'vue-quilly'
13 |
14 | const editor = ref>()
15 | ```
16 |
17 | **Usage in component:**
18 | ```vue
19 |
31 | ```
32 |
33 | ---
34 |
35 | ## Quill Core Types
36 |
37 | Import types from `quill/core` for Quill-specific types.
38 |
39 | ### QuillOptions
40 |
41 | Editor configuration options.
42 |
43 | ```typescript
44 | import type { QuillOptions } from 'quill/core'
45 |
46 | interface QuillOptions {
47 | theme?: string
48 | placeholder?: string
49 | readOnly?: boolean
50 | formats?: string[]
51 | bounds?: HTMLElement | string
52 | scrollingContainer?: HTMLElement | string
53 | modules?: {
54 | toolbar?: boolean | string | string[][] | ToolbarConfig
55 | clipboard?: ClipboardOptions
56 | keyboard?: KeyboardOptions
57 | history?: HistoryOptions
58 | [key: string]: any
59 | }
60 | }
61 | ```
62 |
63 | **Example:**
64 | ```typescript
65 | const options: QuillOptions = {
66 | theme: 'snow',
67 | placeholder: 'Start writing...',
68 | readOnly: false,
69 | modules: {
70 | toolbar: [
71 | ['bold', 'italic'],
72 | [{ header: [1, 2, false] }]
73 | ]
74 | }
75 | }
76 | ```
77 |
78 | ---
79 |
80 | ### Delta
81 |
82 | Quill's document format representing content and changes.
83 |
84 | ```typescript
85 | import type { Delta } from 'quill/core'
86 |
87 | interface Delta {
88 | ops?: Op[]
89 | }
90 |
91 | interface Op {
92 | insert?: any
93 | delete?: number
94 | retain?: number
95 | attributes?: Record
96 | }
97 | ```
98 |
99 | **Example:**
100 | ```typescript
101 | import { Delta } from 'quill/core'
102 |
103 | // Create a new Delta
104 | const delta = new Delta()
105 | .insert('Hello ', { bold: true })
106 | .insert('World')
107 | .insert('\n', { header: 1 })
108 |
109 | // Use in event handler
110 | const onTextChange = ({ delta }: { delta: Delta }) => {
111 | console.log('Changes:', delta.ops)
112 | }
113 | ```
114 |
115 | **Delta operations:**
116 | - `insert` - Add content
117 | - `delete` - Remove content
118 | - `retain` - Keep content unchanged
119 | - `attributes` - Apply formatting
120 |
121 | ---
122 |
123 | ### Range
124 |
125 | Selection or cursor position in the editor.
126 |
127 | ```typescript
128 | import type { Range } from 'quill/core'
129 |
130 | interface Range {
131 | index: number // Starting position (0-based)
132 | length: number // Length of selection
133 | }
134 | ```
135 |
136 | **Example:**
137 | ```typescript
138 | const onSelectionChange = ({ range }: { range: Range }) => {
139 | if (range) {
140 | if (range.length === 0) {
141 | console.log(`Cursor at position ${range.index}`)
142 | } else {
143 | console.log(`Selected from ${range.index} to ${range.index + range.length}`)
144 | }
145 | } else {
146 | console.log('No selection (editor lost focus)')
147 | }
148 | }
149 |
150 | // Set selection programmatically
151 | quill.setSelection(0, 10) // Select first 10 characters
152 | quill.setSelection(5, 0) // Place cursor at position 5
153 | ```
154 |
155 | ---
156 |
157 | ### EmitterSource
158 |
159 | Source of an event or change.
160 |
161 | ```typescript
162 | import type { Sources as EmitterSource } from 'quill/core'
163 |
164 | type EmitterSource = 'user' | 'api' | 'silent'
165 | ```
166 |
167 | **Values:**
168 | - `'user'` - User interaction (typing, clicking, pasting)
169 | - `'api'` - Programmatic change via Quill API
170 | - `'silent'` - Silent change (no event emission)
171 |
172 | **Example:**
173 | ```typescript
174 | const onTextChange = ({ source }: { source: EmitterSource }) => {
175 | switch (source) {
176 | case 'user':
177 | console.log('User edited content')
178 | autoSave()
179 | break
180 | case 'api':
181 | console.log('Programmatic change')
182 | break
183 | case 'silent':
184 | console.log('Silent update')
185 | break
186 | }
187 | }
188 | ```
189 |
190 | ---
191 |
192 | ### BoundsStatic
193 |
194 | Position and dimensions of a selection or element.
195 |
196 | ```typescript
197 | interface BoundsStatic {
198 | left: number
199 | right: number
200 | top: number
201 | bottom: number
202 | height: number
203 | width: number
204 | }
205 | ```
206 |
207 | **Example:**
208 | ```typescript
209 | const range = quill.getSelection()
210 | if (range) {
211 | const bounds = quill.getBounds(range.index, range.length)
212 | console.log('Selection bounds:', bounds)
213 |
214 | // Position a tooltip
215 | tooltip.style.left = `${bounds.left}px`
216 | tooltip.style.top = `${bounds.bottom}px`
217 | }
218 | ```
219 |
220 | ---
221 |
222 | ## Event Handler Types
223 |
224 | Type-safe event handlers for all component events.
225 |
226 | ### TextChangeHandler
227 |
228 | ```typescript
229 | type TextChangeHandler = (params: {
230 | delta: Delta
231 | oldContent: Delta
232 | source: EmitterSource
233 | }) => void
234 |
235 | const onTextChange: TextChangeHandler = ({ delta, oldContent, source }) => {
236 | // Fully typed parameters
237 | }
238 | ```
239 |
240 | ### SelectionChangeHandler
241 |
242 | ```typescript
243 | type SelectionChangeHandler = (params: {
244 | range: Range
245 | oldRange: Range
246 | source: EmitterSource
247 | }) => void
248 |
249 | const onSelectionChange: SelectionChangeHandler = ({ range, oldRange, source }) => {
250 | // Fully typed parameters
251 | }
252 | ```
253 |
254 | ### EditorChangeHandler
255 |
256 | ```typescript
257 | type EditorChangeHandler = (eventName: 'text-change' | 'selection-change') => void
258 |
259 | const onEditorChange: EditorChangeHandler = (eventName) => {
260 | // Fully typed parameter
261 | }
262 | ```
263 |
264 | ### ReadyHandler
265 |
266 | ```typescript
267 | import type Quill from 'quill'
268 |
269 | type ReadyHandler = (quill: Quill) => void
270 |
271 | const onReady: ReadyHandler = (quill) => {
272 | // Fully typed Quill instance
273 | }
274 | ```
275 |
276 | ---
277 |
278 | ## Parchment Types
279 |
280 | For custom blots and formats (when using `quill/core`).
281 |
282 | ```typescript
283 | import type { BlotConstructor } from 'parchment'
284 |
285 | const Inline = Quill.import('blots/inline') as BlotConstructor
286 | const Block = Quill.import('blots/block') as BlotConstructor
287 |
288 | class CustomBlot extends Inline {
289 | static blotName = 'custom'
290 | static tagName = 'span'
291 | }
292 | ```
293 |
294 | ---
295 |
296 | ## Complete TypeScript Example
297 |
298 | ```vue
299 |
392 |
393 |
394 |
405 |
406 | ```
407 |
408 | ---
409 |
410 | ## Type Imports Reference
411 |
412 | Quick reference for all type imports:
413 |
414 | ```typescript
415 | // Component types
416 | import type { QuillyEditor } from 'vue-quilly'
417 |
418 | // Quill core types
419 | import type {
420 | QuillOptions,
421 | Delta,
422 | Range,
423 | Sources as EmitterSource,
424 | BoundsStatic,
425 | TextChangeHandler,
426 | SelectionChangeHandler
427 | } from 'quill/core'
428 |
429 | // Quill class
430 | import Quill from 'quill'
431 |
432 | // Parchment (for custom formats)
433 | import type { BlotConstructor } from 'parchment'
434 | ```
435 |
436 | ---
437 |
438 | ## Type Guards
439 |
440 | Helper type guards for runtime type checking:
441 |
442 | ```typescript
443 | // Check if range exists (editor has focus)
444 | function hasSelection(range: Range | null): range is Range {
445 | return range !== null
446 | }
447 |
448 | // Check if selection is a cursor (length 0)
449 | function isCursor(range: Range): boolean {
450 | return range.length === 0
451 | }
452 |
453 | // Usage
454 | const onSelectionChange = ({ range }: { range: Range }) => {
455 | if (hasSelection(range)) {
456 | if (isCursor(range)) {
457 | console.log('Cursor at', range.index)
458 | } else {
459 | console.log('Selection length', range.length)
460 | }
461 | }
462 | }
463 | ```
464 |
465 | ---
466 |
467 | ## See Also
468 |
469 | - [Component API](/api/component) - Props and methods
470 | - [Events](/api/events) - Event reference
471 | - [Quill API Documentation](https://quilljs.com/docs/api/) - Official Quill docs
472 |
--------------------------------------------------------------------------------
/docs/guide/basic-usage.md:
--------------------------------------------------------------------------------
1 | # Basic Usage
2 |
3 | Learn the essential patterns and features for working with vue-quilly.
4 |
5 | ## Basic Setup
6 |
7 | The minimal setup requires three steps:
8 |
9 | 1. Import the component and styles
10 | 2. Initialize the editor
11 | 3. Use v-model for content binding
12 |
13 | ```vue
14 |
28 |
29 |
30 |
31 |
32 | ```
33 |
34 | ## Content Management
35 |
36 | ### HTML Format
37 |
38 | Use `v-model` for HTML content:
39 |
40 | ```vue
41 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | ```
52 |
53 | ### Delta Format
54 |
55 | Use Quill's Delta format for programmatic content manipulation:
56 |
57 | ```typescript
58 | import { Delta } from 'quill/core'
59 |
60 | const editor = ref>()
61 | let quill: Quill | undefined
62 |
63 | onMounted(() => {
64 | quill = editor.value?.initialize(Quill)!
65 |
66 | // Set content using Delta
67 | quill.setContents(
68 | new Delta()
69 | .insert('Hello ')
70 | .insert('World', { bold: true })
71 | .insert('\n')
72 | )
73 |
74 | // Get content as Delta
75 | const delta = quill.getContents()
76 | console.log(delta)
77 | })
78 | ```
79 |
80 | ### Semantic HTML
81 |
82 | For clean, SEO-friendly HTML output:
83 |
84 | ```vue
85 |
89 | ```
90 |
91 | This outputs `` instead of `
` instead of `