FileTrigger
A FileTrigger allows a user to access the file system with any pressable React Aria or React Spectrum component, or custom components built with usePress.
install | yarn add react-aria-components |
---|---|
version | 1.0.0-beta.1 |
usage | import {FileTrigger} from 'react-aria-components' |
Example#
import {FileTrigger, Button} from 'react-aria-components';
function Example(){
let [file, setFile] = React.useState(null);
return (
<>
<FileTrigger
onSelect={(e) => {
let files = Array.from(e);
let urls = files.map((file) => file.name);
setFile(urls);
}}>
<Button>Select a file</Button>
</FileTrigger>
{file && file}
</>
)
}
import {FileTrigger, Button} from 'react-aria-components';
function Example(){
let [file, setFile] = React.useState(null);
return (
<>
<FileTrigger
onSelect={(e) => {
let files = Array.from(e);
let urls = files.map((file) => file.name);
setFile(urls);
}}>
<Button>Select a file</Button>
</FileTrigger>
{file && file}
</>
)
}
import {
Button,
FileTrigger
} from 'react-aria-components';
function Example() {
let [file, setFile] =
React.useState(null);
return (
<>
<FileTrigger
onSelect={(
e
) => {
let files =
Array.from(
e
);
let urls =
files.map((
file
) =>
file.name
);
setFile(urls);
}}
>
<Button>
Select a file
</Button>
</FileTrigger>
{file && file}
</>
);
}
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: 1rem;
text-align: center;
margin: 0;
outline: none;
padding: 6px 10px;
&[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);
}
&[data-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: 1rem;
text-align: center;
margin: 0;
outline: none;
padding: 6px 10px;
&[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);
}
&[data-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: 1rem;
text-align: center;
margin: 0;
outline: none;
padding: 6px 10px;
&[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);
}
&[data-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#
A file input can be created with an <input type=“file”>
element, but this supports limited styling options and may not integrate well with the overall design of a website or application. To overcome this, FileTrigger
extends the functionality of the standard file input element by working with a pressable child such as a Button
to create accessible file inputs that can be style as needed.
- Customizable – Works with any pressable React Aria or React Spectrum component, and custom components built with usePress.
Anatomy#
A FileTrigger
wraps around a pressable child such as a button, and includes a visually hidden input element that allows the user to select files from their device.
import {FileTrigger, Button} from 'react-aria-components';
<FileTrigger>
<Button />
</FileTrigger>
import {FileTrigger, Button} from 'react-aria-components';
<FileTrigger>
<Button />
</FileTrigger>
import {
Button,
FileTrigger
} from 'react-aria-components';
<FileTrigger>
<Button />
</FileTrigger>
If a visual label is not provided on the pressable child, then an aria-label
or aria-labelledby
prop must be passed to identify the file trigger to assistive technology.
Composed Components#
A FileTrigger
can use the following components, which may also be used standalone or reused in other components.
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>
Media 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 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>
Props#
Name | Type | 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. |
Events
Name | Type | Description |
onSelect | (
(files: FileList
| | null
)) => void | Handler when a user selects a file. |
Styling#
FileTrigger#
The FileTrigger
component does not render any element of its own so it does not support styling.
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 | [data-focused] | Whether the button is focused, either via a mouse or keyboard. |
isFocusVisible | [data-focus-visible] | Whether the button is keyboard focused. |
isDisabled | [data-disabled] | Whether the button is disabled. |