FileInput
FileInput preserves native file selection, FileList access, picker security, and form behavior without owning an upload workflow.
Overview and decision boundary
Use FileInput for native single or multiple file selection when the product owns everything that happens after selection.
Do not add upload requests, Dropzone behavior, previews, queues, progress, retry, storage, or product validation policy to FileInput.
Choose one PDF or image file.
import { Field, FileInput } from '@nerio-ui/ui';<Field label="Attachment" description="Choose one PDF or image file."><FileInput name="attachment" accept=".pdf,image/*" /></Field>Installation and imports
Install the editable registry source, or use the matching package entrypoint when the product keeps Nerio as a workspace dependency.
pnpm exec nerio add file-inputimport { Field, FileInput } from '@nerio-ui/ui';Usage
import { Field, FileInput } from '@nerio-ui/ui';<Field label="Attachment" description="Choose one PDF or image file."><FileInput name="attachment" accept=".pdf,image/*" /></Field>Variants
| Variant | Description |
|---|---|
Single | Default native single-file selection. |
Multiple | Native multiple selection without upload queue behavior. |
Accept and capture | Platform hints that do not replace consumer validation. |
Anatomy
| Slot | Description |
|---|---|
file-input-root | Layout wrapper for the input and decorative icon. |
file-input | Native input, picker trigger, and browser file summary. |
file-input-icon | Decorative upload icon over the compact native selector. |
States
| State | Behavior |
|---|---|
Default | One native file-selection control with browser-owned picker chrome. |
Multiple | The native multiple attribute returns one FileList with every selection. |
Required | Native form validity requires a selection before submission. |
Invalid | aria-invalid and the shared danger boundary communicate an actual error. |
Disabled | The native disabled attribute prevents selection and form submission. |
Motion
- Hover and focus transition through shared control motion tokens.
- Reduced motion keeps every state visible without nonessential timing.
Accessibility
- Use with Label or Field, aria-label, or aria-labelledby so the native file input has an accessible name.
- The native input remains visible, focusable, and available to assistive technology; browser picker and security behavior stay platform-owned.
- Supports accept, capture, multiple, name, form, required, disabled, aria-describedby, and native form reset.
- Read FileList from event.currentTarget.files or the forwarded HTMLInputElement ref.
- The public API rejects controlled value, defaultValue, readOnly, and alternate input types because browsers prohibit populating file selection.
- Accept and capture are native picker hints; consumers own file validation and localized messages.
- Uploads, Dropzone, previews, queues, progress, retries, persistence, and storage remain consumer or Pro responsibilities.
Review the shared responsibility and evidence boundaries in the Accessibility foundation alongside this component-specific contract. Use the Spacing & layout foundation for shared density, wrapping, overflow, reflow, and component-versus-product ownership guidance. The Color foundation, Typography foundation, and Localization foundation define the shared visual-role, text-resilience, direction, and locale boundaries used by component examples.
API
| Prop | Type | Description |
|---|---|---|
accept | string | Native picker hint for file extensions or MIME types. |
multiple | boolean | Allows more than one selected file in FileList. |
capture | boolean | "user" | "environment" | Native compatible-device capture hint. |
name / form / required / disabled | native props | Form ownership and validity behavior. |
onChange | ChangeEvent<HTMLInputElement> | Reads event.currentTarget.files directly. |
ref | HTMLInputElement | Accesses files, validity, focus, and an intentional reset path. |
size | sm | md | lg | Shared Core control geometry. |
invalid | boolean | Normalizes data-invalid and aria-invalid. |
Implementation contract
| Contract | Value |
|---|---|
Semantic root | Native input type=file |
Entrypoint | @nerio-ui/ui |
State | No mirrored FileList or hidden interactive input |
Reset | Native form reset, intentional remount, or direct empty ref value |
Boundary | Selection only; uploads and file workflows remain consumer or Pro work |
Styling contract
| Contract | Value |
|---|---|
Authoring | Complete, statically detectable Tailwind CSS v4 recipes own component visuals. |
Values | Semantic and component --n-* variables remain the canonical customization layer. |
Overrides | Customizable slots merge consumer className values with tailwindCn so conflicting utilities resolve deterministically. |
Residual CSS | Only shared keyframes and scoped no-Preflight compatibility rules remain; there is no parallel visual selector layer. |
Design notes
- FileInput is server-safe and renders one native input without mirrored selection state.
- Browser file-picker chrome and security restrictions remain platform-owned.
- Consumers may render localized file summaries outside the primitive from the change event.
Do / do not
- Provide a visible label and explain accepted formats nearby.
- Read FileList from the change event or forwarded ref.
- Validate files and localize summaries in consumer code.
- Hide the native input from assistive technology or the tab order.
- Programmatically populate a file value.
- Add Dropzone, previews, queues, progress, retries, or storage to Core.
Related components
Tokens
These are the primary customization points. Override semantic or component tokens instead of changing component source.
| Token | Purpose |
|---|---|
--n-input-height-md | Public customization point for this component contract. |
--n-input-height-sm | Public customization point for this component contract. |
--n-input-height-lg | Public customization point for this component contract. |
--n-input-radius | Public customization point for this component contract. |
--n-input-background | Public customization point for this component contract. |
--n-input-background-hover | Public customization point for this component contract. |
--n-input-border | Public customization point for this component contract. |
--n-input-border-hover | Public customization point for this component contract. |
--n-input-border-focus | Public customization point for this component contract. |
--n-input-border-danger | Public customization point for this component contract. |
--n-input-foreground | Public customization point for this component contract. |
--n-input-disabled-background | Public customization point for this component contract. |
--n-input-disabled-foreground | Public customization point for this component contract. |
--n-file-input-button-gap | Public customization point for this component contract. |
--n-file-input-divider-length | Public customization point for this component contract. |
--n-file-input-button-size | Public customization point for this component contract. |
--n-file-input-button-background | Public customization point for this component contract. |
--n-file-input-button-background-hover | Public customization point for this component contract. |
--n-file-input-button-border | Public customization point for this component contract. |
--n-file-input-button-foreground | Public customization point for this component contract. |
--n-file-input-button-disabled-background | Public customization point for this component contract. |
--n-file-input-button-disabled-foreground | Public customization point for this component contract. |
--n-motion-hover-duration | Public customization point for this component contract. |
--n-motion-focus-duration | Public customization point for this component contract. |
--n-focus-ring | Public customization point for this component contract. |