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".
npm i react-use-camera
yarn add react-use-camera
There are 2 ways to use this library:
- The
<Camera />
component (recommended) - The
useCamera()
hook.
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>
);
}
-
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 componentcontain
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:
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>
);
}
MIT