# Classic quick start

Compose Core, paginated views and product UI into a complete editing experience.

Classic is a paginated product shell above the framework. `@quirekit/classic-editor` provides mounting, workspace and product plugins. Optional `@quirekit/classic-docx` assembles Word schemas, UI and file services. Product plugins are distinct from ordinary Core extensions.

To build your own Classic-like interface, start with [the Core product tutorial](/en/build). This page integrates the existing Classic shell. See [product plugins](/en/build/product-plugin) for custom ribbon, panel and file-service implementation.

## Distribution and assembly

The Classic shell uses AGPL-3.0-only; the Word preset and Pro are separate commercial packages. This example consumes workspace packages. External applications must obtain the relevant packages and license rather than assuming public npm availability. See [Word plugins](/en/plugins/word).

Choose a path through [free evaluation and community licenses](/en/classic/free) or [commercial use](/en/classic/commercial), then continue with [configuration and lifetime](/en/classic/configuration).

## Minimal mounting

In Vue's `onMounted`, obtain the host element and create the product through entries sharing your Vue runtime:

```ts [Create a Word product instance]
import { createClassicEditor } from '@quirekit/classic-editor/vue'
import {
  createClassicWordPreset,
  createClassicWordDefaultDocument,
  createClassicWordDocxPlugin,
} from '@quirekit/classic-docx/vue'
import '@quirekit/classic-editor/styles.css'
import '@quirekit/classic-docx/styles.css'

const instance = createClassicEditor({
  element,
  preset: createClassicWordPreset({ proofing: false }),
  document: createClassicWordDefaultDocument('en'),
  locale: 'en',
  plugins: [createClassicWordDocxPlugin()],
  webFonts: false,
})
instance.ui.setZoomMode('fit-width')
```

`element` is the mounted host, such as the value of a Vue element ref. Give it a real height, for example `height: 640px`. `preset` installs the Word model and View; `document` supplies compatible initial content; `plugins` separately installs DOCX services. Proofing and external font acquisition are disabled here; enable them through their respective options when host services are ready.

Call `instance.destroy()` in `onBeforeUnmount`. Plain-script hosts can create through root entries. Nuxt mounts on the client; the complete example below handles asynchronous loading and disposal.

## Live effect

This is the public Word preset's default document. Type, format, switch to read-only, and download current JSON. The official DOCX plugin supplies file-menu actions. Edits last only for this page session.

### classic/editor.vue

```vue
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue";
import { QuireButton, useQuireKitTheme } from "@quirekit/ui/vue";
import type { ClassicEditorInstance, ClassicEditorLocale } from "@quirekit/classic-editor";
import { downloadJson } from "../shared/download";

const props = withDefaults(defineProps<{
  /** Interface language; changing it never replaces document content. */ locale?: ClassicEditorLocale;
  /** Deployed host license; local evaluation works without a key. */ licenseKey?: string;
}>(), { locale: "zh-CN" });
const host = ref<HTMLElement>();
const instance = shallowRef<ClassicEditorInstance>();
const theme = useQuireKitTheme();
const loading = ref(false);
const failed = ref(false);
const readOnly = ref(false);
let disposed = false;
const text = computed(() => props.locale === "en" ? {
  loading: "Preparing Classic…", failure: "The editor could not load. Reload this page to try again.",
  retry: "Reload page", read: "Read only", edit: "Resume editing", download: "Download JSON",
  note: "A live Word preset. Edits stay on this page; download JSON before leaving.",
} : {
  loading: "正在准备 Classic…", failure: "编辑器加载失败，请重新加载页面后再试。", retry: "重新加载页面",
  read: "只读预览", edit: "继续编辑", download: "下载 JSON",
  note: "真实 Word 预设。修改仅保留在当前页面，离开前可下载 JSON。",
});

/** Loads the public product only in the browser, respecting the owning component's lifetime. */
async function mount(): Promise<void> {
  if (loading.value || disposed || instance.value) return;
  loading.value = true;
  failed.value = false;
  let created: ClassicEditorInstance | undefined;
  try {
    const [classic, word, license] = await Promise.all([
      import("@quirekit/classic-editor/vue"), import("@quirekit/classic-docx/vue"), import("@quirekit/license"),
      import("@quirekit/classic-editor/styles.css"), import("@quirekit/classic-docx/styles.css"),
    ]);
    if (disposed || !host.value) return;
    if (props.licenseKey !== undefined) license.setQuireKitLicense(props.licenseKey || null);
    created = classic.createClassicEditor({
      element: host.value,
      locale: props.locale,
      preset: word.createClassicWordPreset({ proofing: false }),
      document: word.createClassicWordDefaultDocument(props.locale),
      theme: theme?.value,
      webFonts: false,
      plugins: [word.createClassicWordDocxPlugin()],
      shell: { leftSidebar: false, rightSidebar: false, toolbar: false, ribbonOverflow: "collapse" },
    });
    created.ui.setZoomMode("fit-width");
    instance.value = created;
  } catch {
    created?.destroy();
    failed.value = true;
  } finally {
    loading.value = false;
  }
}
/** Changes editability through the product contract without replacing the current document. */
function toggleReadOnly(): void {
  readOnly.value = !readOnly.value;
  instance.value?.update({ editable: !readOnly.value });
}
/** Downloads the current canonical content, including edits made in the live preview. */
function download(): void {
  if (instance.value) downloadJson(instance.value.getJSON(), "classic-document.json");
}
/** Retries failed module fetching in a fresh browser module map before any document is mounted. */
function reload(): void {
  if (!instance.value) window.location.reload();
}
watch(() => props.locale, locale => instance.value?.update({ locale }));
if (theme) watch(theme, value => instance.value?.update({ theme: value }));
onMounted(mount);
onBeforeUnmount(() => { disposed = true; instance.value?.destroy(); instance.value = undefined; });
</script>
<template>
  <div class="classic-example" :data-editor-ready="Boolean(instance)">
    <div class="classic-example-actions">
      <span class="classic-example-note">{{ text.note }}</span>
      <QuireButton variant="outline" size="sm" :disabled="!instance" :aria-pressed="readOnly" @click="toggleReadOnly">{{ readOnly ? text.edit : text.read }}</QuireButton>
      <QuireButton variant="outline" size="sm" :disabled="!instance" @click="download">{{ text.download }}</QuireButton>
    </div>
    <div v-if="!instance" class="classic-example-state" role="status">
      <p>{{ failed ? text.failure : text.loading }}</p>
      <QuireButton v-if="failed" variant="outline" @click="reload">{{ text.retry }}</QuireButton>
    </div>
    <div ref="host" class="classic-editor-host" :class="{ 'classic-editor-pending': !instance }" />
  </div>
</template>
<style scoped>
.classic-example { width: 100%; min-width: 0; }
.classic-example-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 12px 16px; background: var(--qk-color-surface-page); border-bottom: 1px solid var(--qk-color-border-subtle); }
.classic-example-note { flex: 1 1 240px; font-size: 12px; line-height: 1.6; color: var(--qk-color-text-secondary); }
.classic-editor-host { height: 640px; min-width: 0; text-align: start; }
.classic-editor-pending { height: 0; overflow: hidden; }
.classic-example-state { display: grid; align-content: center; justify-items: center; height: 420px; padding: 24px; background: var(--qk-color-surface-subtle); color: var(--qk-color-text-secondary); }
@media (max-width: 600px) { .classic-editor-host { height: 540px; } .classic-example-actions { padding: 12px; } }
</style>

```

### shared/download.ts

```ts
/**
 * Downloads canonical JSON through a short-lived browser URL.
 * @param document - Serializable canonical content.
 * @param name - Download filename chosen by the host.
 */
export function downloadJson(document: unknown, name: string): void {
  const url = URL.createObjectURL(new Blob([JSON.stringify(document, null, 2)], { type: "application/json" }));
  const link = window.document.createElement("a");
  link.href = url;
  link.download = name;
  link.click();
  window.setTimeout(() => URL.revokeObjectURL(url), 1000);
}

```

A Vue host uses the `/vue` entries to share its Vue runtime. After async loading, check that the host still exists; call `destroy()` on disposal. The example updates theme, language and editability while retaining the same Core, content and undo history. Document-model and other structural updates still rebuild; see [configuration and lifetime](/en/classic/configuration).

Import `@quirekit/classic-editor/styles.css` and the selected Word package's `@quirekit/classic-docx/styles.css`, as the source does. Public style entries include extracted component styles needed by ribbons, block controls, overlays and panels; copying only canvas rules is insufficient. A custom Core workspace uses View's own public structural stylesheet; see [View integration](/en/build/view).

## Public entry points

### createClassicEditor

`@quirekit/classic-editor` · AGPL-3.0-only

Creates a framework-neutral Classic Editor product instance.
@param options - Product document, preset, feature, plugin, and mount options.
@returns Reusable product instance.

```ts
function createClassicEditor(options?: ClassicEditorOptions): ClassicEditorInstance
```

### createClassicWordPreset

`@quirekit/classic-docx` · Commercial

Creates a complete opt-in Word product preset for one Host configuration.
@param options - Host-owned product authorities captured by the preset.
@returns Frozen preset that resolves an independent extension set per mount.

```ts
function createClassicWordPreset(options?: ClassicWordPresetOptions): ClassicEditorPreset
```

### createClassicWordDefaultDocument

`@quirekit/classic-docx` · Commercial

Creates the complete Word-shaped starter document for the opt-in assembly.
@param locale - Locale used only for product-owned starter copy.
@returns Canonical Quire JSON with one section and named header/footer stories.

```ts
function createClassicWordDefaultDocument(locale?: ClassicEditorLocale): QuireJSONContent
```

## Product plugins

Ordinary extensions own document semantics; Classic plugins compose ribbons, menus, sidebars and document services.

### defineClassicEditorPlugin

`@quirekit/classic-editor` · AGPL-3.0-only

Defines a Classic Editor plugin while preserving literal contribution types.
@param plugin - Product plugin declaration.
@returns The same declaration for composition in presets or instance options.

```ts
function defineClassicEditorPlugin<Plugin extends ClassicEditorPlugin>(plugin: Plugin): Plugin
```

### createClassicWordDocxPlugin

`@quirekit/classic-docx` · Commercial

Creates the official product-level DOCX import/export plugin.
@param options - Binary codec and optional product ids.
@returns Classic Editor plugin with Word document and Word template services and menu entries.

```ts
function createClassicWordDocxPlugin(options?: ClassicWordDocxPluginOptions): ClassicEditorPlugin
```

Pro review panels, content-control UI and optional AI/PDF/OFD adapters require separate assembly and are not installed in this example.

Next, connect [saving, opening and conversion](/en/classic/files), then adapt the interface through [configuration](/en/classic/configuration).
