use-web-midi
Access MIDI devices with the Web MIDI API.
| Package | @vizejs/composable/use-web-midi |
| Own the source | vize lib pull composable:use-web-midi |
| Runtime exports | useWebMIDI |
| Gzip budget | 2304 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useWebMIDI } from "@vizejs/composable/use-web-midi";
Try it
List MIDI controllers
Ask for MIDI access and show the connected keyboards and controllers.
What to observe: Allow MIDI access asks for permission where Web MIDI exists; the inputs appear once access is granted.
onMessage receives note and control messages. Request sysex only when you need it, because it asks for more permission. Every example renders a neutral message until it mounts, so server and client markup match, and then explains what to do when the browser lacks the API.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { useMounted } from "@vizejs/composable/use-mounted";
import { useWebMIDI } from "@vizejs/composable/use-web-midi";
const mounted = useMounted();
const { supported, status, inputs, request } = useWebMIDI();
</script>
<template>
<div class="composable-example">
<p>List MIDI keyboards and controllers after the reader allows access.</p>
<button type="button" :disabled="!mounted || !supported" @click="() => request()">
Allow MIDI access
</button>
<ul aria-label="MIDI inputs">
<li v-for="input in inputs" :key="input.id">{{ input.name }}</li>
</ul>
<output aria-live="polite">{{
!mounted
? "Checking browser support…"
: supported
? `MIDI access: ${status}`
: "Web MIDI is not available in this browser."
}}</output>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useWebMIDI |
system | experimental | deterministic-fallback | caller-managed | reactive-scope, returned-value | web, desktop | window |
tryOnScopeDispose |
API
useWebMIDI
Access MIDI devices with the Web MIDI API. Nothing is requested until request() is called. Once granted, inputs and outputs follow statechange events, and onMessage receives messages from every input. Failures land in error. Listeners are removed when the owning reactive scope stops; outside a scope call stop(). Server rendering: supported is false, status stays "idle" and no access is requested.
function useWebMIDI(options: UseWebMIDIOptions = {}): WebMIDIControls
const midi = useWebMIDI({ onMessage: ({ data }) => console.log(data) });
await midi.request();
midi.send(midi.outputs.value[0]!.id, [0x90, 60, 127]);
Types
MIDIPortLike
Minimal MIDIPort read by useWebMIDI.
| Member | Type | Description |
|---|---|---|
id |
string |
Stable port identifier. |
name? |
string | null |
Port name. |
manufacturer? |
string | null |
Manufacturer name. |
state |
string |
Device state. |
connection |
string |
Connection state. |
MIDIOutputLike
Minimal MIDIOutput used by useWebMIDI.
| Member | Type | Description |
|---|---|---|
id |
string |
Stable port identifier. |
name? |
string | null |
Port name. |
manufacturer? |
string | null |
Manufacturer name. |
state |
string |
Device state. |
connection |
string |
Connection state. |
send |
(data: number[], timestamp?: number) => void |
Send one or more MIDI messages, optionally scheduled at timestamp. |
MIDIAccessLike
Minimal MIDIAccess used by useWebMIDI.
| Member | Type | Description |
|---|---|---|
inputs |
{ values(): Iterable<MIDIPortLike> } |
Available inputs. |
outputs |
{ values(): Iterable<MIDIOutputLike> } |
Available outputs. |
MIDIRequestFlags
Access request flags of navigator.requestMIDIAccess.
| Member | Type | Description |
|---|---|---|
sysex? |
boolean |
Request system-exclusive message access. |
software? |
boolean |
Include software synthesizers. |
MIDIHost
Navigator-like capability used by useWebMIDI.
| Member | Type | Description |
|---|---|---|
requestMIDIAccess |
(options?: MIDIRequestFlags) => Promise<MIDIAccessLike> |
Request MIDI access. |
MIDIPortInfo
Plain description of one MIDI port.
| Member | Type | Description |
|---|---|---|
id |
string |
Stable port identifier. |
name |
string |
Port name (empty when unknown). |
manufacturer |
string |
Manufacturer (empty when unknown). |
state |
string |
Device state, e.g. "connected" or "disconnected". |
connection |
string |
Connection state, e.g. "open", "closed" or "pending". |
MIDIInputMessage
A message received on an input port.
| Member | Type | Description |
|---|---|---|
data |
Uint8Array |
Raw message bytes. |
timeStamp |
number |
Event timestamp in milliseconds. |
inputId |
string |
Identifier of the receiving input. |
UseWebMIDIOptions
Options for useWebMIDI.
| Member | Type | Description |
|---|---|---|
host? |
MaybeRefOrGetter<MIDIHost | null | undefined> |
Navigator-like MIDI capability. |
sysex? |
boolean |
Request system-exclusive access. |
software? |
boolean |
Include software synthesizers. |
onMessage? |
(message: MIDIInputMessage) => void |
Receives every input message. When set, midimessage listeners are attached to all inputs (which implicitly opens them). |
WebMIDIControls
Reactive state and actions returned by useWebMIDI.
| Member | Type | Description |
|---|---|---|
supported |
ComputedRef<boolean> |
Whether Web MIDI is available. |
status |
Readonly<Ref<MIDIAccessStatus>> |
Access request status. |
inputs |
Readonly<ShallowRef<readonly MIDIPortInfo[]>> |
Input ports, refreshed on statechange. |
outputs |
Readonly<ShallowRef<readonly MIDIPortInfo[]>> |
Output ports, refreshed on statechange. |
error |
Readonly<ShallowRef<unknown>> |
Most recent request or send failure. |
request |
() => Promise<boolean> |
Request MIDI access (may prompt the user). |
send |
( outputId: string, data: Uint8Array | readonly number[], timestamp?: number, ) => boolean |
Send bytes to an output. |
stop |
() => void |
Remove every listener and forget the access object. Idempotent. |