React Use Camera
The lightweight library (1.9kb minified + gzipped)
to add camera & photo capture functionality in your React app.
Note: WebRTC is only supported over https so you will need an SSL certificate in production. For development, chrome supports WebRTC even without SSL / https as long as it's running on "localhost".
Install
npm
npm i react-use-camera
yarn
yarn add react-use-camera
Instructions
There are 2 ways to use this library:
- The
<Camera />
component (recommended) - The
useCamera()
hook.
The Camera Component
This gives you a raw camera interface without any opinionated UI elements or buttons. Draw your own UI over the camera stream.
import { useRef } from "react";
import { Camera, CameraElement } from "react-use-camera";
export default function App() {
const cameraRef = useRef<CameraElement>(null);
const handleCapture = async () => {
const imageData = await cameraRef.current?.capture(); // Camera view will pause after capture
// imageData.url is a base64 string that can also be used as src for an <img/> tag
// imageData.blob is a blob string to send to your server
// NOTES:
// (i) Use `cameraRef.current?.capture({ mirror: true });` to flip the captured image (will be enabled by default on front camera)
// (ii) Use `cameraRef.current?.capture({ width: 512 });` to capture image in 512px width (height will be auto calculated)
// (iii) Use `cameraRef.current?.capture({ height: 512 });` to capture image in 512px height (width will be auto calculated)
// (iv) If width or height is not specified, your captured image will be of the same size as the camera resolution
};
const handleClear = () => {
cameraRef.current?.clear(); // Discards the captured photo and resumes the camera view
};
return (
<div>
<Camera
ref={cameraRef}
className="your-classes-here"
style={/* width, height, etc */}
errorLayout={<div>Oops!</div>}
onReady={() => console.log("Camera is now visibile to the user")}
onError={(e) => console.error("Camera couldn't load :(")}
/>
{/* Add your own UI here... */}
<button onClick={handleCapture}>Capture</button>
<button onClick={handleClear}>Clear</button>
</div>
);
}
Props
-
fit
- Type:
fill | contain | cover | blur
- Default:
contain
- Notes:
-
fill
will stretch or squish the video to match the exact width or height that you give to camera component -
contain
will maintain its aspect ratio while fitting within the camera component's width and height. There might be empty spaces around the camera stream. -
cover
will keep the aspect ratio and crop the camera stream to fit the width and height that you give to the camera component. -
blur
will work similar to contain BUT instead of empty spaces around the camera, it will show a blurred version of the camera stream as the background.
-
- Type:
-
constraints
- Type:
MediaTrackConstraints
- Default:
{ facingMode: "user", width: { ideal: 1440 }, height: { ideal: 1080 }}
- Notes:
- If you want to select the front or back camera, you will need to pass
facingMode
asuser
orenvironment
respectively. Default is set touser
i.e. the front camera.
- If you want to select the front or back camera, you will need to pass
- Type:
-
errorLayout
- Type:
ReactNode | JSX
- Default:
undefined
- Notes: This layout will be shown instead of the camera stream in case of an error. For example:
- Browser doesn't support the camera API
- No camera found on the device
- User denied the camera permission
- Type:
-
onError
- Type:
(error: unknown) => void
- Type:
-
onReady
- Type:
() => void
- Type:
The useCamera() Hook
This give you no UI. You just get a MediaStream
instance that you have to attach to a <video />
tag. To capture an image, call the hook's capture
function with the MediaStream
instance or a ref to the <video />
tag as a parameter.
import { useEffect, useState, useRef } from "react";
import { useCamera } from "react-use-camera";
export const MyCustomCameraComponent = () => {
const videoRef = useRef<HTMLVideoElement>(null);
const { startCamera, stopCamera, capture } = useCamera();
const [stream, setStream] = useState<MediaStream>();
const handleStartCamera = async () => {
try {
const stream = await startCamera({ /* MediaTrackConstraints */ })
setStream(stream);
videoRef.current!.srcObject = stream;
} catch (e) {
alert("Oops! Camera failed to start!");
console.error(e);
}
}
const handleStopCamera = () => {
stopCamera(stream);
}
const handleCapture = async () => {
if (!stream) return; // Don't capture if the stream isn't active!
try {
const capturedImage = await capture({ videoRef }, {
mirror: false, // Pass true if you want to mirror the captured image (recommended for front camera)
});
// NOTES:
// (i) To capture using MediaStream instead of a videoRef, use can use `await capture({ stream })`
// (ii) To get the captured image in a custom width, use `await capture({...}, { width: YOUR_REQUIRED_WIDTH })` (height will be auto calculated)
// (iii) To get the captured image in a custom height, use `await capture({...}, { height: YOUR_REQUIRED_HEIGHT })` (width will be auto calculated)
// (iv) If width or height is not specified, your captured image will be of the same size as the camera resolution
if (capturedImage) {
console.log("URL:" + capturedImage.url);
console.log("Blob: " + capturedImage.blob);
}
} catch {
alert("Oops! Unable to capture image. Check if the camera stream is active.");
}
}
return (
<div>
<video
ref={videoRef}
autoPlay
playsInline
/>
<button onClick={handleStartCamera}>Start Camera</button>
<button onClick={handleStopCamera}>Stop Camera</button>
<button onClick={handleCapture}>Capture</button>
</div>
);
}
License
MIT