A CodeMirror 6 based editor for ChordPro songs. ~26 KB (~7 KB gzipped).
Part of ChordProject
A CodeMirror 6 editor that highlights ChordPro syntax (directives, chords, comments, tab blocks), aligned with the official ChordPro directives and chord specification.
- Node.js 20.19.0 or newer for development and builds.
@chordproject/parserversion 1 or newer is a peer dependency and must be installed by the consuming application.
$ npm i @chordproject/editorimport { createChordProEditor } from '@chordproject/editor';
const editor = createChordProEditor({
parent: document.querySelector('#editor'),
doc: '{title: Amazing Grace}\n[G]Amazing [C]grace...',
theme: 'light', // or 'dark'
onChange: (value) => console.log(value),
});Colors read the same CSS custom properties as chordproject-client
(--color-primary-*, --color-error-*, --color-neutral-*), with sensible fallbacks for
standalone use. Ships with its own TypeScript types, no @types/* package needed.
| Option | Type | Description |
|---|---|---|
parent |
HTMLElement |
Required. Element that will contain the editor. |
doc |
string? |
Initial document content. |
theme |
'light' | 'dark'? |
Initial theme. Defaults to 'light'. |
extensions |
Extension[]? |
Extra CodeMirror 6 extensions to append (escape hatch). |
onChange |
(value: string) => void |
Called with the full document on every change. |
onFocus / onBlur |
() => void |
Called when the editor gains/loses focus. |
The returned ChordProEditor handle:
| Member | Description |
|---|---|
view |
The underlying CodeMirror EditorView, for anything not covered below. |
getValue() / setValue(value) |
Read/replace the whole document. |
setTheme('light' | 'dark') |
Swaps the theme without recreating the editor. |
insertChord() |
Inserts "[]" at the cursor (or wraps the selection) and opens chord suggestions - no keyboard shortcut needed, works from a button/tap. |
openCompletionList() |
Opens the completion list (chords or snippets, depending on cursor position) without any keyboard shortcut. |
getChordNotationSuggestions() |
Returns grouped suggestions for valid non-canonical chord spellings, such as Asus to Asus4. |
normalizeChordNotation() |
Replaces all suggested spellings in one undoable CodeMirror transaction and returns the applied groups. |
focus() / destroy() |
Focus the editor / tear it down and release its DOM node. |
Multiple independent createChordProEditor() instances can coexist on the same page.
$ npm i
$ npm run devOpen http://localhost:5173/ to try it.
$ npm testThe test suite covers grouped chord-notation suggestions and safe normalization of slash chords, annotations, already canonical chords, and historical combined tokens.
- Syntax highlighting: directives (known/custom/invalid), chords, comments, tab blocks,
{define:} - Chord autocomplete (common chord vocabulary, boosted by chords already used in the song)
- Directive snippets, expandable with
Tab(see table below) - Folding for
{start_of_x}/{end_of_x}blocks - Parser warnings displayed on their source line for malformed directives, invalid metadata, and malformed chords
- Warns (non-blocking) when a "once per song" directive like
{title:}or{key:}is repeated - Suggests canonical spellings for valid legacy abbreviations such as
AsustoAsus4,AM7toAmaj7, andD+toDaug, with an individual replacement action - Exposes
getChordNotationSuggestions()andnormalizeChordNotationText(content)for hosts that want to preview or apply grouped normalization - No fixed keyboard shortcut requirement: chords and snippets suggest themselves as you type,
and
insertChord()/openCompletionList()work from a button/tap - useful sinceCtrl+Spaceand its usual alternates are unreliable across OS/keyboard layouts
Type the snippet and press Tab to expand it.
| Snippet | Result |
|---|---|
title or t |
{title: value} |
subtitle or st |
{subtitle: value} |
artist or a |
{artist: value} |
album |
{album: value} |
arranger |
{arranger: value} |
composer |
{composer: value} |
lyricist |
{lyricist: value} |
copyright |
{copyright: value} |
capo |
{capo: 5} |
key or k |
{key: Am} |
tempo |
{tempo: 120} |
time |
{time: 4/4} |
duration |
{duration: 4:00} |
year |
{year: 2020} |
meta |
{meta: label value} |
comment or c |
{comment: value} |
chorus / soc / eoc |
Chorus block / {start_of_chorus} / {end_of_chorus} |
verse / sov / eov |
Verse block / {start_of_verse} / {end_of_verse} |
bridge / sob / eob |
Bridge block / {start_of_bridge} / {end_of_bridge} |
tab / sot / eot |
Tab block with a 6-string template / {start_of_tab} / {end_of_tab} |
define or d |
{define: Am base-fret 1 frets 0 0 0 0 0 0 fingers 0 0 0 0 0 0} |
[ |
Inserts a chord ([Am]) |
This project welcomes contributions of all types. If you find any bug or want some new features, please feel free to create an issue or submit a pull request.
Join the community and chat with us on Discord