File input
The native <input type="file">, styled in place — no wrapper and no JavaScript.
Add .re-file and the browser’s own “Choose file” button is restyled via
::file-selector-button, while the filename text the browser renders after it
stays native (and accessible).
<div class="stack">
<label class="re-field">
<span class="re-field__label">Resume</span>
<input type="file" class="re-file" name="resume" />
</label>
<label class="re-field">
<span class="re-field__label">Attachments</span>
<input type="file" class="re-file" name="attachments" multiple />
<span class="re-field__hint">You can select more than one file.</span>
</label>
</div> <div class="stack">
<input type="file" class="re-file" data-size="sm" aria-label="Small file input" />
<input type="file" class="re-file" aria-label="Medium file input" />
<input type="file" class="re-file" data-size="lg" aria-label="Large file input" />
</div> States
Section titled “States”<div class="stack">
<input type="file" class="re-file" aria-label="Invalid file input" aria-invalid="true" />
<input type="file" class="re-file" aria-label="Disabled file input" disabled />
</div> Accessibility
Section titled “Accessibility”- Keyboard — fully native. Tab moves focus to the control; Space / Enter opens the OS file picker. There is no custom keyboard layer.
- Focus — a visible
:focus-visiblering (--re-shadow-focus, replacing the default outline) frames the whole control, drawn on the field rather than the inner button so it isn’t clipped. - Semantics — it remains a real
<input type="file">, so the file picker,multiple,accept, the selected-files list, and form submission are all native. Give it a name with a wrapping<label class="re-field">(oraria-label); the filename text (“No file chosen” / “report.pdf”) is rendered by the browser, so it reaches assistive tech without any extra markup. Invalid state usesaria-invalid="true"(or:user-invalid), matching the other inputs. - Notes — only the
::file-selector-buttonand the field’s border/focus are styled; the button is a neutral fill (--re-color-bg-muted, which stays distinct from the field surface in dark mode) with a solid border so it remains a recognizable button under@media (forced-colors: active), where the fill flattens to a system color.:disableddims the control, shows anot-allowedcursor, and is removed from the tab order natively. See the accessibility guide.