Embed ChordPro and iReal Pro in your React app
@chordsketch/react ships the same parser + renderer pipeline that
powers https://chordsketch.koeda.me as a published React component
library. This page is the recipe collection for the most common
embedding scenarios; copy-paste into a fresh Vite + React 18 app
(or Next.js, see §Server-side rendering / Next.js
below) and it works.
Prerequisite.
npm install @chordsketch/react react react-dom. The PDF / PNG export bundle is a separate optional peer — see §Export to PDF for when to install it.
Recipe 1 — Drop in a ChordPro playground in 30 seconds
The fastest path. One component, no configuration, full editor + preview + transpose UI:
import { ChordProEditor } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
export default function App() {
return <ChordProEditor defaultValue={"{title: My Song}\n[G]Hello [D]world"} />;
}<ChordProEditor> accepts source + onChange to drive the value from
the host (controlled mode) instead of letting the component own it.
Renamed from
<Playground>in@chordsketch/reactv0.3.0 per ADR-0022.
Recipe 2 — Render a read-only chord sheet
For lyrics-and-chords display without any editing affordance:
import { ChordSheet } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
const source = `{title: Amazing Grace}
{key: G}
[G]Amazing [G7]grace, how [C]sweet the [G]sound`;
export function Sheet() {
return <ChordSheet source={source} transpose={0} />;
}format="html" (the default) walks the parsed AST into a React tree
through the chordpro-jsx walker — every element reaches the DOM
through React reconciliation, so the output is safe for snapshot
tests and ordinary React composition. format="text" switches to
a <pre>-wrapped plain-text render for an even-more-conservative
preview.
Recipe 3 — Build a custom editor layout
For hosts that want their own pane layout, <ChordSourceArea> (the
CodeMirror 6 editor with ChordPro syntax highlight) and
<RendererPreview> (the format-switching preview pane) compose
freely:
import { useState } from 'react';
import { ChordSourceArea, RendererPreview, SplitLayout } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
export function Editor() {
const [source, setSource] = useState('{title: My Song}\n[G]Hello');
return (
<SplitLayout
start={<ChordSourceArea value={source} onChange={setSource} />}
end={<RendererPreview source={source} format="html" />}
/>
);
}
<ChordSourceArea>was renamed from<SourceEditor>in@chordsketch/reactv0.3.0.
<SplitLayout> exposes a --cs-split-ratio CSS variable for the
two-pane ratio and falls back to a stacked layout under 768 px.
Recipe 4 — Add transposition controls
<Transpose> is an accessible ± / reset control (announces value
changes via aria-live="polite", supports + / - / 0
keyboard shortcuts while focus is inside, clamps to [min, max]).
Pair it with the transpose prop on <ChordSheet>:
import { ChordSheet, Transpose, useTranspose } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
const source = `{title: Hello}\n[Am]hello [F]world`;
export function Sheet() {
const { value, setValue } = useTranspose({ min: -11, max: 11 });
return (
<div>
<Transpose value={value} onChange={setValue} />
<ChordSheet source={source} transpose={value} />
</div>
);
}useTranspose() clamps every update; reset() returns to the
initial value (not necessarily zero).
Recipe 5 — Export to PDF
PDF export ships in a separate heavy bundle so the lean
@chordsketch/wasm core stays small. Install the optional peer
alongside @chordsketch/react:
npm install @chordsketch/wasm-exportThen drop in <PdfExport>:
import { PdfExport } from '@chordsketch/react';
const source = `{title: Amazing Grace}
{key: G}
[G]Amazing [G7]grace, how [C]sweet the [G]sound`;
export function SaveButton() {
return (
<PdfExport source={source} filename="amazing-grace.pdf">
Export PDF
</PdfExport>
);
}The heavy bundle is lazy-loaded on first export — the initial
page load does not pay for it. <PdfExport> exposes the standard
<button> attributes (className, style, type, …) plus
onExported(filename) and onError(err) callbacks for analytics
or toasts.
usePdfExport() returns the same exportPdf pipeline as state for
custom UIs (dropdown items, command palettes, etc.).
Recipe 6 — Render chord diagrams
<ChordDiagram> looks up the chord in the built-in voicing
database (156 voicings: 60 guitar, 36 ukulele, 60 piano) and
returns inline SVG that inherits currentColor:
import { ChordDiagram } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
export function Voicings() {
return (
<>
<ChordDiagram chord="Am" instrument="guitar" />
<ChordDiagram chord="C" instrument="ukulele" />
<ChordDiagram chord="Dm7" instrument="piano" />
</>
);
}Unknown chords render notFoundFallback (default: an inline
role="note" with the chord name). useChordDiagram() returns the
raw SVG string for hosts that want to embed it inside custom markup
(tooltip, popover, etc.).
Recipe 7 — Drive your own UI from the ChordPro AST
For hosts that want to render the song in a completely custom way
— a karaoke prompter, an alternate layout for printing, a
syntax-highlighted source view — use useChordproAst and
renderChordproAst:
import { useChordproAst, renderChordproAst } from '@chordsketch/react';
export function CustomRender({ source }: { source: string }) {
const { ast, warnings, loading, error } = useChordproAst(source);
if (loading) return <p>Loading…</p>;
if (error) return <p role="alert">{error.message}</p>;
if (ast === null) return null;
return (
<article>
<h1>{ast.metadata.title ?? 'Untitled'}</h1>
<div>{renderChordproAst(ast)}</div>
{warnings.length > 0 ? (
<details>
<summary>Warnings ({warnings.length})</summary>
<ul>
{warnings.map((w, i) => (
<li key={i}>{w.message}</li>
))}
</ul>
</details>
) : null}
</article>
);
}renderChordproAst is also the function <ChordSheet format="html">
uses internally — driving it directly gives identical output you
can place anywhere in your tree.
Recipe 8 — Drop in an iReal Pro playground
<IrealProEditor> is the iReal Pro sibling of <ChordProEditor> — a
single-component embed for an iReal Pro chart:
import { IrealProEditor } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
const URL =
'irealb://Autumn%20Leaves%3D%5BT44Cm7%20%7C%20F7%20%7C%20BbMaj7%20%7C%20EbMaj7%20%5D%3DJoseph%20Kosma%3DJazz%20Ballad%3DC';
export default function App() {
return <IrealProEditor defaultValue={URL} />;
}Renamed from
<IrealPlayground>in@chordsketch/reactv0.3.0 per ADR-0022.
The composite shows the editor (header form + interactive bar grid
with structural editing + URL textarea) next to the SVG preview.
hidePreview, hideBars, and hideUrl trim the layout for
narrower hosts; pass source + onChange for controlled mode.
Editing scope.
v0.2.0brings the iReal Pro surface to parity with the private@chordsketch/ui-irealb-editorper ADR-0020: structural section / bar editing, ARIA-grid keyboard navigation, and a popover-based per-bar chord editor with a chord-row editor, N-th ending input, and symbol picker. The playground at https://chordsketch.koeda.me/chordsketch/irealpro/ still hosts the DOM editor for reference comparison.
Recipe 9 — Custom iReal Pro rendering
For hosts that need their own iReal Pro UI, the <IrealPreview>
component renders the SVG directly:
import { IrealPreview, useIrealParse } from '@chordsketch/react';
export function CustomChart({ url }: { url: string }) {
const { song, error } = useIrealParse(url);
return (
<article>
{song !== null ? <h1>{song.title}</h1> : null}
<IrealPreview source={url} />
{error ? <p role="alert">{error.message}</p> : null}
</article>
);
}useIrealParse exposes the typed IrealSong AST so the host can
build any UI on top: a setlist filtered by key_signature.mode, a
search box that matches against composer, a key-changer that
edits song.transpose and re-serialises via useIrealSerialize.
Recipe 10 — Server-side rendering / Next.js
@chordsketch/react's render hooks load @chordsketch/wasm lazily;
on the Node side this means initialising the wasm runtime once per
process. The editor and preview components touch window /
document on mount, so mark consuming files with 'use client' in
Next.js's App Router:
// app/song/[id]/page.tsx
import { ChordSheet } from '@chordsketch/react';
import '@chordsketch/react/styles.css';
export default function Page({ params }: { params: { id: string } }) {
// The component is a Client Component (see below); SSR streams
// its skeleton from the server but the wasm-backed render runs
// on the client where the binary can be cached by the browser.
return <ChordSheet source={`{title: ${params.id}}`} />;
}// app/song/[id]/sheet.tsx
'use client';
import { ChordSheet } from '@chordsketch/react';
export { ChordSheet };In practice, prefer rendering the preview on the client even for
static content — the browser's HTTP cache stores
chordsketch_wasm_bg.wasm once and reuses it across navigations,
which the Node require cache cannot do across deployments.
For pure SSR (e.g. generating an OG image, emailing a PDF), drive
@chordsketch/wasm directly from a Node module and call
render_html_with_options / render_pdf synchronously — the React
components are the wrong layer for non-React server rendering.
See also
- Render to HTML, plain text, or PDF — same operation across every binding (CLI / Rust / Python / Swift / Kotlin / Ruby / wasm), useful if your stack mixes a React client with a non-React server.
- Transpose chords by N semitones — the transposition surface across bindings, for hosts that want to pre-compute transpositions outside React.
packages/react/README.md— the full API reference for@chordsketch/react, including the AST type re-exports and helper functions.- ADR-0020 — why the
iReal Pro React surface is a native React implementation rather
than a wrapper around the private
@chordsketch/ui-irealb-editor.