Skip to content

Getting started

This guide builds a minimal editor with Vite + TypeScript + Viewfly where you can type and press Enter for new lines: @textbus/core supplies the model and kernel, @textbus/platform-browser handles browser mounting and input, and @textbus/adapter-viewfly renders the document as a Viewfly tree. If you use Vue or React, you do not need Viewfly—see the Vue adapter and React adapter.

TIP

You are reading the development documentation for Textbus. If you want a ready-to-use rich text editor out of the box, check out XNote. Repository: https://github.com/textbus/xnote.

What you'll learn

  • Install the smallest useful set of npm packages
  • Configure decorators and JSX for this stack
  • Wire ViewflyAdapter and BrowserModule, create an instance with new Textbus, then render

1. Scaffold the project and install dependencies

Create a Vite project locally (Vanilla + TypeScript template):

bash
# Vanilla + TypeScript template — easy to add Viewfly JSX
npm create vite@latest my-textbus-editor -- --template vanilla-ts
cd my-textbus-editor
npm install

Install Textbus and Viewfly packages (pin versions to the current 5.x line on npm; ranges below are illustrative):

bash
# reflect-metadata: decorator metadata; the rest are core, browser layer, Viewfly adapter, and runtime
npm install reflect-metadata @textbus/core @textbus/platform-browser @textbus/adapter-viewfly @viewfly/core @viewfly/platform-browser
npm install -D vite typescript @types/node

Point the entry file to src/App.tsx (if it is still main.ts, rename it and update index.html so the script loads /src/App.tsx).

2. Configure TypeScript and Vite

The kernel relies on decorator metadata, and this walkthrough uses Viewfly JSX. Set tsconfig.json to at least:

jsonc
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    // Viewfly: react-jsx automatic runtime, resolve via @viewfly/core
    "jsx": "react-jsx",
    "jsxImportSource": "@viewfly/core",
    // Decorators + emitDecoratorMetadata: required for Textbus DI
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    // Matches decorator field init order (same as this repo’s examples)
    "useDefineForClassFields": false,
    "skipLibCheck": true,
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  },
  "include": ["src"]
}
ts
import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    // Match tsconfig jsxImportSource
    jsx: 'automatic',
    jsxImportSource: '@viewfly/core'
  },
  optimizeDeps: {
    esbuildOptions: {
      // Pre-bundle deps with the same Viewfly JSX settings
      jsx: 'automatic',
      jsxImportSource: '@viewfly/core'
    }
  }
})

Setting useDefineForClassFields to false avoids odd interactions between some decorators and class fields (aligned with the examples in this repository).

3. Page HTML

Root index.html exposes the Viewfly mount #root; App.tsx renders #editor-host (.tb-editor-host needs enough min-height240px in this sample—or the editing surface is hard to click or focus:

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Textbus minimal sample</title>
    <style>
      body {
        margin: 0;
        padding: 1rem;
      }
      /* Editor host needs height so it is easy to click and focus */
      .tb-editor-host {
        min-height: 240px;
        border: 1px solid #ccc;
        border-radius: 4px;
      }
    </style>
  </head>
  <body>
    <!-- Viewfly mount -->
    <div id="root"></div>
    <!-- Entry: first line of App.tsx must be import 'reflect-metadata' -->
    <script type="module" src="/src/App.tsx"></script>
  </body>
</html>

4. Components, adapter, and entry

This example uses three files: App.tsx, components/root.component.tsx, and components/paragraph.component.tsx (place them under src/ or your preferred layout). In the view: only the slot render factory (the second argument passed to adapter.slotRender) must wrap kernel children with createVNode; DOM outside slots can use Viewfly JSX (see TodoRowView in Component basics).

You can edit the sample below and switch to Preview to try it; for a project identical to the steps above, still copy the code into your own repo and install/configure TypeScript and Vite as described.

Ready

5. Run and verify

bash
# Open the dev URL printed in the terminal; confirm typing works and Enter inserts a new line
npm run dev

Open the local URL in a browser and click the editing area—you should be able to type; Enter inserts a new paragraph (handled by onBreak in ParagraphComponent; see Component events & lifecycle for hooks overview).

FAQ

  • reflect-metadata must load first in the entry: otherwise decorator metadata may be incomplete and dependency injection can fail at runtime. Keep import 'reflect-metadata' as the first statement in App.tsx (before other @textbus/* imports).
  • JSX and jsxImportSource: tsconfig.json and vite.config.ts should both point jsxImportSource at @viewfly/core, or view components will not compile correctly.
  • Destroying the instance: if you need to tear down the editor when the page unmounts, call destroy() on the Textbus instance (this sample does not show routing; wire this up when integrating into an SPA).

What's next

MIT Licensed