@dev-nat/use-webcam
v1.0.0
Published
A tiny, dependency-free React hook for working with the webcam: enumerate cameras, start and stop streams, and capture an image — all in a few lines of code.
Downloads
49
Readme
useWebcam
A tiny, dependency-free React hook for working with the webcam: enumerate cameras, start and stop streams, and capture an image — all in a few lines of code.
Built on the native Media Capture and Streams API — no external dependencies.
Features
- Camera enumeration — lists available video input devices, automatically unlocking device names via a one-time permission prompt.
- Stream switching – select a camera and the hook handles starting/stopping the stream, releasing tracks so the indicator light turns off.
- Frame capture – grab a snapshot as a data URL (default) or a downloadable
File. - Cleanup handled – in-flight
getUserMediarequests and active tracks are released on unmount/camera change, preventing leaks. - Type safe – written in TypeScript with generated type declarations.
Installation
npm install @dev-nat/use-webcamyarn add @dev-nat/use-webcampnpm add @dev-nat/use-webcamUsage
import { useRef } from 'react'
import { useWebcam } from '@dev-nat/use-webcam'
export function Camera() {
const { cameras, videoRef, isStreaming, capture } = useWebcam()
return (
<>
{cameras.length > 0 && (
<select>
{cameras.map((camera) => (
<option key={camera.deviceId} value={camera.deviceId}>
{camera.label}
</option>
))}
</select>
)}
<video ref={videoRef} autoPlay playsInline muted />
{isStreaming && (
<button onClick={() => capture()}>Take picture</button>
)}
</>
)
}Note: The
selectabove doesn't wire up device switching — see the API reference and selecting a camera below.
API
useWebcam() returns an object with the following fields:
| Field | Type | Description |
| ----------------------- | --------------------- | --------------------------------------------------------------------------------------------- |
| cameras | MediaDeviceInfo[] | The list of available video input devices. |
| selectedDeviceId | string | The currently selected camera's deviceId. Defaults to the first camera. |
| setSelectedDeviceId | (id: string) => void| Switch to a different camera by deviceId. |
| videoRef | RefObject<HTMLVideoElement> | Attach to a <video> element to render the stream. |
| isStreaming | boolean | Whether the camera stream is currently active. |
| error | Error \| null | The last error (e.g. permission denied), or null if no error. |
| capture | async (format?) => string \| File \| null | Captures a snapshot of the current frame. |
capture(format?)
Captures the video's current frame to a canvas.
'base64'(default) — returns a JPEGdata:URL string.'file'– returns a downloadable JPEGFileobject.
Returns null if the video isn't loaded or the frame can't be drawn.
const { capture } = useWebcam()
// Format options:
const dataUrl = await capture() // 'base64' (default)
const imageFile = await capture('file') // File objectSelecting a camera
The returned selectedDeviceId / setSelectedDeviceId pair gives you full
control over which camera is active. Building on the example above:
import { useRef } from 'react'
import { useWebcam } from '@dev-nat/use-webcam'
export function CameraSwitcher() {
const { cameras, selectedDeviceId, setSelectedDeviceId, videoRef, capture } =
useWebcam()
return (
<>
<select
value={selectedDeviceId}
onChange={(e) => setSelectedDeviceId(e.target.value)}
>
{cameras.map((camera) => (
<option key={camera.deviceId} value={camera.deviceId}>
{camera.label}
</option>
))}
</select>
<video ref={videoRef} autoPlay playsInline muted />
<button onClick={() => capture('file')}>Download photo</button>
</>
)
}Example: handling errors
Permission and hardware errors are reported through the error field:
const { error, isStreaming } = useWebcam()
if (error) {
console.error(error.message)
}Requirements
- React
^19with React DOM. - The hook uses
'use client'semantics and only runs in the browser — it is not intended for server-side rendering.
