Skip to content

useDropZone

Turns any element into a file drop zone. Tracks drag-over state and validates file types before accepting drops.

Drag image files here
import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
,
import useDropZone
useDropZone
} from "@usels/core";
function
function MyDropZone(): React.JSX.Element
MyDropZone
() {
const
const el$: Ref$<HTMLDivElement>
el$
=
useRef$<HTMLDivElement>(externalRef?: React.Ref<HTMLDivElement> | undefined): Ref$<HTMLDivElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const {
const files$: any
files$
,
const isOverDropZone$: any
isOverDropZone$
} =
import useDropZone
useDropZone
(
const el$: Ref$<HTMLDivElement>
el$
, {
onDrop: (files: any) => any
onDrop
: (
files: any
files
) =>
any
console
.
any
log
(
files: any
files
),
});
return (
<
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.RefAttributes<HTMLDivElement>.ref?: React.Ref<HTMLDivElement> | undefined

Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).

ref
={
const el$: Ref$<HTMLDivElement>
el$
}
React.HTMLAttributes<HTMLDivElement>.style?: React.CSSProperties | undefined
style
={{
StandardShorthandProperties<string | number, string & {}>.background?: Property.Background<string | number> | undefined

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Syntax: <bg-layer>#? , <final-bg-layer>

| Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | 1 | 1 | 1 | 12 | 4 |

background
:
const isOverDropZone$: any
isOverDropZone$
.
any
get
() ? "#e0e7ff" : "#f9fafb" }}>
Drop files here
</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
,
import useDropZone
useDropZone
} from "@usels/core";
function
function ImageDropZone(): void
ImageDropZone
() {
const
const el$: Ref$<HTMLDivElement>
el$
=
useRef$<HTMLDivElement>(externalRef?: React.Ref<HTMLDivElement> | undefined): Ref$<HTMLDivElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const {
const files$: any
files$
} =
import useDropZone
useDropZone
(
const el$: Ref$<HTMLDivElement>
el$
, {
dataTypes: {}
dataTypes
: ["image/png", "image/jpeg", "image/webp"],
});
// ...
}
const { files$ } = useDropZone(el$, {
checkValidity: (items) => Array.from(items).every((item) => item.type.startsWith("image/")),
});
const { files$ } = useDropZone(el$, {
multiple: false,
onDrop: (files) => files && uploadFile(files[0]),
});
const { files$ } = useDropZone(el$, (files, event) => {
if (files) processFiles(files);
});
export interface UseDropZoneOptions {
dataTypes?: string[] | ((types: readonly string[]) => boolean);
checkValidity?: (items: DataTransferItemList) => boolean;
onDrop?: (files: File[] | null, event: DragEvent) => void;
onEnter?: (files: File[] | null, event: DragEvent) => void;
onLeave?: (files: File[] | null, event: DragEvent) => void;
onOver?: (files: File[] | null, event: DragEvent) => void;
multiple?: boolean;
preventDefaultForUnhandled?: boolean;
}
export interface UseDropZoneReturn {
files$: Observable<File[] | null>;
isOverDropZone$: Observable<boolean>;
}
export declare function useDropZone(target: MaybeElement, options?: DeepMaybeObservable<UseDropZoneOptions> | UseDropZoneOptions["onDrop"]): UseDropZoneReturn;

View on GitHub

  • tigerwest
  • a7392ab 2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)