Nuxt Nation conference is coming. Join us on November 12-13.

nuxt-codemirror
nuxt-codemirror

Nuxt codemirror module

Nuxt CodeMirror

npm version npm downloads License Nuxt

Codemirror as a Nuxt module. Demo can be found in below playground

Features

  • 🚀 Easily configure codemirror to your own needs using almost every API
  • 🚠 Built with Typescript
  • 🌲 Custom useNuxtCodeMirror composable for creating your own editor
  • Built for CodeMirror 6 and above

Documentation

This module consists of one Component, one Composable and a few types for you to use. Read the CodeMirror Reference guide for more in depth information: CodeMirror docs

NuxtCodeMirror.vue

This component is auto imported and is the CodeMirror wrapper.

Component props:

interface NuxtCodeMirrorProps
  extends Omit<EditorStateConfig, 'doc' | 'extensions'> {
  /** value of the auto created model in the editor. Works as underlying logic of a V-Model */
  modelValue?: string
  /** The height value of the editor. */
  height?: string
  /** The minimum height value of the editor. */
  minHeight?: string
  /** The maximum height value of the editor. */
  maxHeight?: string
  /** The width value of the editor. */
  width?: string
  /** The minimum width value of the editor. */
  minWidth?: string
  /** The maximum width value of the editor. */
  maxWidth?: string
  /** focus on the editor. */
  autoFocus?: boolean
  /** Enables a placeholder—a piece of example content to show when the editor is empty. */
  placeholder?: string | HTMLElement
  /**
   * `light` / `dark` / `Extension` Defaults to `light`.
   * @default light
   */
  theme?: 'light' | 'dark' | 'none' | Extension
  /**
   * Whether to optional basicSetup by default
   * @default true
   */
  basicSetup?: boolean | BasicSetupOptions
  /**
   * This disables editing of the editor content by the user.
   * @default true
   */
  editable?: boolean
  /**
   * This disables editing of the editor content by the user.
   * @default false
   */
  readOnly?: boolean
  /**
   * Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
   * or behaves according to the browser's default behavior (`false`).
   * @default true
   */
  indentWithTab?: boolean
  /** Fired whenever a change occurs to the document. */
  onChange?(value: string, viewUpdate: ViewUpdate): void
  /** Some data on the statistics editor. */
  onStatistics?(data: Statistics): void
  /** Fired whenever any state change occurs within the editor, including non-document changes like lint results. */
  onUpdate?(viewUpdate: ViewUpdate): void
  /** The first time the editor executes the event. */
  onCreateEditor?(view: EditorView, state: EditorState): void
  /** Fired whenever the editor is focused. */
  onFocus?(view: ViewUpdate): void
  /** Fired whenever the editor is blurred. */
  onBlur?(view: ViewUpdate): void
  /**
   * Extension values can be [provided](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions) when creating a state to attach various kinds of configuration and behavior information.
   * They can either be built-in extension-providing objects,
   * such as [state fields](https://codemirror.net/6/docs/ref/#state.StateField) or [facet providers](https://codemirror.net/6/docs/ref/#state.Facet.of),
   * or objects with an extension in its `extension` property. Extensions can be nested in arrays arbitrarily deep—they will be flattened when processed.
   */
  extensions?: Extension[]
  /**
   * If the view is going to be mounted in a shadow root or document other than the one held by the global variable document (the default), you should pass it here.
   * Originally from the [config of EditorView](https://codemirror.net/6/docs/ref/#view.EditorView.constructor%5Econfig.root)
   */
  root?: ShadowRoot | Document
  /**
   * Create a state from its JSON representation serialized with [toJSON](https://codemirror.net/docs/ref/#state.EditorState.toJSON) function
   */
  initialState?: {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    json: any
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    fields?: Record<string, StateField<any>>
  }
}

The NuxtCodeMirror component accepts a Template ref and exposes The CodeMirror div element, the Editor view and the Editor State

interface CodeMirrorRef {
  /** Container element of the CodeMirror instance */
  container: HTMLDivElement | null
  /** The EditorView of the CodeMirror instance */
  view: EditorView | undefined
  /** The EditorState of the CodeMirror instance */
  state: EditorState | undefined
  /** Editor element of the CodeMirror instance */
  editor: HTMLDivElement | null
}

If you need access to the underlying CodeMirror instance You can do so by adding a ref with the same name as your Template ref. An example on how to do this can be found here: 🏀 Online playground

If for some reason you want to write your own CodeMirror component then you can do that too :)

UseNuxtCodeMirror.ts

This composable is the underlying magic of the NuxtCodeMirror component and is also auto imported.

It requires minimum 3 Refs, one for the div element CodeMirror will connect to, one for the CodeMirror view, and one for the CodeMirror state

Make sure you execute the composable in onMounted otherwise you will get an eror because codemirror can't be linked to the DOM.

const editor = ref<HTMLDivElement | null>(null)
const container = ref<HTMLDivElement | null>(null)
const view = ref<EditorView>()
const state = ref<EditorState>()

onMounted(() => {
  useNuxtCodeMirror({
    ...props,
    container: editor.value,
    viewRef: view,
    stateRef: state,
    containerRef: container,
  })
})

For more information on how this is implemented see the source, to get inspiration for your own version

Credits

This Nuxt module wouldn't be possible without:

Quick Setup

Install the module to your Nuxt application with one command:

npx nuxi module add nuxt-codemirror

That's it! You can now use Nuxt-codemirror in your Nuxt app ✨

Tested extensions

Below is a list of tested extensions you can use as of @codemirror/view version 6.29.1 and @codemirror/state verion 6.4.1

and many more...

Contribution

If you have ideas or bugs feel free to start by opening an issue. For ideas please start a Discussion.

I welcome any kind of contribution Thank you in advance!!

Local development
# Install dependencies
pnpm i

# Generate type stubs
pnpm dev:prepare

# Develop with the playground
pnpm dev

# Build the playground
pnpm dev:build

# Run ESLint
pnpm lint

# Run Vitest
pnpm test
pnpm test:watch

# Release new version
pnpm release

FAQ

Issue

  • I get errors when starting the dev server with your module: Pre-transform error: Failed to resolve import "@codemirror/view", Pre-transform error: Failed to resolve import "@codemirror/state".

Solution

  • Assuming you use pnpm with shamefully-hoist=false install @codemirror/state and @codemirror/view and these errors should disappear