---
title: "Quick start: plain Vue"
description: "Set up the simple editor in a Vite and Vue app: peers, Nuxt UI plugin, CSS and a mounted SimpleEditor with toolbar and outline."
canonical_url: "https://skaile-ai.github.io/forge-editor/getting-started/quick-start-vue"
---
# Quick start: plain Vue

> Set up the simple editor in a Vite and Vue app: peers, Nuxt UI plugin, CSS and a mounted SimpleEditor with toolbar and outline.

`SimpleEditor` is the two core features alone (`core-content` and `core-ui`): bold/italic/underline/strike/code/link, headings, lists, quotes, code blocks, horizontal rule, undo/redo. No backend requests, no Yjs, no feature code. The runnable reference is [`examples/vue-simple`](https://github.com/skaile-ai/forge-editor/tree/main/examples/vue-simple); start it with `bun run --cwd examples/vue-simple dev` (port 3040). Its sample picker loads five demo documents — „Start“, „Formatierung“ (marks, lists, quote, code block, rule), „Gliederung“ (three outline levels), „Hinweise“ (the own „Hinweis“ block) and „Ungültig (Block-JSON)“ (advanced JSON, rejected through `contentError`) — beside the toolbar and outline, with the JSON and Markdown of the document next to the editor. The `/hinweis` entry and the callout behind it are an own block added through the `extensions` and `commands` props; the [tutorial](https://skaile-ai.github.io/forge-editor/tutorial/own-block-path-a) shows how, and how to go further with a full feature.

## Setup

Starting a new app from nothing? The files below plus these three are all that [`examples/vue-simple`](https://github.com/skaile-ai/forge-editor/tree/main/examples/vue-simple) has:

- `package.json` dependencies: `@skaile/forge-editor` (`workspace:*` inside this repository), `vue`, `@nuxt/ui`, `tailwindcss`, `@iconify-json/lucide`, `@tiptap/core`, `@tiptap/pm`, `@tiptap/vue-3`, `yjs`, `@hocuspocus/provider`; dev dependencies `vite`, `@vitejs/plugin-vue`, `typescript`, `vue-tsc`; scripts `dev` (`vite`), `build` (`vite build`), `typecheck` (`vue-tsc --noEmit -p tsconfig.json`). Use the exact version ranges of the example's [`package.json`](https://github.com/skaile-ai/forge-editor/blob/main/examples/vue-simple/package.json).
- `index.html` with `<div id="app"></div>` and `<script type="module" src="/src/main.ts"></script>`.
- `tsconfig.json` with `moduleResolution: "Bundler"`, `types: ["vite/client"]`, `strict`, `verbatimModuleSyntax` and `include: ["src/**/*.ts", "src/**/*.vue", "vite.config.ts"]` (see the example's [`tsconfig.json`](https://github.com/skaile-ai/forge-editor/blob/main/examples/vue-simple/tsconfig.json)).

Optional: Nuxt UI resolves `i-lucide-*` icons at build time, but a workspace library lies outside the Vite root it scans, so without the extra config the page fetches the toolbar's icons from the Iconify API at runtime. The example's [`vite.config.ts`](https://github.com/skaile-ai/forge-editor/blob/main/examples/vue-simple/vite.config.ts) collects the library's icon names into `ui({ icon: { clientBundle: { scan: true, icons } } })` to bundle them.

`vite.config.ts` — Nuxt UI's Vite plugin without a router:

```ts
import ui from '@nuxt/ui/vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({ plugins: [vue(), ui({ router: false })] })
```

`main.ts` — Nuxt UI and the editor context. `createEditor()` (from the Vue layer, `@skaile/forge-editor/vue`) owns the settings of this app and is required by every editor component:

```ts
import ui from '@nuxt/ui/vue-plugin'
import { createEditor } from '@skaile/forge-editor/vue'
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'

createApp(App).use(ui).use(createEditor()).mount('#app')
```

`createEditor()` loads and saves the settings per account through its backend: with the default backend (`createFetchBackend`, the HTTP routes of the Nuxt module over the platform `fetch`) the first `useEditorSettings()` asks `GET /api/editor/settings` and every change is sent with `PUT`. They are local-only (`localStorage`, `tiptap-editor:settings`) when the backend offers no `settings` capability: `createEditor({ backend: createMemoryBackend() })`. `createEditor({ backend })` swaps the whole data layer of all features (documents, uploads, mention lookups, settings, themes, AI); `createHttpBackend({ fetch })` (`@skaile/forge-editor/adapters/http`) lets a host hand in its own HTTP client such as Nuxt's `$fetch`. `createEditor({ locale: 'en' })` switches every string the editor renders to English (default `'de'`), `createEditor({ messages: { 'toolbar.bold': 'Strong' } })` overrides single messages; see [Language](https://skaile-ai.github.io/forge-editor/guides/language). Components read `useEditorI18n()` (`{ t, locale }`); the Nuxt module takes the same two options as `tiptapEditor: { locale, messages }`.

`createEditor()` is a thin Vue plugin. The headless core (`@skaile/forge-editor/core`) imports no Vue: `createEditorContext(options)` returns the framework-free context with the same options, whose `settings` is a store (`get()`, `set(value)`, `update(recipe)`, `subscribe(listener)`) and whose `ready` and `synced` are read-only stores. `createEditor()` creates that context, provides it to the app and disposes it on unmount; Vue components read the settings through `useEditorSettings()` (reactive refs) from `@skaile/forge-editor/vue`.

`style.css` — Tailwind, Nuxt UI, then the core CSS, and let Tailwind scan the library's whole `dist` (the Features' `features/*/components` sit beside `vue`; in this repository the examples scan the sibling's `src` instead):

```css
@import "tailwindcss";
@import "@nuxt/ui";
@import "@skaile/forge-editor/styles/core.css";
@source "../node_modules/@skaile/forge-editor/dist"; /* relative path from this CSS file to the installed package's dist */
```

`App.vue` wraps everything in `<UApp>` (overlays, tooltips, toasts).

## Mount the editor

```vue
<script setup lang="ts">
import { ref, shallowRef } from 'vue'
import type { Editor, JSONContent } from '@tiptap/core'
import { SimpleEditor } from '@skaile/forge-editor/vue/simple'
import { EditorToolbar } from '@skaile/forge-editor/vue'
import { EditorOutline } from '@skaile/forge-editor/outline/vue'

const editor = shallowRef<Editor>()
const content = ref<JSONContent>({ type: 'doc', content: [{ type: 'paragraph' }] })
</script>

<template>
  <UApp>
    <EditorToolbar :editor="editor" />
    <SimpleEditor v-model="content" @ready="editor = $event" />
    <EditorOutline :editor="editor" />
  </UApp>
</template>
```

Try it here: type, use the toolbar, switch to read-only and watch the JSON `v-model` and the outline.

<demo-simple-editor>



</demo-simple-editor>

## Next steps

The [tutorial](https://skaile-ai.github.io/forge-editor/tutorial/simple-editor) continues from this editor; the props and events of `SimpleEditor` are covered there. To add features such as mentions, media, tables and block UI, see [Compose features](https://skaile-ai.github.io/forge-editor/tutorial/compose-features).


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
