accidentaljs
v1.0.0
Published
React component for rendering music notation using VexFlow
Maintainers
Readme
accidentaljs
A React component for rendering music notation using VexFlow. Compatible with React and Next.js.
Installation
npm install accidentaljs vexflowor
yarn add accidentaljs vexflowor
pnpm add accidentaljs vexflowUsage
React
import { VexFlowRenderer } from "accidentaljs";
import type { Measure } from "accidentaljs";
const measures: Measure[] = [
{
notes: [
{ keys: ["c/4"], duration: "q" },
{ keys: ["d/4"], duration: "q" },
{ keys: ["e/4"], duration: "q" },
{ keys: ["f/4"], duration: "q" },
],
},
{
notes: [
{ keys: ["g/4"], duration: "8" },
{ keys: ["a/4"], duration: "8" },
{ keys: ["b/4"], duration: "8" },
{ keys: ["c/5"], duration: "8" },
{ keys: ["d/5"], duration: "q" },
{ keys: ["e/5"], duration: "q" },
],
beams: [[0, 1, 2, 3]], // Group first 4 eighth notes with a beam
},
];
function App() {
return (
<VexFlowRenderer
measures={measures}
timeSignature="4/4"
maxCompasesPerRow={2}
/>
);
}Next.js (App Router)
The component includes the "use client" directive, so it works automatically:
import { VexFlowRenderer } from "accidentaljs";
export default function Page() {
const measures = [
{
notes: [
{ keys: ["c/4"], duration: "q" },
{ keys: ["e/4"], duration: "q" },
{ keys: ["g/4"], duration: "q" },
{ keys: ["c/5"], duration: "q" },
],
},
];
return <VexFlowRenderer measures={measures} />;
}Next.js (Pages Router)
For the Pages Router, use dynamic import with SSR disabled:
import dynamic from "next/dynamic";
const VexFlowRenderer = dynamic(
() => import("accidentaljs").then((mod) => mod.VexFlowRenderer),
{ ssr: false }
);
export default function Page() {
const measures = [
{
notes: [
{ keys: ["c/4"], duration: "q" },
{ keys: ["e/4"], duration: "q" },
{ keys: ["g/4"], duration: "q" },
{ keys: ["c/5"], duration: "q" },
],
},
];
return <VexFlowRenderer measures={measures} />;
}Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| measures | Measure[] | required | Array of measures to render |
| timeSignature | TimeSignature | "4/4" | Time signature ("4/4", "3/4", "2/4", "6/8") |
| maxCompasesPerRow | number | 2 | Maximum measures per row |
| fontSize | number | 10 | Font size for notation |
| backgroundColor | string | "#fff" | Background color |
Types
Note
interface Note {
keys: string[]; // e.g., ["c/4", "e/4", "g/4"] for a chord
duration: NoteDuration; // e.g., "q" for quarter, "8" for eighth
accidental?: string; // e.g., "#", "b", "n"
}Measure
interface Measure {
notes: Note[];
beams?: number[][]; // Groups of note indices to beam together
}NoteDuration
type NoteDuration =
| "w" | "h" | "q" | "8" | "16" | "32" | "64" // Notes
| "wr" | "hr" | "qr" | "8r" | "16r" | "32r" | "64r" // Rests
| "wd" | "hd" | "qd" | "8d" | "16d"; // Dotted notesw= whole noteh= half noteq= quarter note8= eighth note16= sixteenth notersuffix = restdsuffix = dotted
TimeSignature
type TimeSignature = "4/4" | "3/4" | "2/4" | "6/8";Examples
With Accidentals
const measures = [
{
notes: [
{ keys: ["c#/4"], duration: "q", accidental: "#" },
{ keys: ["db/4"], duration: "q", accidental: "b" },
{ keys: ["e/4"], duration: "h" },
],
},
];With Beams
const measures = [
{
notes: [
{ keys: ["c/4"], duration: "8" },
{ keys: ["d/4"], duration: "8" },
{ keys: ["e/4"], duration: "8" },
{ keys: ["f/4"], duration: "8" },
{ keys: ["g/4"], duration: "h" },
],
beams: [[0, 1], [2, 3]], // Two groups of beamed eighth notes
},
];Chords
const measures = [
{
notes: [
{ keys: ["c/4", "e/4", "g/4"], duration: "h" }, // C major chord
{ keys: ["d/4", "f/4", "a/4"], duration: "h" }, // D minor chord
],
},
];License
MIT
