Jump to a component
Core · Forms
DropZone
Where a file goes: drop or choose. Shows empty, busy (reading the file) and filled states.
Live, from @anicanon/sakuga 2.0.0
Sakuga for iOS and Android is coming
iOS
Coming soon
DropZone for iOS is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
Android
Coming soon
DropZone for Android is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
- Use it for
- Where a file goes, dropped or chosen, then read and held: a clip to bring in.
- Not for
- A page or a list with nothing in it yetEmptyState
- A frame waiting for a picture that will be madeThumb
- Choosing one thing already in the story, such as a placePicker
Guidelines
Motion: state changes fade with motion-fast; entrances use motion-base and ease-enter.
onFiles(files)makes it work: a press opens the file chooser (accept,multiple) and a drop hands over the files.onClickruns first; callpreventDefaultto take the press yourself.
import { DropZone } from '@anicanon/sakuga/ui';
export default function DropZoneExample() {
return (
<>
<DropZone
title="Drop a clip, or choose a file"
hint="Audio or video · up to 30 seconds"
/>
<DropZone
state="busy"
title="Extracting the audio"
hint="hero-shout.mp4"
/>
<DropZone state="filled" title="front.jpg" />
</>
);
}PropsDropZoneProps
state'empty' | 'busy' | 'filled'Default 'empty'titlestringhintstringiconIconNameDefault upload.heightnumberonClickMouseEventHandler<HTMLButtonElement>onFiles(files: File[]) => voidacceptstringmultiplebooleanclassNamestringAn IconName is any of the names Icon lists.
Each token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.
Colour
drop-borderDropZone: dashed edge.border-placeholdershade-a24rgba(11,10,16,0.24)border-placeholderwhite-a22rgba(255,255,255,0.22)drop-hover-borderDropZone: edge on hover.border-controlshade-a52rgba(11,10,16,0.52)border-controlwhite-a45rgba(255,255,255,0.45)drop-fgDropZone: hint.text-mutedneutral-600#5c5b67text-mutedneutral-400#a3a3a7drop-titleDropZone: title.text-primaryneutral-925#0b0a10text-primaryneutral-0#ffffffdrop-iconDropZone: icon.accentcamellia-600#c2335faccentcamellia-400#f4779fdrop-filled-bgDropZone: filled and busy fill.bg-surface-raisedneutral-100#ececf0bg-surface-raisedneutral-875#1a1a21Space and shape
drop-gapgap-mddrop-min-heightdrop-paddinginset-lgdrop-radiusradius-mddrop-inset-ring-widthline-strongdrop-active-scalescale-press-lgdrop-hover-inset-ring-widthline-strongdrop-filled-inset-ring-widthline-hairlinedrop-focus-outline-offsetfocus-ring-offsetdrop-loader-sizedrop-icon-sizeicon-size-lgType
drop-fonttext-captiondrop-b-fonttext-labelMotion
drop-durationmotion-fastdrop-easingease-standarddrop-active-durationmotion-instantChecked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.
- Result
- No issues found, in light or in dark.
- By design
- A button that Tab reaches, named by its
titleandhint(and "added" once filled), with the icon hidden; while busy it carries aria-busy, says its title and hint once through the page's live region as it starts, and its loader stays quiet. WithonFiles, Enter, Space or a click open the file chooser (afteronClick, which can prevent it) and a drop hands the files over. - Not tested
- The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.