import type { Meta, StoryObj } from '@storybook/web-components-vite'; import { html } from 'lit'; import './index.ts'; import type { USAFileInput } from './usa-file-input.js'; const meta: Meta = { title: 'Forms/File Input', component: 'usa-file-input', parameters: { layout: 'padded', docs: { description: { component: ` # USA File Input The USA File Input component provides accessible file upload functionality with drag-and-drop support using official USWDS styling. This component allows users to select files through a traditional file browser or by dragging files directly onto the input area. ## Features - Drag and drop file upload - Multiple file selection support - File type restrictions with accept attribute - File size display and formatting - Individual file removal - Form validation integration - ARIA attributes for screen readers - Visual feedback for drag states ## Usage Guidelines - Use for file upload functionality - Provide clear labels indicating what files are expected - Consider file size and type restrictions - Use hints to clarify upload requirements - Test drag and drop functionality across browsers - Ensure keyboard accessibility for file removal ## Accessibility - File input is keyboard accessible - Labels are properly associated with inputs - File removal buttons have descriptive aria-labels - Helper text is connected via aria-describedby - Drag states provide visual feedback - Screen reader announcements for file operations `, }, }, }, argTypes: { label: { control: { type: 'text' }, description: 'Label text for the file input', }, hint: { control: { type: 'text' }, description: 'Helper text shown below the label', }, name: { control: { type: 'text' }, description: 'Name attribute for form submission', }, inputId: { control: { type: 'text' }, description: 'ID for the input element', }, multiple: { control: { type: 'boolean' }, description: 'Whether multiple files can be selected', }, disabled: { control: { type: 'boolean' }, description: 'Whether the file input is disabled', }, required: { control: { type: 'boolean' }, description: 'Whether the file input is required', }, accept: { control: { type: 'text' }, description: 'File types that can be accepted (e.g., .pdf,.doc,.docx)', }, maxFileSize: { control: { type: 'text' }, description: 'Maximum file size allowed', }, }, args: { label: 'Select file', hint: '', name: 'file-input', inputId: 'file-input', multiple: false, disabled: false, required: false, accept: '', maxFileSize: '', }, }; export default meta; type Story = StoryObj; export const Default: Story = { render: (args) => html` `, }; export const WithHelperText: Story = { args: { label: 'Upload Document', hint: 'Select a PDF, Word document, or image file', }, render: (args) => html` `, }; export const MultipleFiles: Story = { args: { label: 'Upload Images', hint: 'You can select multiple image files at once', multiple: true, accept: '.jpg,.jpeg,.png,.gif,.webp', }, render: (args) => html` `, }; export const Required: Story = { args: { label: 'Required Document', hint: 'This field is required', required: true, }, render: (args) => html` `, }; export const WithFileTypeRestrictions: Story = { args: { label: 'Upload Resume', hint: 'Only PDF and Word documents are accepted', accept: '.pdf,.doc,.docx', }, render: (args) => html` `, }; export const Disabled: Story = { args: { label: 'Disabled File Input', hint: 'This field is currently disabled', disabled: true, }, render: (args) => html` `, }; export const CustomText: Story = { args: { label: 'Custom Upload Area', hint: 'Customized drag and drop text', }, render: (args) => html` `, }; export const FormExample: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`
{ e.preventDefault(); const form = e.target as HTMLFormElement; const formData = new FormData(form); console.log('Form data:', formData); // Log file information const files = formData.getAll('document'); files.forEach((file, index) => { if (file instanceof File) { console.log(`File ${index + 1}:`, { name: file.name, size: file.size, type: file.type, }); } }); alert('Form submitted! Check console for file data.'); }} >
Submit Files
`, }; export const ValidationStates: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`
`, }; export const AccessibilityFeatures: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`

Accessibility Features Demo

This demo shows various accessibility features of the file input component.

Features demonstrated:

  • Label properly associated with input
  • Helper text connected via aria-describedby
  • Required field marked with asterisk
  • File type restrictions via accept attribute
  • Drag and drop with visual feedback
  • Keyboard accessible file selection
  • Screen reader compatible structure
  • Individual file removal with descriptive labels
`, }; export const InteractiveDemo: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`

Interactive File Input Demo

Try uploading files by clicking the input area or dragging files onto it.

{ console.log('Files selected:', e.detail); const output = document.getElementById('file-output'); if (output) { const fileList = e.detail.files .map( (file: File) => `• ${file.name} (${(file.size / 1024).toFixed(1)} KB, ${file.type})` ) .join('\\n'); output.textContent = fileList || 'No files selected'; } }} @file-remove=${(e: CustomEvent) => { console.log('File removed:', e.detail); const status = document.getElementById('remove-status'); if (status) { status.textContent = `Removed: ${e.detail.file.name} (index ${e.detail.index})`; setTimeout(() => { if (status) status.textContent = ''; }, 3000); } }} >

Selected Files:

No files selected

Try these actions:

  • Click the file input area to browse for files
  • Drag files from your computer onto the input area
  • Select multiple files to see the preview list
  • Use the "Remove" button to delete individual files
  • Check the browser console for detailed event information
`, }; export const DragAndDropDemo: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`

Drag and Drop Functionality

This demo highlights the drag and drop capabilities with visual feedback.

Drag and Drop Features:

  • Visual feedback: The input area changes appearance when files are dragged over it
  • Multiple files: Drop multiple files at once for bulk selection
  • File validation: Only accepted file types will be processed (if accept attribute is set)
  • Disabled state: Drag and drop is ignored when the input is disabled
  • Custom text: The drag instructions can be customized
`, }; export const FileTypeExamples: Story = { parameters: { controls: { disable: true }, // Static demo - no interactive controls needed }, render: () => html`

File Type Restriction Examples

File Type Notes:

  • The accept attribute filters the file browser dialog
  • Users can still bypass restrictions in most browsers
  • Always validate file types on the server side
  • Consider using MIME types for more precise filtering
  • Multiple extensions can be specified with commas
`, };