FileTrigger
A FileTrigger allows a user to access the file system with either a Button or Link.
| install | yarn add react-aria-components |
|---|---|
| version | 1.0.0-alpha.5 |
| usage | import {FileTrigger} from 'react-aria-components' |
Example#
import {FileTrigger} from 'react-aria-components';
import {Button} from 'react-aria-components';
<FileTrigger>
<Button>Select a file</Button>
</FileTrigger>
import {FileTrigger} from 'react-aria-components';
import {Button} from 'react-aria-components';
<FileTrigger>
<Button>Select a file</Button>
</FileTrigger>
import {FileTrigger} from 'react-aria-components';
import {Button} from 'react-aria-components';
<FileTrigger>
<Button>
Select a file
</Button>
</FileTrigger>
Show CSS
.react-aria-Button {
--border-color: var(--spectrum-alias-border-color);
--border-color-pressed: var(--spectrum-alias-border-color-down);
--border-color-disabled: var(--spectrum-alias-border-color-disabled);
--background-color: var(--spectrum-global-color-gray-50);
--background-color-pressed: var(--spectrum-global-color-gray-100);
--text-color: var(--spectrum-alias-text-color);
--text-color-disabled: var(--spectrum-alias-text-color-disabled);
--focus-ring-color: slateblue;
color: var(--text-color);
background: var(--background-color);
border: 1px solid var(--border-color);
border-radius: 4px;
appearance: none;
vertical-align: middle;
font-size: 1.2rem;
text-align: center;
margin: 0;
outline: none;
padding: 4px 12px;
&[data-pressed] {
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
background: var(--background-color-pressed);
border-color: var(--border-color-pressed);
}
&[data-focus-visible] {
border-color: var(--focus-ring-color);
box-shadow: 0 0 0 1px var(--focus-ring-color);
}
&:disabled {
border-color: var(--border-color-disabled);
color: var(--text-color-disabled);
}
}
@media (forced-colors: active) {
.react-aria-Button {
forced-color-adjust: none;
--border-color: ButtonBorder;
--border-color-pressed: ButtonBorder;
--border-color-disabled: GrayText;
--background-color: ButtonFace;
--background-color-pressed: ButtonFace;
--text-color: ButtonText;
--text-color-disabled: GrayText;
--focus-ring-color: Highlight;
}
}.react-aria-Button {
--border-color: var(--spectrum-alias-border-color);
--border-color-pressed: var(--spectrum-alias-border-color-down);
--border-color-disabled: var(--spectrum-alias-border-color-disabled);
--background-color: var(--spectrum-global-color-gray-50);
--background-color-pressed: var(--spectrum-global-color-gray-100);
--text-color: var(--spectrum-alias-text-color);
--text-color-disabled: var(--spectrum-alias-text-color-disabled);
--focus-ring-color: slateblue;
color: var(--text-color);
background: var(--background-color);
border: 1px solid var(--border-color);
border-radius: 4px;
appearance: none;
vertical-align: middle;
font-size: 1.2rem;
text-align: center;
margin: 0;
outline: none;
padding: 4px 12px;
&[data-pressed] {
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
background: var(--background-color-pressed);
border-color: var(--border-color-pressed);
}
&[data-focus-visible] {
border-color: var(--focus-ring-color);
box-shadow: 0 0 0 1px var(--focus-ring-color);
}
&:disabled {
border-color: var(--border-color-disabled);
color: var(--text-color-disabled);
}
}
@media (forced-colors: active) {
.react-aria-Button {
forced-color-adjust: none;
--border-color: ButtonBorder;
--border-color-pressed: ButtonBorder;
--border-color-disabled: GrayText;
--background-color: ButtonFace;
--background-color-pressed: ButtonFace;
--text-color: ButtonText;
--text-color-disabled: GrayText;
--focus-ring-color: Highlight;
}
}.react-aria-Button {
--border-color: var(--spectrum-alias-border-color);
--border-color-pressed: var(--spectrum-alias-border-color-down);
--border-color-disabled: var(--spectrum-alias-border-color-disabled);
--background-color: var(--spectrum-global-color-gray-50);
--background-color-pressed: var(--spectrum-global-color-gray-100);
--text-color: var(--spectrum-alias-text-color);
--text-color-disabled: var(--spectrum-alias-text-color-disabled);
--focus-ring-color: slateblue;
color: var(--text-color);
background: var(--background-color);
border: 1px solid var(--border-color);
border-radius: 4px;
appearance: none;
vertical-align: middle;
font-size: 1.2rem;
text-align: center;
margin: 0;
outline: none;
padding: 4px 12px;
&[data-pressed] {
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
background: var(--background-color-pressed);
border-color: var(--border-color-pressed);
}
&[data-focus-visible] {
border-color: var(--focus-ring-color);
box-shadow: 0 0 0 1px var(--focus-ring-color);
}
&:disabled {
border-color: var(--border-color-disabled);
color: var(--text-color-disabled);
}
}
@media (forced-colors: active) {
.react-aria-Button {
forced-color-adjust: none;
--border-color: ButtonBorder;
--border-color-pressed: ButtonBorder;
--border-color-disabled: GrayText;
--background-color: ButtonFace;
--background-color-pressed: ButtonFace;
--text-color: ButtonText;
--text-color-disabled: GrayText;
--focus-ring-color: Highlight;
}
}Features#
Access to a computer’s file system can be created in HTML with the <input> element with a file type attribute. FileTrigger sets up the configuration between the input element and pressable child for a customizable file upload.
- Flexible – Works with any pressable component, meaning that it is compatible with both React Aria Components and React Spectrum Components.
Anatomy#
A FileTrigger wraps around an input element and a pressable child, usually a link or button, that allows the user to upload files. The input element is not displayed and has no effect on the layout.
If a visual label is not provided (e.g. an icon only button/link, or image only link), then an aria-label or aria-labelledby prop must be passed to identify the link to assistive technology.
Composed Components#
A FileTrigger can use the following components, which may also be used standalone or reused in other components.
Props#
| Name | Type | Default | Description |
acceptedFileTypes | Array<string> | — | Specifies what mime type of files are allowed. |
allowsMultiple | boolean | — | Whether multiple files can be selected. |
defaultCamera | 'user' | 'environment' | — | Specifies the use of a media capture mechanism to capture the media on the spot. |
children | ReactNode | — | The children of the component. |
className | string | — | The CSS className for the element. |
style | CSSProperties | — | The inline style for the element. |
Events
| Name | Type | Default | Description |
onChange | (
(files: FileList
| | null
)) => void | — | Handler when a user selects a file. |
Layout
| Name | Type | Default | Description |
slot | string | — | A slot name for the component. Slots allow the component to receive props from a parent component. |
Accessibility
| Name | Type | Default | Description |
aria-label | string | — | Defines a string value that labels the current element. |
aria-labelledby | string | — | Identifies the element (or elements) that labels the current element. |
aria-describedby | string | — | Identifies the element (or elements) that describes the object. |
aria-details | string | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
Styling#
React Aria components can be styled in many ways, including using CSS classes, inline styles, utility classes (e.g. Tailwind), CSS-in-JS (e.g. Styled Components), etc. By default, all components include a builtin className attribute which can be targeted using CSS selectors. These follow the react-aria-ComponentName naming convention.
.react-aria-FileTrigger {
/* ... */
}
.react-aria-FileTrigger {
/* ... */
}
.react-aria-FileTrigger {
/* ... */
}
A custom className can also be specified on any component. This overrides the default className provided by React Aria with your own.
<FileTrigger className="my-filetrigger">
{/* ... */}
</FileTrigger>
<FileTrigger className="my-filetrigger">
{/* ... */}
</FileTrigger>
<FileTrigger className="my-filetrigger">
{/* ... */}
</FileTrigger>
The states and selectors for each component used in a FileTrigger are documented below.
Button#
A Button can be targeted with the .react-aria-Button CSS selector, or by overriding with a custom className. It supports the following states:
| Name | CSS Selector | Description |
isHovered | [data-hovered] | Whether the button is currently hovered with a mouse. |
isPressed | [data-pressed] | Whether the button is currently in a pressed state. |
isFocused | :focus | Whether the button is focused, either via a mouse or keyboard. |
isFocusVisible | [data-focus-visible] | Whether the button is keyboard focused. |
isDisabled | :disabled | Whether the button is disabled. |
Link#
A Link can be targeted with the .react-aria-Link CSS selector, or by overriding with a custom className. It supports the following states:
| Name | CSS Selector | Description |
isCurrent | [aria-current] | Whether the link is the current item within a list. |
isHovered | [data-hovered] | Whether the link is currently hovered with a mouse. |
isPressed | [data-pressed] | Whether the link is currently in a pressed state. |
isFocused | :focus | Whether the link is focused, either via a mouse or keyboard. |
isFocusVisible | [data-focus-visible] | Whether the link is keyboard focused. |
isDisabled | [aria-disabled] | Whether the link is disabled. |
Usage#
Accepted file types#
By default, the file trigger will accept any file type. To support only certain file types, pass an array of the mime type of files via the acceptedFileTypes prop.
<FileTrigger acceptedFileTypes={['image/png']}>
<Button>Select files</Button>
</FileTrigger>
<FileTrigger acceptedFileTypes={['image/png']}>
<Button>Select files</Button>
</FileTrigger>
<FileTrigger
acceptedFileTypes={[
'image/png'
]}
>
<Button>
Select files
</Button>
</FileTrigger>
Multiple files#
A file trigger can accept multiple files by passsing the allowsMultiple property.
<FileTrigger allowsMultiple>
<Button>Upload your files</Button>
</FileTrigger>
<FileTrigger allowsMultiple>
<Button>Upload your files</Button>
</FileTrigger>
<FileTrigger
allowsMultiple
>
<Button>
Upload your files
</Button>
</FileTrigger>
Capture#
To specify the media capture mechanism to capture media on the spot, pass user for the user-facing camera or environment for the outward-facing camera via the defaultCamera prop.
This behavior only works on mobile devices. On desktop devices, it will open the file system like normal. Read more about about capture.
<FileTrigger defaultCamera="environment">
<Button>Open Camera</Button>
</FileTrigger>
<FileTrigger defaultCamera="environment">
<Button>Open Camera</Button>
</FileTrigger>
<FileTrigger defaultCamera="environment">
<Button>
Open Camera
</Button>
</FileTrigger>