Device Selector
Choose which microphone, camera, or speaker a call uses. It composes Dropdown Menu — a radio group of devices with the active one checked — and docks against a Media Toggle as a split control.
Mic: MacBook Pro Microphone
tsx
"use client"
import * as React from "react"
import {
DeviceSelector,
DeviceSelectorContent,
DeviceSelectorTrigger,
} from "@/registry/seam/ui/device-selector"
const DEVICES = [
{ deviceId: "default", label: "MacBook Pro Microphone" },
{ deviceId: "airpods", label: "AirPods Pro" },
{ deviceId: "yeti", label: "Blue Yeti" },
]
export default function DeviceSelectorDemo() {
const [value, setValue] = React.useState("default")
return (
<div className="flex flex-col items-center gap-3">
<DeviceSelector devices={DEVICES} value={value} onValueChange={setValue}>
<DeviceSelectorTrigger />
<DeviceSelectorContent />
</DeviceSelector>
<p className="text-muted-foreground text-sm">
Mic: {DEVICES.find((d) => d.deviceId === value)?.label}
</p>
</div>
)
}bunx --bun @seamui/cli@latest add device-selectorNotes
- Pass a
devicesarray to control the list, or omit it and the owneduseMediaDeviceshook enumerates real hardware and re-lists ondevicechange. The shape maps onto the LiveKituseMediaDeviceSelecthook with no runtime dependency. - Device labels are empty until mic/camera permission is granted, so the hook falls back to “Microphone 2”-style names until then.
- No new motion — the trigger presses via the dogfooded Button and the menu rises at overlay depth, all inherited from Dropdown Menu.
- Full menu semantics from Base UI: roving focus, typeahead, and a checked radio item for the active device. The trigger carries an
aria-label.
Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.