<midi-player> HTML elements powered by Midy.

The simplest example with no extra styles.
旅 OLD WOODS HUT 黒木健太

1. Import the appropriate level of Midy.

import { MidyGMLite as Midy } from "midy/dist/midy-GMLite.min.js";
// import { MidyGM1 as Midy } from "midy/dist/midy-GM1.min.js";
// import { MidyGM2 as Midy } from "midy/dist/midy-GM2.min.js";
// import { Midy } from "midy/dist/midy.min.js";

const audioContext = new AudioContext();
if (audioContext.state === "running") await audioContext.suspend();
const midy = new Midy(audioContext);

2. Add player.

const midiPlayer = new MIDIPlayer(midy);
midiPlayer.defaultLayout();
document.getElementById("simpleTest").appendChild(midiPlayer.root);
await midiPlayer.loadMIDI("midi/travel.mid");

You can also replace icons via constructor options:

const midiPlayer = new MIDIPlayer(midy, {
  icons: {
    play: `<svg ...>...</svg>`,
    pause: `<svg ...>...</svg>`,
    // volumeOn, volumeOff, speed, repeatOff, repeatOn
  },
});
An example of styling using ::part.
人心2-HitoGokoro2- 煉獄庭園 煉獄小僧

Each element inside the shadow DOM exposes a part attribute, so you can style it from outside with ::part.

midi-player::part(midi-player-btn) {
  border: 1px solid #aaa;
  border-radius: 4px;
  padding: 2px;
  cursor: pointer;
}
midi-player::part(midi-player-btn):hover {
  background: rgba(0, 0, 0, 0.08);
}
midi-player::part(midi-player-text) {
  padding: 0 4px;
  font-size: 0.85em;
}
const midiPlayer = new MIDIPlayer(midy);
midiPlayer.defaultLayout();
document.getElementById("partTest").appendChild(midiPlayer.root);
await midiPlayer.loadMIDI("midi/hitogo2.mid");
An example of styling using Bootstrap via applyTheme(). You can use any CSS frameworks.
テーマ02 魔王魂 森田交一 (CC-BY-4.0)

Pass a CSSStyleSheet and a class map to applyTheme(). The stylesheet is added to adoptedStyleSheets; the class map appends extra classes to matching elements inside the shadow DOM.

// Build a CSSStyleSheet from document styles once and reuse it.
// Call this after external stylesheets (e.g. Bootstrap) have loaded.
// In a type="module" script this is guaranteed; in an inline script
// call it inside DOMContentLoaded.
const sheet = new CSSStyleSheet();
let css = "";
for (const s of document.styleSheets) {
  try { for (const r of s.cssRules) css += r.cssText; }
  catch { /* skip cross-origin sheets */ }
}
sheet.replaceSync(css);

// Call applyTheme() after defaultLayout() so shadow DOM elements exist.
const midiPlayer = new MIDIPlayer(midy);
midiPlayer.defaultLayout();
midiPlayer.applyTheme(sheet, {
  "midi-player-btn": "btn bg-light-subtle p-1",
  "midi-player-text": "p-1",
  "midi-player-range": "form-range",
});
document.getElementById("stylingTest").appendChild(midiPlayer.root);
await midiPlayer.loadMIDI("midi/hitogo2.mid");
An example of arranging layout.
Giselle - Pas de deux (1er Acte) Mutopia Project Adolphe-Charles Adam (Public Domain)
function arrangeLayout(midiPlayer) {
  const div = midiPlayer.row();
  div.appendChild(midiPlayer.playPauseResume());
  div.appendChild(midiPlayer.seekBar());
}

const midiPlayer = new MIDIPlayer(midy);
arrangeLayout(midiPlayer);
midiPlayer.applyTheme(sheet, {
  "midi-player-btn": "btn bg-light-subtle p-1",
  "midi-player-range": "form-range",
});
document.getElementById("arrangingTest").appendChild(midiPlayer.root);
await midiPlayer.loadMIDI("midi/0002.mid");