React Aria Hooks

This page describes how to get started with React Aria hooks.

Installation#


React Aria can be installed using a package manager like npm or yarn.

yarn add react-aria

If you prefer, you can also use our hooks from individually versioned packages. This allows you to only install the hooks you use, or more granularly manage their versions. The individual packages are published under the @react-aria scope on npm. For example:

yarn add @react-aria/button

Once installed, hooks can be used from the monopackage or individual packages the same way.

// Monopackage
import {useButton} from 'react-aria';
// Monopackage
import {useButton} from 'react-aria';
// Monopackage
import {useButton} from 'react-aria';
// Individual packages
import {useButton} from '@react-aria/button';
// Individual packages
import {useButton} from '@react-aria/button';
// Individual packages
import {useButton} from '@react-aria/button';

Building a component#


React Aria provides behavior and accessibility through React Hooks. Since it does not provide any rendering, you are responsible for defining the DOM structure for your component and passing the DOM props returned by each React Aria hook to the appropriate elements. This is powerful because it allows you to be in complete control over the DOM structure that you render. For example, you may need to add extra elements for styling or layout control. You also get complete control over how you style your components: you could use CSS classes, inline styles, CSS-in-JS, etc.

Start by importing the hook you wish to use, and calling it in your component. You'll typically pass through the props from your component, along with a ref to the DOM node in some cases. The hook will return one or more sets of DOM props which you should pass through to the appropriate element. This can be done by spreading the props returned from the hook onto the element that you render.

This example shows a very simple button component built with the useButton hook.

import {useButton} from 'react-aria';

function Button(props) {
  let ref = React.useRef(null);
  let { buttonProps, isPressed } = useButton(props, ref);
  return (
    <button
      ref={ref}
      {...buttonProps}      style={{
        background: isPressed ? '#444' : '#666',
        color: 'white',
        padding: '6px 12px',
        borderRadius: 4,
        border: 'none'
      }}
    >
      {props.children}
    </button>
  );
}

<Button onPress={() => alert('Button pressed!')}>
  Press me
</Button>
import {useButton} from 'react-aria';

function Button(props) {
  let ref = React.useRef(null);
  let { buttonProps, isPressed } = useButton(props, ref);
  return (
    <button
      ref={ref}
      {...buttonProps}      style={{
        background: isPressed ? '#444' : '#666',
        color: 'white',
        padding: '6px 12px',
        borderRadius: 4,
        border: 'none'
      }}
    >
      {props.children}
    </button>
  );
}

<Button onPress={() => alert('Button pressed!')}>
  Press me
</Button>
import {useButton} from 'react-aria';

function Button(props) {
  let ref = React.useRef(
    null
  );
  let {
    buttonProps,
    isPressed
  } = useButton(
    props,
    ref
  );
  return (
    <button
      ref={ref}
      {...buttonProps}      style={{
        background:
          isPressed
            ? '#444'
            : '#666',
        color: 'white',
        padding:
          '6px 12px',
        borderRadius: 4,
        border: 'none'
      }}
    >
      {props.children}
    </button>
  );
}

<Button
  onPress={() =>
    alert(
      'Button pressed!'
    )}
>
  Press me
</Button>

Now you just need to add your own styling, and you have a fully accessible button component that works consistently across mouse, touch, keyboard, and screen readers with high quality interactions! See the useButton docs more examples.

Stateful components#


Many components are stateless — they display information to a user. Examples of stateless components include buttons, progress bars, and links. These components don't update as the user interacts with them.

A stateful component has some state, and allows a user to interact with the component in order to update that state. Examples of stateful components include text fields, checkboxes, and selects.

React Aria separates the state management logic into a separate hook that lives in react-stately. The state hook holds the state for the component, and provides an interface to read and update that state. This allows this logic to be reused across different platforms, e.g. in react-native. Read more about this on the architecture page.

To build a stateful component, you'll need to install and import the corresponding state hook from react-stately. Then, call the state hook from your component, and pass the resulting state object to the React Aria hook. You can also use the state in your rendering code to determine what visual state to display.

This example shows a number field component built with the useNumberField hook, along with the useNumberFieldState hook from react-stately.

import {useNumberFieldState} from 'react-stately';
import {useLocale, useNumberField} from 'react-aria';

function NumberField(props) {
  let {locale} = useLocale();
  let state = useNumberFieldState({...props, locale});
  let inputRef = React.useRef(null);
  let {
    labelProps,
    groupProps,
    inputProps,
    incrementButtonProps,
    decrementButtonProps
  } = useNumberField(props, state, inputRef);

  return (
    <div>
      <label {...labelProps}>{props.label}</label>
      <div {...groupProps} style={{display: 'flex', gap: 4}}>
        <Button {...decrementButtonProps}>-</Button>
        <input {...inputProps} ref={inputRef} />
        <Button {...incrementButtonProps}>+</Button>
      </div>
    </div>
  );
}

<NumberField
  label="Price"
  defaultValue={6}
  formatOptions={{
    style: 'currency',
    currency: 'USD'
  }}
/>
import {useNumberFieldState} from 'react-stately';
import {useLocale, useNumberField} from 'react-aria';

function NumberField(props) {
  let { locale } = useLocale();
  let state = useNumberFieldState({ ...props, locale });
  let inputRef = React.useRef(null);
  let {
    labelProps,
    groupProps,
    inputProps,
    incrementButtonProps,
    decrementButtonProps
  } = useNumberField(props, state, inputRef);

  return (
    <div>
      <label {...labelProps}>{props.label}</label>
      <div
        {...groupProps}
        style={{ display: 'flex', gap: 4 }}
      >
        <Button {...decrementButtonProps}>-</Button>
        <input {...inputProps} ref={inputRef} />
        <Button {...incrementButtonProps}>+</Button>
      </div>
    </div>
  );
}

<NumberField
  label="Price"
  defaultValue={6}
  formatOptions={{
    style: 'currency',
    currency: 'USD'
  }}
/>
import {useNumberFieldState} from 'react-stately';
import {
  useLocale,
  useNumberField
} from 'react-aria';

function NumberField(
  props
) {
  let { locale } =
    useLocale();
  let state =
    useNumberFieldState({
      ...props,
      locale
    });
  let inputRef = React
    .useRef(null);
  let {
    labelProps,
    groupProps,
    inputProps,
    incrementButtonProps,
    decrementButtonProps
  } = useNumberField(
    props,
    state,
    inputRef
  );

  return (
    <div>
      <label
        {...labelProps}
      >
        {props.label}
      </label>
      <div
        {...groupProps}
        style={{
          display:
            'flex',
          gap: 4
        }}
      >
        <Button
          {...decrementButtonProps}
        >
          -
        </Button>
        <input
          {...inputProps}
          ref={inputRef}
        />
        <Button
          {...incrementButtonProps}
        >
          +
        </Button>
      </div>
    </div>
  );
}

<NumberField
  label="Price"
  defaultValue={6}
  formatOptions={{
    style: 'currency',
    currency: 'USD'
  }}
/>

This gives you a number field complete with input validation, internationalized formatting, accessibility, mobile keyboard support, and much more! See the useNumberField docs to learn more about all of the features.