henryavila/laravel-nova-chordpro-field
A Laravel Nova field for editing and displaying ChordPro song lyrics with chords, giving Nova resources a clean, dedicated input experience.
The package adds a Nova field that stores and displays ChordPro song text — lyrics with inline chords ([C]Amazing [F]grace) plus directives such as {title:}, {key:} and, as of 1.2.0, {capo:}.
composer require henryavila/laravel-nova-chordpro-field
TEXT (not VARCHAR) column to hold the raw ChordPro source, e.g. songs.content.Song resource:
use HenryAvila\ChordproField\Chordpro;
public function fields(NovaRequest $request)
{
return [
Text::make('Title'),
Chordpro::make('Content')
->rules('required', 'string', 'max:65535')
->help('Paste ChordPro text. Use {capo: n} for a capo warning.'),
];
}
resources/js/components/FormField.vue / DetailField.vue, and the README's directive examples. The 1.2.0 diff is small enough to read in full — it lives in the detail/display component where {capo:} is parsed and surfaced.Store source, render on read. Keep the DB column as the raw ChordPro string and let the field handle parsing on the Detail/Index side. Never store HTML — you lose the ability to re-render after a chord library upgrade or a capo/transpose change.
Capo as metadata, not as transposition. {capo: 2} tells the performer to clamp fret 2; it does not mean "transpose the chords by 2". The 1.2.0 feature is a display concern — a badge/hint in the field output. If you also want transposed chords, do the math yourself in an accessor and feed the field a derived string (or a separate read-only field):
Chordpro::make('Content')->onlyOnDetail(),
Text::make('Capo', fn () => $this->capo_fret)->onlyOnDetail(),
Parse the directive once, reuse it. If you need the capo value in the UI outside the field (badges on the index, setlist printouts), regex the stored source rather than duplicating parsing logic:
protected function capoFret(): int
{
preg_match('/^\s*\{capo:\s*(\d+)\s*\}/mi', $this->content ?? '', $m);
return (int) ($m[1] ?? 0);
}
Compose with a renderer only if needed. The Nova field gives you editing and a metadata-aware preview; it is not a full lead-sheet renderer. For public-facing song pages, render server-side from the same stored string (e.g. a ChordPro-to-HTML library or a Blade partial) so the Nova preview and the front end agree on directives.
Validation and normalisation. Use ->rules() plus a ->fillUsing() or model mutator to normalise line endings and trim stray whitespace around directives — ChordPro parsers are line-oriented and brittle about indentation.
Index columns. For lists, prefer a truncated plain text column over the ChordPro field:
Text::make('Title')->sortable(),
Text::make('Capo', fn () => $this->capo_fret ?: '—')->onlyOnIndex(),
{capo: 2} indented by a space, or inline after lyrics, will be ignored by most ChordPro parsers — including whatever the field uses. Normalise on save.composer update is safe; pin ^1.1 if you need to freeze.{capo: 0} and {capo:} before casting to int.DetailField.vue before opening the field to non-admin users.TEXT/MEDIUMTEXT; a VARCHAR(255) truncation looks like a parsing bug and is a bad afternoon.{title: …} inside a Blade {{ }} context is a common self-inflicted breakage.vendor:publish then npm run build) — editing files under vendor/ is lost on the next composer update, and forgetting the rebuild makes the capo display silently fail to appear.nova.log first.$song->getRawOriginal('content')) to separate "editor mangled the input" from "renderer didn't parse it". Almost every reported capo bug is the former.How can I help you explore Laravel packages today?