j3w1 / File inputVue · HTML · React · Astro

J3W1 / DESIGN SYSTEM

File input

A native file input behind a label styled as a secondary button, optionally inside a drop zone, with a list of chosen files and per-file errors.

stable · LIGHT DOM · 1.1.0

Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.

Live variants

default

No file chosen

Choose local files. This component does not upload them; the host validates its own file policy.

✕ Choose at least one file.

<j3w1-file-input id="example-file-input-default"><div class="file-input">
  <label class="file-input-label" for="example-file-input-default-fi-attach">Attachments</label>
  <div class="file-input-root">
    <input class="file-input-native" id="example-file-input-default-fi-attach" type="file" multiple="" aria-describedby="example-file-input-default-fi-attach-help example-file-input-default-fi-attach-message" name="example-file-input-default-fi-attach">
    <label class="file-input-button" for="example-file-input-default-fi-attach">Choose files</label>
    <span class="file-input-status" role="status">No file chosen</span>
    <span class="file-input-drop-hint" aria-hidden="true">Release to add</span>
  </div>
  <div class="file-input-progress" aria-hidden="true"></div>
  <p class="file-input-help" id="example-file-input-default-fi-attach-help">Choose local files. This component does not upload them; the host validates its own file policy.</p>
  <p class="file-input-message" id="example-file-input-default-fi-attach-message">✕ Choose at least one file.</p>
</div></j3w1-file-input>

drop-zone

No file chosen

Choose local files. This component does not upload them; the host validates its own file policy.

✕ Only PNG or WebP files.

<j3w1-file-input id="example-file-input-drop-zone"><div class="file-input">
  <label class="file-input-label" for="example-file-input-drop-zone-fi-zone">Screenshots</label>
  <div class="file-input-root file-input-zone">
    <input class="file-input-native" id="example-file-input-drop-zone-fi-zone" type="file" multiple="" accept="image/png,image/webp" aria-describedby="example-file-input-drop-zone-fi-zone-help example-file-input-drop-zone-fi-zone-message" name="example-file-input-drop-zone-fi-zone">
    <label class="file-input-button" for="example-file-input-drop-zone-fi-zone">Choose files</label>
    <span class="file-input-status" role="status">No file chosen</span>
    <span class="file-input-drop-hint" aria-hidden="true">Release to add</span>
  </div>
  <div class="file-input-progress" aria-hidden="true"></div>
  <p class="file-input-help" id="example-file-input-drop-zone-fi-zone-help">Choose local files. This component does not upload them; the host validates its own file policy.</p>
  <p class="file-input-message" id="example-file-input-drop-zone-fi-zone-message">✕ Only PNG or WebP files.</p>
</div></j3w1-file-input>

with-list

No file chosen

    Choose local files. This component does not upload them; the host validates its own file policy.

    ✕ One file could not be added.

    <j3w1-file-input id="example-file-input-with-list"><div class="file-input">
      <label class="file-input-label" for="example-file-input-with-list-fi-list">Attachments</label>
      <div class="file-input-root">
        <input class="file-input-native" id="example-file-input-with-list-fi-list" type="file" multiple="" aria-describedby="example-file-input-with-list-fi-list-help example-file-input-with-list-fi-list-message" name="example-file-input-with-list-fi-list">
        <label class="file-input-button" for="example-file-input-with-list-fi-list">Add files</label>
        <span class="file-input-status" role="status">No file chosen</span>
        <span class="file-input-drop-hint" aria-hidden="true">Release to add</span>
      </div>
      <div class="file-input-progress" aria-hidden="true"></div>
      <ul class="file-input-list" aria-label="Chosen files"></ul>
      <p class="file-input-help" id="example-file-input-with-list-fi-list-help">Choose local files. This component does not upload them; the host validates its own file policy.</p>
      <p class="file-input-message" id="example-file-input-with-list-fi-list-message">✕ One file could not be added.</p>
    </div></j3w1-file-input>

    Install and register

    Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

    npm install --save-exact @j3w1/ui@1.1.0
    import '@j3w1/ui/tokens.css';
    import '@j3w1/ui/styles/file-input.css';
    import '@j3w1/ui/register/file-input';

    Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

    Vue SFC, React, Astro and plain HTML integration →

    Copy the complete implementation

    npx --package=@j3w1/ui@1.1.0 j3w1-ui copy file-input --out ./vendor/j3w1/file-input

    The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

    Public API

    attributes

    NameType / signatureMeaning
    disabledCustomEventDisable the native controls owned by this instance.
    loadingCustomEventMark the primary control busy and prevent duplicate activation.

    properties

    NameType / signatureMeaning
    disabledbooleanDelegates disabled state to native children.
    namestringNative control name; application form keys remain explicit.
    filesFile[]Current native files; files are never uploaded by the component. Read only.

    methods

    NameType / signatureMeaning
    refresh(): voidReconnect behavior after replacing native child structure.
    focus(options?: FocusOptions): voidFocus the first usable native control.
    clear(): voidClear the current native file selection.

    events

    NameType / signatureMeaning
    j3w1-changeCustomEventNative file selection changed; read files from the component.

    Dependencies and verification

    Registered components: none. Style dependencies: none.

    Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

    Full implementation manifest, API and token dependency closure

    Canonical specification

    Purpose

    Choosing one or more files from the host. The native input keeps the host chooser, its keyboard behaviour and its security model; the theme replaces only the input’s own rendering with a button-styled label, adds an optional drop zone, and lists what was chosen with any per-file error.

    Anatomy

    The field label; the root row (or the drop zone) holding the button-styled label and the status text; the hidden-but-focusable native input; an optional list of chosen files, each with name, size in color.text.subtle and a remove button, one of which may carry the ✕ glyph and an error in color.status.danger.text; a static striped progress bar while uploading; help and validation message below.

    States

    StateVisualNon-colour channel
    defaultbutton: 1px color.action.secondary.border outline, text color.action.secondary.text; zone: 1px dashed color.interaction.drop-target
    hoverbutton background → color.action.secondary.hover-bg; border unchangedcursor: pointer
    focus-visiblering 1px dashed color.interaction.focus.ring at −2px on the button (the input has focus)the ring
    drop-targetroot fill color.interaction.marquee; border 1px dashed color.interaction.drop-targetdashed pattern; the hint text changes to “Release to add”
    invalidbutton border 2px color.status.danger.border; message with the ✕ glyph; a failed row shows its own ✕border width 1 → 2px; glyphs; aria-invalid
    disabledbutton text color.text.disabled, border color.border.disabled, background color.interaction.disabled.bg; the zone’s dashes take color.border.disabled; no hoverdisabled; cursor: not-allowed
    loadinga static bar of 45° stripes, color.action.primary.bg on color.interaction.pressed.bg, below the row; the button stays enabledaria-busy; the status text reads “Uploading n files”; no animation

    Precedence when several apply: disabled > loading > invalid > drop-target > hover; focus-visible is always drawn.

    Keyboard

    Tab reaches the native input, which is drawn as the button; Enter or Space opens the host chooser; Escape in the chooser returns to the input. Each remove button in the list is its own tab stop after the input, and Delete or Backspace on it acts like Enter. Dropping is a pointer gesture only and never the sole way to add a file.

    Accessibility

    The native input is hidden with the sr-only pattern, never display: none or visibility: hidden, so it keeps focus and the host chooser. It is named by both labels (“Attachments” and “Choose files”), and aria-describedby lists help and message. The status text and the list are announced through a polite live region after a choice; per-file errors are in the row text, not only in colour. The drop zone has no role and no tabindex; aria-busy on the root marks uploading. Contrast: button text 10.37:1 on the canvas and 6.84:1 on the hover fill, button border 4.45:1, drop-target border 4.69:1 on the canvas and 4.52:1 on the marquee fill, status and help 5.81:1, sizes 5.10:1, danger text 5.40:1.

    Portability

    The button is the secondary button of the actions family; the zone is a dashed border and a translucent fill; the stripes are a repeating gradient (or a hatched brush). Toolkits without drag-and-drop omit the zone and keep the button; toolkits without a translucent fill composite the marquee over the canvas and record the value.

    Non-examples

    A hidden input with display: none and a button that clicks it by script. A drop zone that is the only way to add files. A rounded, dotted, animated “pulsing” zone. A spinner while uploading. A progress bar that animates its stripes. Errors shown by a red file name alone. Disabling by opacity.

    j3w1 / command

    • SPEC Overview
    • SPEC Foundations
    • SPEC Components
    • SPEC Patterns
    • SPEC Tokens
    • SPEC Tools
    • SPEC Implement
    • SPEC For agents
    • SPEC Ports
    • SPEC Releases
    • DEMO Vue application demo
    • SPEC Complete UI theme specification