Skip to content
Sensors

useDisplayMedia

Reactive wrapper around the MediaDevices.getDisplayMedia() API for screen sharing. Provides start/stop controls and automatically handles the browser's "Stop sharing" button.

Display Media
Not Supported

Share your screen via getDisplayMedia. Click Start to begin sharing.

No screen shared
import {
const useDisplayMedia: (options?: DeepMaybeObservable<UseDisplayMediaOptions>) => UseDisplayMediaReturn
useDisplayMedia
} from "@usels/web";
function
function ScreenShare(): JSX.Element
ScreenShare
() {
const {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
,
const stream$: ReadonlyObservable<OpaqueObject<MediaStream> | null>

Current display media stream

stream$
,
const enabled$: ReadonlyObservable<boolean>

Whether stream is currently active

enabled$
,
const start: () => Promise<MediaStream>

Start screen sharing. Throws if getDisplayMedia fails.

start
,
const stop: () => void

Stop screen sharing

stop
} =
function useDisplayMedia(options?: DeepMaybeObservable<UseDisplayMediaOptions>): UseDisplayMediaReturn

Framework-agnostic reactive wrapper around MediaDevices.getDisplayMedia().

Provides start/stop controls and automatically handles the browser's "Stop sharing" button via a per-track ended listener.

useDisplayMedia
();
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Supported: {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "Yes" : "No"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Sharing: {
const enabled$: ReadonlyObservable<boolean>

Whether stream is currently active

enabled$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "Yes" : "No"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const start: () => Promise<MediaStream>

Start screen sharing. Throws if getDisplayMedia fails.

start
()}>Share Screen</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const stop: () => void

Stop screen sharing

stop
()}>Stop</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
// @noErrors
import { useDisplayMedia } from "@usels/web";
function ScreenShareWithAudio() {
const { stream$, start, stop } = useDisplayMedia({
video: true,
audio: true,
});
return (
<div>
<button onClick={() => start()}>Share with Audio</button>
<button onClick={() => stop()}>Stop</button>
</div>
);
}

Options can be passed as plain values, per-field Observables, or a single Observable<UseDisplayMediaOptions>. video and audio are read at each start() call, so changes take effect on the next share.

import { observable } from "@usels/core";
import { useDisplayMedia } from "@usels/web";
const audio$ = observable(false);
const { start } = useDisplayMedia({
video: true,
audio: audio$,
});
// Later: enable audio capture reactively
audio$.set(true);
start(); // uses updated audio constraint

options is DeepMaybeObservable. Each option field can be a plain value or an Observable. video and audio are read at each start() call time. immediate is mount-time-only.

View on GitHub