The zone that stops inviting
A dropzone with a file already in it kept saying "Drag a file here". Nothing threw, no test went red, and the screen was lying.
On the invoices screen at nosferry.com, whoever issues the official invoice attaches the PDF in a side sheet. Everything in that sheet was ours. The typography, the spacing, the radii, the dark mode. Everything except one control, which read Choose File No file chosen in Chrome’s own font, in English, and could not be styled by anyone. A file field was the one place in the product where the product stopped looking like itself.
So @akira-io/ui got a Dropzone. That is not the interesting part. Every design system gets one eventually.
The interesting part came after, with the component mounted on the real screen and a real PDF attached to it, still saying Drag a file here.
It could not take another. multiple was off, a file was already chosen, and the next drop would replace what was there without a word. The zone was advertising a capacity it did not have. Nothing threw. No test went red. The screen made a promise the code would not keep.
The fix is one line:
const inviting = multiple || chosen.length === 0;
With a file chosen and no multiple, the drop area, its label and its trigger stop rendering. What is left is the file, its size, and the control that removes it. Replacing means removing first. Under multiple nothing changes, because another file still fits. The root and the hidden input stay mounted either way, so the invitation is what disappears, never the plumbing.
The obvious objection holds. That is one more state to maintain, and it costs a click nobody paid before. It is still the cheaper side. A false invitation is a defect nobody reports: you drop a second file, you watch the first one vanish, and you stop trusting the sheet. The extra click is visible. The broken promise is not.
None of this came from the design. It came from having the component mounted on the screen it was built for, with real content inside it. A component looks finished in isolation because isolation is where it has nothing to contradict.
A control that offers what it cannot accept is already broken, even when nothing crashes.