Vize

use-serial

Talk to serial devices with the Web Serial API.

Package @vizejs/composable/use-serial
Own the source vize lib pull composable:use-serial
Runtime exports useSerial
Gzip budget 2560 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 { useSerial } from "@vizejs/composable/use-serial";

Try it

Read a microcontroller's log

Open a serial port and stream decoded text lines from a connected board.

Open the interactive example

What to observe: Connect a board opens the port chooser where Web Serial exists; incoming lines appear in the output area.

decode: "text" decodes chunks as UTF-8 and onData receives each chunk. Set the baud rate your board uses. 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
Read a microcontroller's log: initial state
Initial state
Read a microcontroller's log: state after the verified interactions
After the verified interactions

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 { ref } from "vue";
import { useMounted } from "@vizejs/composable/use-mounted";
import { useSerial } from "@vizejs/composable/use-serial";

const mounted = useMounted();
const lines = ref<string[]>([]);
const { supported, connected, requestPort, open, close } = useSerial({
  decode: "text",
  onData: (chunk) => {
    lines.value = [...lines.value, String(chunk)].slice(-5);
  },
});

async function connectBoard() {
  const port = await requestPort();
  if (port) await open(port, { baudRate: 115200 });
}
</script>

<template>
  <div class="composable-example">
    <p>Read log lines from a microcontroller over a serial port.</p>
    <div class="example-actions">
      <button type="button" :disabled="!mounted || !supported || connected" @click="connectBoard">
        Connect a board
      </button>
      <button type="button" :disabled="!connected" @click="() => close()">Disconnect</button>
    </div>
    <pre aria-label="Serial output">{{ lines.join("\n") }}</pre>
    <output aria-live="polite">{{
      !mounted
        ? "Checking browser support…"
        : supported
          ? connected
            ? "Reading from the board."
            : "Ready to connect."
          : "Web Serial is not available in this browser."
    }}</output>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useSerial system experimental deterministic-fallback caller-managed reactive-scope, returned-value web, desktop window tryOnScopeDispose

API

useSerial

Talk to serial devices with the Web Serial API. requestPort() prompts for a port, open() opens it and starts a read loop that feeds onData with bytes or decoded text, write() sends text or bytes. ports follows the host's connect / disconnect events and a port's own disconnect closes the session. Failures land in error. The read loop is cancelled and the port closed when the owning reactive scope stops; outside a scope call close(). Server rendering: supported and connected are false, nothing is read.

function useSerial<const Decoding extends SerialDecoding = "bytes">( options: UseSerialOptions<Decoding> = {}, ): SerialControls
const serial = useSerial({ decode: "text", onData: (text) => log(text) });
const port = await serial.requestPort([{ usbVendorId: 0x2341 }]);
if (port) await serial.open(port, { baudRate: 115200 });

Types

SerialPortFilter

USB identifiers used to filter requestPort.

Member Type Description
usbVendorId? number USB vendor id.
usbProductId? number USB product id.
bluetoothServiceClassId? number | string Bluetooth RFCOMM service class id.

SerialOpenOptions

Line settings passed to SerialPort.open.

Member Type Description
baudRate number Baud rate, e.g. 9600 or 115200.
dataBits? number Data bits per frame (7 or 8).
stopBits? number Stop bits (1 or 2).
parity? "none" | "even" | "odd" Parity mode.
bufferSize? number Read/write buffer size in bytes.
flowControl? "none" | "hardware" Flow control mode.

SerialPortLike

Minimal SerialPort used by useSerial.

Member Type Description
readable ReadableStream<Uint8Array> | null Byte stream from the device while open; null otherwise or after a fatal error.
writable WritableStream<Uint8Array> | null Byte sink to the device while open.
open (options: SerialOpenOptions) => Promise<void> Open the port.
close () => Promise<void> Close the port.

SerialHost

navigator.serial-like capability used by useSerial.

Member Type Description
getPorts () => Promise<SerialPortLike[]> Ports the page already has access to.
requestPort (options?: { readonly filters?: readonly SerialPortFilter[]; }) => Promise<SerialPortLike> Prompt the user for a port.

UseSerialOptions

Options for useSerial.

Member Type Description
host? MaybeRefOrGetter<SerialHost | null | undefined> navigator.serial-like capability.
decode? Decoding Deliver raw bytes or text decoded with encoding (streaming, so split multi-byte characters are joined).
encoding? string Text encoding used when decode is "text".
onData? (chunk: SerialChunk<Decoding>) => void Receives every chunk read from the open port.

SerialControls

Reactive state and actions returned by useSerial.

Member Type Description
supported ComputedRef<boolean> Whether Web Serial is available.
ports Readonly<ShallowRef<readonly SerialPortLike[]>> Ports the page has access to, refreshed on connect / disconnect.
port Readonly<ShallowRef<SerialPortLike | undefined>> Currently open port.
connected Readonly<Ref<boolean>> Whether a port is open.
error Readonly<ShallowRef<unknown>> Most recent failure (request, open, read, write).
requestPort ( filters?: readonly SerialPortFilter[], ) => Promise<SerialPortLike | undefined> Prompt the user for a port (requires user activation).
getPorts () => Promise<readonly SerialPortLike[]> Refresh ports.
open (port: SerialPortLike, options: SerialOpenOptions) => Promise<boolean> Open port (closing any other open port) and start the read loop.
write (data: string | Uint8Array) => Promise<boolean> Write text (UTF-8 encoded) or bytes.
close () => Promise<void> Stop reading and close the open port. Idempotent.