# Technical Documentation: adobe/react-spectrum

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/adobe/react-spectrum)

### Overview (README.md)

#  [React Spectrum Libraries](https://react-spectrum.adobe.com/)

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.

### React Spectrum

A React implementation of Spectrum, Adobe’s design system. Spectrum provides adaptive, accessible, and cohesive experiences for all Adobe applications.

[Explore React Spectrum](https://react-spectrum.adobe.com/react-spectrum/index.html)

### React Aria

A library of unstyled React components and hooks that helps you build accessible, high quality UI components for your application or design system.

[Learn more about React Aria](https://react-spectrum.adobe.com/react-aria/index.html)

### React Stately

A library of React Hooks that provides cross-platform state management for your design system.

[More information about React Stately](https://react-spectrum.adobe.com/react-stately/index.html)

### Internationalized

A collection of framework-agnostic internationalization libraries for the web.

[Internationalized Packages](https://react-spectrum.adobe.com/internationalized/index.html)

## Features

* ♿️ **[Accessible](https://react-spectrum.adobe.com/react-aria/accessibility.html)** – Accessibility and behavior is implemented according to [WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.2/), including full screen reader and keyboard navigation support. All components have been tested across a wide variety of screen readers and devices to ensure the best experience possible for all users.
* 📱 **[Adaptive](https://react-spectrum.adobe.com/react-aria/interactions.html)** – All components are designed to work with mouse, touch, and keyboard interactions. They’re built with responsive design principles to deliver a great experience, no matter the device.
* 🌍 **[International](https://react-spectrum.adobe.com/react-aria/internationalization.html)** – Support over 30 languages is included out of the box, including support for right-to-left languages, date and number formatting, and more.
* 🎨 **[Customizable](https://react-spectrum.adobe.com/react-spectrum/theming.html)** – React Spectrum components support custom themes, and automatically adapt for dark mode. For even more customizability, you can build your own components with your own DOM structure and styling using the [React Aria](https://react-spectrum.adobe.com/react-aria/index.html) and [React Stately](https://react-spectrum.adobe.com/react-stately/index.html) hooks to provide behavior, accessibility, and interactions.

## Getting started

React Spectrum includes several libraries, which you can choose depending on your usecase.

* [React Spectrum](https://react-spectrum.adobe.com/react-spectrum/getting-started.html) is an implementation of Adobe's design system. If you’re integrating with Adobe software or would like a complete component library to use in your project, look no further!
* [React Aria](https://react-spectrum.adobe.com/react-aria/getting-started.html) is a collection of unstyled React components and hooks that helps you build accessible, high quality UI components for your own application or design system. If you're building a component library for the web from scratch with your own styling, start here.
* [React Stately](https://react-spectrum.adobe.com/react-stately/getting-started.html) is a library of state management hooks for use in your component library. If you're using React Aria, you'll likely also use React Stately, but it can also be used independently (e.g. on other platforms like React Native).

[Read more about our architecture](https://github.com/adobe/react-spectrum/blob/main/rfcs/2019-v3-architecture.md).

## Contributing

One of the goals of the React Spectrum project is to make building design systems and component libraries as easy as possible, while maintaining high quality interactions and accessibility support. We aim to raise the bar for web applications. The best way to achieve that goal is **together**. We would love contributions from the community no matter how big or small. 😍

Read our [contributing guide](https://github.com/adobe/react-spectrum/blob/main/CONTRIBUTING.md) to learn about how to propose bugfixes and improvements, and how the development process works. For detailed information about our architecture, and how all of the pieces fit together, read our [architecture rfc](https://github.com/adobe/react-spectrum/blob/main/rfcs/2019-v3-architecture.md).

---

### Starters Docs README (`starters/docs/README.md`)

# React Aria Starter

Welcome to React Aria! This starter kit includes a [Storybook](https://storybook.js.org/) containing all of the examples in the docs. You can modify any of the components or their corresponding CSS files to play around or bootstrap your own component library.

To get started, run the following commands:

```shell
yarn
yarn storybook
```

## Building for Production

This starter uses [CSS Nesting](https://drafts.csswg.org/css-nesting/), which is supported in the latest version of all major browsers, but if further support is needed, you can compile this to flattened selectors by enabling the feature in [Lightning CSS](https://lightningcss.dev/docs.html) or using the [PostCSS Nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting#usage) plugin in your build.

---

### Packages @Internationalized Date Docs Index (`packages/@internationalized/date/docs/index.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [date, time]
order: -1
navigationTitle: Introduction
description: The @internationalized/date package provides objects and functions for representing and manipulating dates and times in a locale-aware manner.
---

# @internationalized/date

The `@internationalized/date` package provides objects and functions for representing and manipulating dates and times in a locale-aware manner.

<HeaderInfo packageData={packageData} />

## Features

* **Typed objects** – Includes immutable objects to represent dates, times, and calendars.
* **International calendars** – Support for 13 calendar systems used around the world, including Gregorian, Buddhist, Islamic, Persian, and more.
* **Manipulation** – Add and subtract durations, set and cycle fields, etc.
* **Conversion** – Convert between calendar systems, time zones, string representations, and object types.
* **Queries** – Compare dates and times for ordering or full/partial equality. Determine locale-specific metadata such as day of week, weekend/weekday, etc.
* **Time zone aware** – The [ZonedDateTime](ZonedDateTime.html) object supports time zone aware date and time manipulation.
* **Predictable** – The API is designed to resolve ambiguity in all operations explicitly, including time zone conversions, arithmetic involving daylight saving time, locale-specific queries, and more.
* **Small bundle size** – The entire library including all calendars and functions is 8 kB minified and compressed with Brotli.
* **Tree shakeable** – Only include the functions and calendar systems you need. For example, if you only use the Gregorian calendar and builtin `CalendarDate` methods, it's just 2.8 kB.

## Introduction

Dates and times are represented in many different ways by cultures around the world. This includes differences in calendar systems, time zones, daylight saving time rules, date and time formatting, weekday and weekend rules, and much more. When building applications that support users around the world, it is important to handle these aspects correctly for each locale. The `@internationalized/date` package provides a library of objects and functions to perform date and time related manipulation, queries, and conversions that work across locales and calendars.

By default, JavaScript represents dates and times using the [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object. However, `Date` has _many_ problems, including a very difficult to use API, lack of all internationalization support, and more. The [Temporal](https://tc39.es/proposal-temporal/docs/index.html) proposal will eventually address this in the language, and `@internationalized/date` is heavily inspired by it. We hope to back the objects in this package with it once it is implemented in browsers.

## Package structure

The `@internationalized/date` package includes the following object types:

* [Calendar](Calendar.html) – An interface which provides calendar conversion and metadata like number of days in month, and number of months in year. Many implementations are provided to support the most commonly used calendar systems.
* [CalendarDate](CalendarDate.html) – An immutable object that stores a date associated with a specific calendar system, without any time components.
* [CalendarDateTime](CalendarDateTime.html) – An immutable object that represents a date and time without a time zone, in a specific calendar system.
* [ZonedDateTime](ZonedDateTime.html) – An immutable object that represents a date and time in a specific time zone and calendar system.
* [Time](Time.html) – An immutable object that stores a clock time without any date components.

Each object includes methods to allow basic manipulation and conversion functionality, such as adding and subtracting durations, and formatting as an ISO 8601 string. Additional less commonly used functions can be imported from the `@internationalized/date` package, and passed a date object as a parameter. This includes functions to parse ISO 8601 strings, query properties such as day of week, convert between time zones and much more. See the documentation for each of the objects to learn more about the supported methods and functions.

This example constructs a `CalendarDate` object, manipulates it to get the start of the next week, and converts it to a string representation.

```tsx
import {CalendarDate, startOfWeek} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
date = date.add({weeks: 1});
date = startOfWeek(date, 'en-US');
date.toString(); // 2022-02-06
```

---

### Packages @Internationalized Number Docs Index (`packages/@internationalized/number/docs/index.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/number/package.json';

---
category: Numbers
keywords: [number, internationalization]
order: 0
navigationTitle: Introduction
description: The @internationalized/number package provides utilities for formatting and parsing numbers across locales and numbering systems.
---

# @internationalized/number

The `@internationalized/number` package provides utilities for formatting and parsing numbers across locales and numbering systems.

<HeaderInfo packageData={packageData} />

## Features

* **Advanced formatting** – Formatting and parsing decimals, percentages, currency values, and unit values are supported.
* **Locale-aware** – Numbers are formatted and parsed according to the locale expectations, including decimal characters and separators, percent signs, unit and currency symbols, and more.
* **International numbering systems** – Support for the Latin, Arabic, and Han decimal numbering systems, including automatic detection of the numbering system used in the input.
* **Small bundle size** – The entire library is 1.7 kB minified and compressed with Brotli. No large locale data is needed – all data is retrieved from builtin browser APIs!

## Introduction

Numbers are represented in many different ways by cultures around the world. This includes differences in currency symbols, units, decimal points, grouping separators, and even digits themselves. When building applications that support users around the world, it is important to handle these aspects correctly for each locale. The `@internationalized/number` package provides a utilities to format and parse numbers according to locale expectations.

This example parses a percentage in the Arabic numbering system according to the `ar-SA` locale, and formats as a Latin number in the `en-US` locale.

```tsx
import {NumberParser, NumberFormatter} from '@internationalized/number';

let parser = new NumberParser('ar-SA', {style: 'percent'});
let number = parser.parse('٤٥٪'); // 0.45

let formatter = new NumberFormatter('en-US', {style: 'percent'});
formatter.format(number); // '45%'
```

See the docs for [NumberParser](NumberParser.html) and [NumberFormatter](NumberFormatter.html) to learn more.

---

### Packages Dev Docs Pages Index (`packages/dev/docs/pages/index.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import {Highlights, Hero} from '@react-spectrum/docs';
import heroNarrow from 'url:./assets/ReactSpectrumHome_Mobile_976x1025_1x.png';
import heroNarrow2x from 'url:./assets/ReactSpectrumHome_Mobile_976x1025_2x.png';
import heroNarrowWebp from 'url:./assets/ReactSpectrumHome_Mobile_976x1025_1x.webp';
import heroNarrow2xWebp from 'url:./assets/ReactSpectrumHome_Mobile_976x1025_2x.webp';
import heroWide from 'url:./assets/ReactSpectrumHome_976x445_1x.png';
import heroWide2x from 'url:./assets/ReactSpectrumHome_976x445_2x.png';
import heroWideWebp from 'url:./assets/ReactSpectrumHome_976x445_1x.webp';
import heroWide2xWebp from 'url:./assets/ReactSpectrumHome_976x445_2x.webp';
import {VisuallyHidden} from '@react-aria/visually-hidden';
import clsx from 'clsx';
import linkStyle from '@adobe/spectrum-css-temp/components/link/vars.css';
import styles from '@react-spectrum/docs/src/docs.css';
import typographyStyles from '@adobe/spectrum-css-temp/components/typography/vars.css';

---
description: A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.
keywords: [react spectrum, react aria, react stately, design system]
---

# React Spectrum Libraries

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.

<p className={clsx(typographyStyles['spectrum-Body2'], styles.homeLinks)}>
  <a href="https://github.com/adobe/react-spectrum" className={clsx(linkStyle['spectrum-Link'], styles.link)}>GitHub</a>
</p>

<Hero
  narrow={heroNarrow}
  narrow2x={heroNarrow2x}
  narrowWebp={heroNarrowWebp}
  narrow2xWebp={heroNarrow2xWebp}
  wide={heroWide}
  wide2x={heroWide2x}
  wideWebp={heroWideWebp}
  wide2xWebp={heroWide2xWebp}
  alt="React Spectrum hero image" />

<Highlights items={[
  {
    title: 'React Spectrum',
    description: 'A React implementation of Spectrum, Adobe’s design system. Spectrum provides adaptive, accessible, and cohesive experiences for all Adobe applications.',
    url: './react-spectrum/index.html',
    urlText: <>Explore<VisuallyHidden elementType="span"> React Spectrum</VisuallyHidden></>
  },
  {
    title: 'React Aria',
    description: 'A library of unstyled React components and hooks that helps you build accessible, high quality UI components for your application or design system.',
    url: './react-aria/index.html',
    urlText: <>Learn more<VisuallyHidden elementType="span"> about React Aria</VisuallyHidden></>
  },
  {
    title: 'React Stately',
    description: 'A library of React Hooks that provides cross-platform state management for your design system.',
    url: './react-stately/index.html',
    urlText: <>Get Started<VisuallyHidden elementType="span"> with React Stately</VisuallyHidden></>
  },
  {
    title: 'Internationalized',
    description: 'A collection of framework-agnostic internationalization libraries for the web.',
    url: './internationalized/index.html',
    urlText: <>Show <VisuallyHidden elementType="span">Internationalized</VisuallyHidden> Packages</>
  }
]} />

---

### Packages Dev Docs Pages React Spectrum Getting Started (`packages/dev/docs/pages/react-spectrum/getting-started.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

---
category: Introduction
---

# Getting Started

This page describes how to get started building an application with React Spectrum.

## What is React Spectrum?

**React Spectrum** is a React implementation of [Spectrum](https://spectrum.adobe.com/), Adobe's design system.
It provides components that are adaptive to interactions and screen sizes across devices, and includes full
screen reader and keyboard navigation support for accessibility.

## Installation

You can install React Spectrum package using a package manager like [npm](https://docs.npmjs.com/cli/npm) or
[yarn](https://classic.yarnpkg.com/lang/en/).

```
yarn add @adobe/react-spectrum
```

If you prefer, you can also install components from individually versioned packages. See the [versioning](versioning.html)
docs for more details.

## Build tooling

React Spectrum works with most popular build tooling, like [Parcel](https://parceljs.org) and
[create-react-app](https://create-react-app.dev), or lower level tools like [webpack](https://webpack.js.org/).

The only requirement is CSS importing support. This is built into Parcel and create-react-app out of the box.
If you're using React Spectrum with raw webpack, then you'll need to configure [css-loader](https://webpack.js.org/loaders/css-loader/).

If your application is written in TypeScript, be sure to add [@types/react](https://www.npmjs.com/package/@types/react) and [@types/react-dom](https://www.npmjs.com/package/@types/react-dom) to your project's dependencies as per React's [type checking guide](https://reactjs.org/docs/static-type-checking.html#type-definitions). React Spectrum components are published with their type definitions, so you can take advantage of static type checking, IDE autocomplete, and other TypeScript features.

## Setting up your app

All React Spectrum applications start with a [Provider](Provider.html). The `Provider` specifies the theme to use,
along with application level settings like the locale. Inside the `Provider`, you should render your application,
including all React Spectrum components.

```tsx example
import {Provider} from '@react-spectrum/provider';
import {theme} from '@react-spectrum/theme-default';
import {Button} from '@react-spectrum/button';

function App() {
  return (
    <Provider theme={theme}>
      <Button
        variant="accent"
        onPress={() => alert('Hey there!')}>
        Hello React Spectrum!
      </Button>
    </Provider>
  );
}
```

See the [Provider](Provider.html) and [Button](Button.html) docs for more information about the components used in this example.

## Next steps

Now that you've set up your app, you can read the documentation for the individual components to understand them in detail.
We also have high level documentation about topics like [theming](theming.html), [custom styling](styling.html),
[layout](layout.html), and [testing](testing.html).

---

### Packages Dev Docs Pages React Spectrum Index (`packages/dev/docs/pages/react-spectrum/index.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import {Highlights, Hero} from '@react-spectrum/docs';
import heroNarrow from 'url:../assets/ReactSpectrum_Mobile_976x1025_1x.png';
import heroNarrow2x from 'url:../assets/ReactSpectrum_Mobile_976x1025_2x.png';
import heroNarrowWebp from 'url:../assets/ReactSpectrum_Mobile_976x1025_1x.webp';
import heroNarrow2xWebp from 'url:../assets/ReactSpectrum_Mobile_976x1025_2x.webp';
import heroWide from 'url:../assets/ReactSpectrum_976x445_1x.png';
import heroWide2x from 'url:../assets/ReactSpectrum_976x445_2x.png';
import heroWideWebp from 'url:../assets/ReactSpectrum_976x445_1x.webp';
import heroWide2xWebp from 'url:../assets/ReactSpectrum_976x445_2x.webp';
import clsx from 'clsx';
import linkStyle from '@adobe/spectrum-css-temp/components/link/vars.css';
import styles from '@react-spectrum/docs/src/docs.css';
import typographyStyles from '@adobe/spectrum-css-temp/components/typography/vars.css';

import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import ComboBoxAnatomy from '../assets/component-illustrations/ComboBox.svg';
import SelectAnatomy from '../assets/component-illustrations/Picker.svg';
import Button from '../assets/component-illustrations/Button.svg';
import ToggleButton from '../assets/component-illustrations/ToggleButton.svg';
import ActionButton from '../assets/component-illustrations/ActionButton.svg';
import ActionGroup from '../assets/component-illustrations/ActionGroup.svg';
import ButtonGroup from '../assets/component-illustrations/ButtonGroup.svg';
import Checkbox from '../assets/component-illustrations/Checkbox.svg';
import CheckboxGroup from '../assets/component-illustrations/CheckboxGroup.svg';
import RadioGroup from '../assets/component-illustrations/RadioGroup.svg';
import Switch from '../assets/component-illustrations/Switch.svg';
import TextField from '../assets/component-illustrations/TextField.svg';
import TextArea from '../assets/component-illustrations/TextArea.svg';
import NumberField from '../assets/component-illustrations/NumberField.svg';
import SearchField from '../assets/component-illustrations/SearchField.svg';
import Form from '../assets/component-illustrations/Form.svg';
import Meter from '../assets/component-illustrations/Meter.svg';
import ProgressCircle from '../assets/component-illustrations/ProgressCircle.svg';
import ProgressBar from '../assets/component-illustrations/ProgressBar.svg';
import StatusLight from '../assets/component-illustrations/StatusLight.svg';
import Tabs from '../assets/component-illustrations/Tabs.svg';
import Link from '../assets/component-illustrations/Link.svg';
import Breadcrumbs from '../assets/component-illustrations/Breadcrumbs.svg';
import Slider from '../assets/component-illustrations/Slider.svg';
import RangeSlider from '../assets/component-illustrations/RangeSlider.svg';
import Dialog from '../assets/component-illustrations/Dialog.svg';
import Tooltip from '../assets/component-illustrations/Tooltip.svg';
import Popover from '../assets/component-illustrations/Popover.svg';
import ContextualHelp from '../assets/component-illustrations/ContextualHelp.svg';
import Menu from '../assets/component-illustrations/Menu.svg';
import ListBox from '../assets/component-illustrations/ListBox.svg';
import ListView from '../assets/component-illustrations/ListView.svg';
import Table from '../assets/component-illustrations/Table.svg';
import Tree from '../assets/component-illustrations/Tree.svg';
import Calendar from '../assets/component-illustrations/Calendar.svg';
import RangeCalendar from '../assets/component-illustrations/RangeCalendar.svg';
import DateField from '../assets/component-illustrations/DateField.svg';
import TimeField from '../assets/component-illustrations/TimeField.svg';
import DatePicker from '../assets/component-illustrations/DatePicker.svg';
import DateRangePicker from '../assets/component-illustrations/DateRangePicker.svg';
import LabeledValue from '../assets/component-illustrations/LabeledValue.svg';
import Badge from '../assets/component-illustrations/Badge.svg';
import TagGroup from '../assets/component-illustrations/TagGroup.svg';
import DropZone from '../assets/component-illustrations/DropZone.svg';
import FileTrigger from '../assets/component-illustrations/FileTrigger.svg'
import ColorSlider from '../assets/component-illustrations/ColorSlider.svg';
import ColorWheel from '../assets/component-illustrations/ColorWheel.svg';
import ColorArea from '../assets/component-illustrations/ColorArea.svg';
import ColorField from '../assets/component-illustrations/ColorField.svg';
import ColorSwatch from '../assets/component-illustrations/ColorSwatch.svg';
import ColorSwatchPicker from '../assets/component-illustrations/ColorSwatchPicker.svg';
import ColorPicker from '../assets/component-illustrations/ColorPicker.svg';
import Disclosure from '../assets/component-illustrations/Disclosure.svg';
import Accordion from '../assets/component-illustrations/DisclosureGroup.svg';
import Toast from '../assets/component-illustrations/Toast.svg';

---
category: Libraries
description: A React implementation of Spectrum, Adobe’s design system. Spectrum provides adaptive, accessible, and cohesive experiences for all Adobe applications.
---

# React Spectrum

A React implementation of Spectrum, Adobe’s design system.

<p className={clsx(typographyStyles['spectrum-Body2'], styles.homeLinks)}>
  <a href="getting-started.html" className={clsx(linkStyle['spectrum-Link'], styles.link)}>Get started</a>
  <span aria-hidden="true">•</span>
  <a href="https://github.com/adobe/react-spectrum" className={clsx(linkStyle['spectrum-Link'], styles.link)}>GitHub</a>
</p>

<Hero
  narrow={heroNarrow}
  narrow2x={heroNarrow2x}
  narrowWebp={heroNarrowWebp}
  narrow2xWebp={heroNarrow2xWebp}
  wide={heroWide}
  wide2x={heroWide2x}
  wideWebp={heroWideWebp}
  wide2xWebp={heroWide2xWebp}
  alt="React Spectrum hero image" />

<Highlights items={[
  {
    title: 'Accessible',
    description: 'React Spectrum components are designed with accessibility top-of-mind and include full screen reader and keyboard navigation support.',
  },
  {
    title: 'Adaptive',
    description: 'React Spectrum components are designed to work with mouse, touch, and keyboard interactions. They’re built with responsive design principles to deliver a great experience, no matter the device.',
  },
  {
    title: 'Color schemes',
    description: 'React Spectrum includes automatic support for dark and light mode based on operating system settings.'
  },
  {
    title: 'International',
    description: 'React Spectrum components are designed to support over 30 languages, including support for right-to-left languages, date and number formatting, and more.'
  }
]} />

## Components

### Buttons

<section className={styles.cardGroup}>

<ExampleCard
  url="Button.html"
  title="Button"
  description="A button allows a user to perform an action or to navigate to another page.">
  <Button />
</ExampleCard>

<ExampleCard
  url="ActionButton.html"
  title="ActionButton"
  description="An action button allows a user to perform an action.">
  <ActionButton />
</ExampleCard>

<ExampleCard
  url="ToggleButton.html"
  title="ToggleButton"
  description="A toggle button allows a user to toggle between two states.">
  <ToggleButton />
</ExampleCard>

<ExampleCard
  url="ButtonGroup.html"
  title="ButtonGroup"
  description="A button group is a grouping of buttons whose actions are related to each other.">
  <ButtonGroup />
</ExampleCard>

<ExampleCard
  url="ActionGroup.html"
  title="ActionGroup"
  description="An action group is a grouping of action buttons that are related to each other.">
  <ActionGroup />
</ExampleCard>

<ExampleCard
  url="FileTrigger.html"
  title="FileTrigger"
  description="A file trigger allows a user to access the file system with a Button.">
  <FileTrigger />
</ExampleCard>

</section>

### Pickers

<section className={styles.cardGroup}>

<ExampleCard
  url="ComboBox.html"
  title="ComboBox"
  description="A combobox combines a text input with a listbox, and allows a user to filter a list of options.">
  <ComboBoxAnatomy />
</ExampleCard>

<ExampleCard
  url="Picker.html"
  title="Picker"
  description="A picker displays a collapsible list of options, and allows a user to select one of them.">
  <SelectAnatomy />
</ExampleCard>

</section>

### Collections

<section className={styles.cardGroup}>

<ExampleCard
  url="Menu.html"
  title="Menu"
  description="A menu displays a list of actions or options that a user can choose.">
  <Menu />
</ExampleCard>

<ExampleCard
  url="ListBox.html"
  title="ListBox"
  description="A listbox displays a list of options, and allows a user to select one or more of them.">
  <ListBox />
</ExampleCard>

<ExampleCard
  url="ListView.html"
  title="ListView"
  description="A ListView displays a list of interactive items, with keyboard navigation, row selection, and actions.">
  <ListView />
</ExampleCard>

<ExampleCard
  url="TableView.html"
  title="TableView"
  description="A table view displays data in rows and columns, with row selection and sorting.">
  <Table />
</ExampleCard>

<ExampleCard
  url="TreeView.html"
  title="TreeView"
  description="A tree view displays hierarchical data with selection and collapsing.">
  <Tree />
</ExampleCard>

<ExampleCard
  url="TagGroup.html"
  title="TagGroup"
  description="A tag group displays a list of items, with support for keyboard navigation and removal.">
  <TagGroup />
</ExampleCard>

</section>

### Date and time

<section className={styles.cardGroup}>

<ExampleCard
  url="DatePicker.html"
  title="DatePicker"
  description="A date picker combines a DateField and a Calendar popover.">
  <DatePicker />
</ExampleCard>

<ExampleCard
  url="DateRangePicker.html"
  title="DateRangePicker"
  description="A date range picker combines two DateFields and a RangeCalendar popover.">
  <DateRangePicker />
</ExampleCard>

<ExampleCard
  url="DateField.html"
  title="DateField"
  description="A date field allows a user to enter and edit date values using a keyboard.">
  <DateField />
</ExampleCard>

<ExampleCard
  url="TimeField.html"
  title="TimeField"
  description="A time field allows a user to enter and edit time values using a keyboard.">
  <TimeField />
</ExampleCard>

<ExampleCard
  url="Calendar.html"
  title="Calendar"
  description="A calendar allows a user to select a single date from a date grid.">
  <Calendar />
</ExampleCard>

<ExampleCard
  url="RangeCalendar.html"
  title="RangeCalendar"
  description="A range calendar allows a user to select a contiguous range of dates.">
  <RangeCalendar />
</ExampleCard>

</section>

### Color

<section className={styles.cardGroup}>

<ExampleCard
  url="ColorPicker.html"
  title="ColorPicker"
  description="A color picker combines a swatch with a customizable popover for editing a color.">
  <ColorPicker />
</ExampleCard>

<ExampleCard
  url="ColorArea.html"
  title="ColorArea"
  description="A color area allows users to adjust two channels of a color value.">
  <ColorArea />
</ExampleCard>

<ExampleCard
  url="ColorSlider.html"
  title="ColorSlider"
  description="A color slider allows users to adjust an individual channel of a color value.">
  <ColorSlider />
</ExampleCard>

<ExampleCard
  url="ColorWheel.html"
  title="ColorWheel"
  description="A color wheel allows users to adjust the hue of a color value on a circular track.">
  <ColorWheel />
</ExampleCard>

<ExampleCard
  url="ColorField.html"
  title="ColorField"
  description="A color field allows users to edit a hex color or individual color channel value.">
  <ColorField />
</ExampleCard>

<ExampleCard
  url="ColorSwatch.html"
  title="ColorSwatch"
  description="A color swatch displays a preview of a selected color.">
  <ColorSwatch />
</ExampleCard>

<ExampleCard
  url="ColorSwatchPicker.html"
  title="ColorSwatchPicker"
  description="A color swatch picker displays a list of color swatches and allows a user to select one of them.">
  <ColorSwatchPicker />
</ExampleCard>

</section>

### Overlays

<section className={styles.cardGroup}>

<ExampleCard
  url="Dialog.html"
  title="Dialog"
  description="A dialog is an overlay shown above other content in an application.">
  <Dialog />
</ExampleCard>

<ExampleCard
  url="DialogTrigger.html"
  title="DialogTrigger"
  description="Displays a dialog in a popover, modal, or tray in response to a trigger.">
  <Popover />
</ExampleCard>

<ExampleCard
  url="Tooltip.html"
  title="Tooltip"
  description="A tooltip displays a description of an element on hover or focus.">
  <Tooltip />
</ExampleCard>

<ExampleCard
  url="ContextualHelp.html"
  title="ContextualHelp"
  description="Contextual help shows extra information about an adjacent component.">
  <ContextualHelp />
</ExampleCard>

</section>

### Forms

<section className={styles.cardGroup}>

<ExampleCard
  url="Checkbox.html"
  title="Checkbox"
  description="A checkbox allows a user to select an individual option.">
  <Checkbox />
</ExampleCard>

<ExampleCard
  url="CheckboxGroup.html"
  title="CheckboxGroup"
  description="A checkbox group allows a user to select one or more items in a list of options.">
  <CheckboxGroup />
</ExampleCard>

<ExampleCard
  url="RadioGroup.html"
  title="RadioGroup"
  description="A radio group allows a user to select a single item from a list of options.">
  <RadioGroup />
</ExampleCard>

<ExampleCard
  url="Switch.html"
  title="Switch"
  description="A switch allows a user to turn a setting on or off.">
  <Switch />
</ExampleCard>

<ExampleCard
  url="TextField.html"
  title="TextField"
  description="A text field allows a user to enter a plain text value with a keyboard.">
  <TextField />
</ExampleCard>

<ExampleCard
  url="TextArea.html"
  title="TextArea"
  description="A text area allows a user to enter a multi-line text value with a keyboard.">
  <TextArea />
</ExampleCard>

<ExampleCard
  url="SearchField.html"
  title="SearchField"
  description="A search field allows a user to enter and clear a search query.">
  <SearchField />
</ExampleCard>

<ExampleCard
  url="NumberField.html"
  title="NumberField"
  description="A number field allows a user to enter, increment, or decrement a numeric value.">
  <NumberField />
</ExampleCard>

<ExampleCard
  url="Form.html"
  title="Form"
  description="A form provides layout and alignment for a grouping of fields.">
  <Form />
</ExampleCard>

<ExampleCard
  url="Slider.html"
  title="Slider"
  description="A slider allows a user to select a numeric value within a range.">
  <Slider />
</ExampleCard>

<ExampleCard
  url="RangeSlider.html"
  title="RangeSlider"
  description="A range slider allows a user to select a range of values within a larger range.">
  <RangeSlider />
</ExampleCard>

</section>

### Navigation

<section className={styles.cardGroup}>

<ExampleCard
  url="Tabs.html"
  title="Tabs"
  description="Tabs organize content into multiple sections, and allow a user to view one at a time.">
  <Tabs />
</ExampleCard>

<ExampleCard
  url="Link.html"
  title="Link"
  description="A link allows a user to navigate to another page.">
  <Link />
</ExampleCard>

<ExampleCard
  url="Breadcrumbs.html"
  title="Breadcrumbs"
  description="Breadcrumbs display a hierarchy of links to the current page or resource.">
  <Breadcrumbs />
</ExampleCard>

<ExampleCard
  url="Disclosure.html"
  title="Disclosure"
  description="A disclosure is a collapsible section of content.">
  <Disclosure />
</ExampleCard>

<ExampleCard
  url="Accordion.html"
  title="Accordion"
  description="An accordion is a grouping of related disclosures.">
  <Accordion />
</ExampleCard>

</section>

### Status

<section className={styles.cardGroup}>

<ExampleCard
  url="ProgressBar.html"
  title="ProgressBar"
  description="A progress bar shows progress of an operation over time with a linear representation.">
  <ProgressBar />
</ExampleCard>

<ExampleCard
  url="ProgressCircle.html"
  title="ProgressCircle"
  description="A progress circle shows progress of an operation over time with a circular representation.">
  <ProgressCircle />
</ExampleCard>

<ExampleCard
  url="Meter.html"
  title="Meter"
  description="A meter represents a quantity within a known range, or a fractional value.">
  <Meter />
</ExampleCard>

<ExampleCard
  url="LabeledValue.html"
  title="LabeledValue"
  description="A labeled value displays a non-editable value with a label, with locale-specific formatting.">
  <LabeledValue />
</ExampleCard>

<ExampleCard
  url="StatusLight.html"
  title="StatusLight"
  description="A status light displays the status or category of an entity.">
  <StatusLight />
</ExampleCard>

<ExampleCard
  url="Badge.html"
  title="Badge"
  description="A badge displays color-categorized metadata for an object.">
  <Badge />
</ExampleCard>

<ExampleCard
  url="Toast.html"
  title="Toast"
  description="A toast displays a temporary notification of an action, error, or other event.">
  <Toast />
</ExampleCard>

</section>

### Drag and drop
<section className={styles.cardGroup}>

<ExampleCard
  url="DropZone.html"
  title="DropZone"
  description="A drop zone is an area into which one or multiple objects can be dragged and dropped.">
  <DropZone />
</ExampleCard>

</section>

---

### Packages Dev Docs Pages Releases Index (`packages/dev/docs/pages/releases/index.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {BlogLayout, PostListing} from '@react-spectrum/docs';
export default BlogLayout;

---
category: Introduction
description: React Spectrum releases
---

# Releases

<PostListing type="releases" />

---

### .Storybook S2 Docs Migrating (`.storybook-s2/docs/Migrating.mdx`)

import {Migrating} from './Migrating.jsx';
import {H3} from './typography';

<Migrating />

---

### .Storybook S2 Docs Release Notes (`.storybook-s2/docs/Release Notes.mdx`)

import {Release030Intro} from './Release030Intro.jsx';
import {MDXLayout} from './MDXLayout';
export default MDXLayout;

# Release Notes

## v0.12.0

### Updates

- [ActionButton](?path=/docs/actionbutton--docs): Add pending state
- [ColorSlider](?path=/docs/colorslider--docs): Fix `ColorLoupe` position in RTL locales
- [ComboBox](?path=/docs/combobox--docs): Support avatars and onAction
- [CustomDialog](?path=/docs/customdialog--docs): Support custom widths
- [Dialog](?path=/docs/dialog--docs): Add XL size
- [Disclosure](?path=/docs/disclosure--docs): Add animation to disclosure
- [InlineAlert](?path=/docs/inlinealert--docs): Support heading-less Inline Alerts
- [Picker](?path=/docs/picker--docs): Support multiple selection and avatars
- [Tags](?path=/docs/taggroup--docs): Fix Tag collapse calculation for removeable tags
- [Tooltip](?path=/docs/tooltip--docs): Prevent text overflow by default
- Allow placeholders in supported S2 components (e.g. ColorArea, ComboBox, NumberField, SearchField, TextArea, TextField)
- Apply `page.css` styles to the Shadow DOM

### Popover Styling Updates

The Popover component has been updated to better support custom styling. To
remove the preset padding, use the new `padding` prop and wrap your Popover content
in a custom div with your desired styling.

## v0.11.0

### New Components

- [SelectBoxGroup](?path=/docs/selectboxgroup-alpha--docs)

### Updates

- [ComboBox](?path=/docs/combobox--docs): Fix empty state rendering when no items match the current query
- [Picker](?path=/docs/picker--docs): Fix erroneous dropdown outline when opening the Picker via click
- [Tabs](?path=/docs/tabs--docs): Support collapse behavior on Tabs when customizing the layout

## v0.10.0

### Font update

This release introduces a new font for Spectrum 2: Adobe Clean Spectrum VF. This is an evolution of the previous Adobe Clean, with slightly updated metrics allowing for better vertical centering. Along with this update, the S2 Provider component now automatically handles loading the fonts needed for the user's language. The new font does not affect previous versions of React Spectrum.

If you previously used `page.css` without a `Provider`, you'll need to add a `Provider` around your app to load the fonts. See the [updated docs](?path=/docs/intro--docs#setting-up-your-app) for details.

### New Components

- [Calendar](?path=/docs/calendar--docs)
- [RangeCalendar](?path=/docs/rangecalendar--docs)
- [DateField](?path=/docs/datefield--docs)
- [DatePicker](?path=/docs/datepicker--docs)
- [DateRangePicker](?path=/docs/daterangepicker--docs)
- [TimeField](?path=/docs/timefield--docs)

### Updates

- [CardView](?path=/docs/cardview--docs): Fix ActionBar from not scrolling
- [ActionButton](?path=/docs/actionbutton--docs): Fix avatar-only ActionButtons to have square dimensions
- [Tabs](?path=/docs/tabs--docs): Improve selection indicator animation, fix collasped tabs
- [ProgressCircle](?path=/docs/progresscircle--docs): Add track outline in High Contrast Mode
- [Switch](?path=/docs/switch--docs): Fix the toggle in RTL locales
- [TreeView](?path=/docs/treeview--docs): Support async loading

## v0.9.1

### Updates

- [Button](?path=/docs/button--docs): Fix focus visible styles from being applied on standard focus
- [ContextualHelp](?path=/docs/contextualhelp--docs): Update width to match Spectrum designs
- [Tabs](?path=/docs/tabs--docs): Update selection indicator when tab text changes
- [TagGroup](?path=/docs/taggroup--docs): Fix focus visible styles from being applied on standard focus

## v0.9.0

### Updates

- [Combobox](?path=/docs/combobox--docs): Support for virtualization and async loading
- [Dialog](?path=/docs/dialog--docs): Update sizes
- [Picker](?path=/docs/picker--docs): Support for virtualization and async loading
- [Popover](?path=/docs/popover--docs): Add `triggerRef` prop
- [TableView](?path=/docs/tableview--docs): Support custom menus in columns
- Apply `position: relative` to Radio and Checkbox to prevent layout jumps

### UNSAFE_className Typescript Error

Style macros passed to `UNSAFE_className` will now result in a TypeScript error. This is not allowed because `UNSAFE_className` is appended to the component’s own styles, not merged. For example, if you pass a style macro class that sets a property but the component also has a class setting the same property, both will be applied and result in undefined behavior depending on the order the CSS was loaded on the page.

We strongly discourage using `UNSAFE_className` because it results in inconsistent UIs and hard to maintain code. Instead, use [React Aria Components](https://react-spectrum.adobe.com/react-aria/index.html) with the [S2 style macro](https://react-spectrum.adobe.com/s2/index.html?path=/docs/style-macro--docs) to create custom components. [Safe style properties](https://react-spectrum.adobe.com/s2/index.html?path=/docs/intro--docs#styling) can be passed to the `styles` prop of an S2 component.

### Style macro updates

We have made significant changes to the way our Style Macro generates class names in an effort to make them stable between versions. While we work to stabilize the style macro class names, we have added a postfix based on the version number so that class names don't conflict with any prior or future version.

We also made some changes to the available style macro values.

- Reduced the default spacing scale so it only goes up to 96px. Other values can be used via the `space()` macro
- Switched to rems for media queries. Since component sizes scale with rems, breakpoints need to match.
- Switch to px instead of rems for padding and absolute positioning. This avoids adding extra whitespace that causes additional text wrapping.
- Used rems and touch scaling for icon sizes, and added t-shirt size prop
- Added support for percentages and [viewport relative units](https://www.w3.org/TR/css-values-4/#viewport-relative-lengths) (e.g. vw)
- Added support for arbitrary [aspect ratio values](https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio)
- Added support for `calc` and other [math functions](https://www.w3.org/TR/css-values-4/#math)
- Added support for [css-wide keywords](https://www.w3.org/TR/css-values-4/#common-keywords) like `inherit`
- Colors no longer include default hover/press/focus states (e.g. `backgroundColor: 'accent'`). Use the `baseColor` macro instead.
- The `control` value has been removed from `fontSize`, `borderRadius`, `width`, `height`, and other sizing properties. Use explicit values for each t-shirt size instead.
- Fixed spelling of `disc` in `listStyleType` (was `dist`)

## v0.8.0

### New Components

- [NotificationBadge](?path=/docs/actionbutton--docs#notification-badges)
- [Toast](?path=/docs/toast--docs) (alpha)

### Updates

- Pass DOM Props to ButtonGroup
- Prevent Dividers from growing or shrinking in a flex container by default
- Export Autocomplete
- Export SortDescriptor type

### Disclosure Design updates

Spectrum has updated the S disclosure design. As a result, all other sizes (M, L, XL) now map to one size smaller than before. See [PR](https://github.com/adobe/react-spectrum/pull/8006) for details.

## v0.7.0

### New Components

- [TreeView](?path=/docs/treeview--docs)

### Updates

- [Badge](?path=/docs/badge--docs): Add `overflowMode` prop, fix icon alignment, update typo from `variant="charteuse"` to `variant="chartreuse"`
- [CardView](?path=/docs/cardview--docs): Fix styling when using `renderActionBar`
- Image: Add `fetchPriority` prop
- [Menu](?path=/docs/menu--docs): Fix menu item's focus rings from exceeding popover boundaries
- [Tabs](?path=/docs/tabs--docs): Add collapse behavior
- Remove `all: revert-layer` from style macro generated CSS to fix Safari issues
- Remove references to CSS `flex` shorthand. Please use `flexGrow`, `flexBasis`, and `flexShrink` instead.

### Codemods

- Update S2 icon migration map
- Handle margin/padding shorthands in style props codemod

### Important CSS update

In this release, we have made significant changes to the way our Style Macro generates CSS in order to fix issues with Safari. The Style Macro uses [CSS Cascade Layers](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Cascade_layers) to avoid CSS specificity and ordering issues. However, this means global CSS declared outside a `@layer`, such as CSS resets, will take precedence over S2's CSS. To avoid this, we previously used [all: revert-layer](https://developer.mozilla.org/en-US/docs/Web/CSS/revert-layer). Unfortunately, due to numerous bugs in Safari 18, this caused rendering issues in our components.

To fix these Safari issues, we have removed `all: revert-layer` in this release. This means that global CSS will now take precedence over S2's styles. **If you are using a CSS reset on the same page as S2 components, you will need to remove it** or put it in a `@layer` of its own. See [the docs](?path=/docs/intro--docs#css-resets) for more information.

**If you are using a version older than React Spectrum v3 on the same page, you must update to the latest version.** See the Adobe internal documentation for more details.

## v0.6.0

### New Components

- [ActionBar](?path=/docs/actionbar--docs)

### Updates

- [Button](?path=/docs/button--docs): Add `genai` and `premium` gradient variants
- [Menu](?path=/docs/menu--docs): Add `hideLinkOutIcon` prop, update alignment of items in different sections, and show checkmark on selected items that are links.
- Added `staticColor="auto"` option to [ActionButton](?path=/docs/actionbutton--docs), [ToggleButton](?path=/docs/togglebutton--docs), [Divider](?path=/docs/divider--docs), [Meter](?path=/docs/meter--docs), [ProgressBar](?path=/docs/progressbar--docs), and [Link](?path=/docs/link--docs)
- [ContextualHelp](?path=/docs/contextualhelp--docs): Fix alignment with field labels
- [InlineAlert](?path=/docs/inlinealert--docs): Remove maximum width
- [CheckboxGroup](?path=/docs/checkboxgroup--docs): Fix `isRequired` within a Form

### Codemods

- Added TableView codemods

## v0.5.0

In this release we have updated our Dialog and DialogTrigger APIs to improve layout flexibility for custom dialogs and popovers. Dialog has been split into four components:

- [Dialog](?path=/docs/dialog--docs) – a modal dialog with a standard layout with slots for the heading, content, hero image, button group, etc. This corresponds to the previous `type="modal"` API.
- [FullscreenDialog](?path=/docs/fullscreendialog--docs) – a fullscreen or takeover modal, similar to a Dialog but with different slots and layout. This corresponds to the previous `type="fullscreen"` and `type="fullscreenTakeover"` APIs.
- [CustomDialog](?path=/docs/customdialog--docs) – a modal dialog with a completely custom layout. It can have default padding or go edge-to-edge. No built-in slots are provided, the layout is entirely up to you.
- [Popover](?path=/docs/popover--docs) Popovers no longer support the previous dialog-style layout, which was rarely needed in recent apps. In addition, popover now has a reduced amount of padding by default, which was a common request.

In addition, several DialogTrigger props have moved to the above children:

- `type` is removed. Use one of the above components instead.
- `isKeyboardDismissDisabled` moved to Dialog, FullscreenDialog, and CustomDialog
- `isDismissable` was renamed to `isDismissible` (fixed spelling), and moved to Dialog and CustomDialog
- `hideArrow`, `offset`, `crossOffset`, `containerPadding`, `placement`, and `shouldFlip` moved to Popover

We've also continued to iterate on developer experience based on your feedback. Documentation on style macro usage with regards to
[colors](?path=/docs/style-macro--docs#colors) and [typography](?path=/docs/style-macro--docs#typography) have been added to help clarify
these common use cases. Style macro properties like `width` and `height` now allow for arbitrary pixel size values, please see the [docs](?path=/docs/style-macro--docs#sizing)
for more information. Finally, documentation on [optimizing CSS bundling](?path=/docs/style-macro--docs#css-optimization) have also been
added to help you generate a properly optimized output when using the bundler of your choice.

### New components

- [ActionButtonGroup](?path=/docs/actionbuttongroup--docs)
- [CloseButton](?path=/docs/customdialog--docs)
- [CustomDialog](?path=/docs/customdialog--docs)
- [FullscreenDialog](?path=/docs/fullscreendialog--docs)
- [Popover](?path=/docs/popover--docs)
- [ToggleButtonGroup](?path=/docs/togglebuttongroup--docs)

### Updates

- [Accordion](?path=/docs/accordion--docs): Add support for adjacent sibling elements in header
- [ActionButton](?path=/docs/actionbutton--docs): Add support for Avatars in ActionButtons
- [Dialog](?path=/docs/dialog--docs): See above for a summary of the changes to Dialog and Dialog adjacent components.
- [Disclosure](?path=/docs/disclosure--docs): Add support for adjacent sibling elements in header
- [DropZone](?path=/docs/dropzone--docs): Add t-shirt sizing
- [Menu](?path=/docs/menu--docs): Add support for separate user defined selection modes per MenuSection
- [Meter](?path=/docs/meter--docs): Add label positioning support
- Update Spectrum Tokens to v53
- Allow arbitrary pixel sizes for style macro sizing properties (e.g. width, height)

### Codemods

- Support Dialog updates
- Support ActionGroup -> ActionButtonGroup/ToggleButtonGroup
- Support arbitrary pixel sizing for style macro sizing properties
- Update S1 to S2 icon mapping

## v0.4.0

### New components

- [Accordion](?path=/docs/accordion--docs)
- [Disclosure](?path=/docs/disclosure--docs)
- [Card](?path=/docs/card--docs)
- [CardView](?path=/docs/cardview--docs)
- [SegmentedControl](?path=/docs/segmentedcontrol--docs)
- [TableView](?path=/docs/tableview--docs)

### Updates

- [ProgressBar](?path=/docs/progressbar--docs): Support side label, update edges to be rounded, and support custom widths
- [ProgressCircle](?path=/docs/progresscircle--docs): Update edges to be rounded
- [Badge](?path=/docs/badge--docs): Add subtle and outline fill variants
- [Breadcrumbs](?path=/docs/breadcrumbs--docs): Add collapse behavior
- [Button](?path=/docs/button--docs): Add support for pending state
- Update Spectrum Tokens to v46

### Codemods

- Handle legacy Link API
- Remove Section and Items imports if not used elsewhere in file
- Support Badge
- Support Well
- Support icons
- Fix links and install step

## v0.3.0

<Release030Intro />

### New components

- [NumberField](?path=/docs/numberfield--docs)
- [AlertDialog](?path=/docs/alertdialog--docs)
- [Linear and gradient illustrations](?path=/docs/illustrations--docs)
- [AvatarGroup](?path=/docs/avatargroup--docs)
- [Tabs](?path=/docs/tabs--docs)

### Updates

- Add collapse and action support to TagGroup
- Add support for new Adobe Clean variable font
- Updated [workflow icons](?path=/docs/workflow-icons--docs) – **PLEASE NOTE**: some icons changed names in this release.
- Add CLI and Parcel plugins to build custom icons and illustrations
- Add translations for all components
- Add slot contexts to all S2 components
- Fix menu z-index
- Fix overlay trigger press scaling and menu description color
- Fix ComboBox and NumberField custom width
- Fix padding on fields with no visible label
- Add ContextualHelp Storybook stories to components missing them

## v0.2.0

### New components

- [Breadcrumbs](?path=/docs/breadcrumbs--docs)
- [Contextual Help](?path=/docs/contextualhelp--docs)
- [ColorArea](?path=/docs/colorarea--docs)
- [ColorField](?path=/docs/colorfield--docs)
- [ColorSlider](?path=/docs/colorslider--docs)
- [ColorSwatch](?path=/docs/colorswatch--docs)
- [ColorSwatchPicker](?path=/docs/colorswatchpicker--docs)
- [ColorWheel](?path=/docs/colorwheel--docs)
- [RangeSlider](?path=/docs/rangeslider--docs)
- [Slider](?path=/docs/slider--docs)

### Updates

- [ESBuild starter](https://github.com/adobe/react-spectrum/tree/main/examples/s2-esbuild-starter-app) added
- InlineAlert iconography updated
- ContextualHelp added to all form field components
- Fixed custom widths for field components
- Spectrum tokens updated
- CSS processing updated so output size is smaller

See the updated [API changelog](https://github.com/adobe/react-spectrum/blob/main/packages/@react-spectrum/s2/api-diff.md) for a full list of changes since RSP v3.

## v0.1.0

### New components

- [Badge](?path=/docs/badge--docs)
- [ComboBox](?path=/docs/combobox--docs)
- [Meter](?path=/docs/meter--docs)
- [Picker](?path=/docs/picker--docs)

### Updates

- [TagGroup](?path=/docs/taggroup--docs) now supports avatars, images, error message and description help text, and improved hover/focus styling
- Updated React Aria Components to v1.2.0
- Fixed global styles such as CSS resets from applying to Spectrum 2 elements. Note that any CSS rule referenced from an `UNSAFE_className` prop must now be wrapped in `@layer UNSAFE_overrides`. See [the docs](?path=/docs/intro--docs#unsafe-style-overrides) for more details.
- The `style` macro will now error if it is called without importing `with {type: 'macro'}`. Previously it would fail to apply styles silently. This should help with debugging.

See the updated [API changelog](https://github.com/adobe/react-spectrum/blob/main/packages/@react-spectrum/s2/api-diff.md) for a full list of changes since RSP v3.

---

### Contributing Codegen (`docs/contributing/codegen.md`)

# Generated code

@adobe/react-spectrum v3 icon components are generated (`yarn build:icons`) and @react-spectrum/s2 icons are handled through a parcel transformer, not hand-written, and `postinstall` runs `patch-package`, so run install on a fresh clone.

---

### Contributing I18n Strings (`docs/contributing/i18n-strings.md`)

# User-facing strings (i18n)

Add the key to the package's `intl/en-US.json` (ICU MessageFormat) and read it via the localized string hook. Never hardcode UI text, and don't hand-edit the other locale files (translators own those).

---

### Contributing Pull Requests (`docs/contributing/pull-requests.md`)

# Pull requests

## Commenting

Comments while developing are fine. Before presenting code for review, trim verbose comments so the diff reads cleanly. When a genuinely complex section still warrants a comment, prefer a higher-level explanation of the whole section over annotating individual lines. Specific line comments are warranted when it's addressing a browser bug or the code deviates from other patterns.

## Opening a PR

Start from `.github/PULL_REQUEST_TEMPLATE.md` (e.g. `gh pr create --body-file .github/PULL_REQUEST_TEMPLATE.md`) rather than writing a body from scratch: fill in every section, complete the checklist honestly, and disclose AI use. Above the checklist, add a holistic summary of how the changes work and why this approach was chosen — give the intent separately from the implementation.

See also `CONTRIBUTING.md` (AI-assisted contributions).

---

### Contributing S2 Styling (`docs/contributing/s2-styling.md`)

# S2 styling

Style with the `style` [macro](https://react-spectrum.adobe.com/styling) (`import {style} from '../style' with {type: 'macro'};` — the `with {type: 'macro'}` attribute is required). Pass typed style objects to it; don't write CSS files or hand-rolled className strings for S2.

---

### Contributing Testing (`docs/contributing/testing.md`)

# Testing

Test suites are split by type:

- **Jest tests** — `yarn test`
- **SSR tests** — `yarn test:ssr`
- **Browser tests** — `yarn test:browser`
- **Visual regression tests (VRT)** — `yarn chromatic`
- **High-contrast-mode VRT** — `yarn chromatic:forced-colors`

Maintainers run the Chromatic VRT suites themselves — don't run `yarn chromatic` / `yarn chromatic:forced-colors`. You can still start the VRT Storybooks locally to verify visual state: `yarn start:chromatic` and `yarn start:chromatic-fc`.

Tests are **not** co-located with source — each package keeps them in a sibling `test/` directory. The file suffix routes the test to a runner: `*.ssr.test.*` → `yarn test:ssr`, `*.browser.test.*` → `yarn test:browser`, plain `*.test.*` → `yarn test` (Jest). Shared test helpers live in `@react-aria/test-utils` / `@react-spectrum/test-utils` (the `User` event abstraction and per-component testers).

## Writing tests

- **Run the full suite before committing.** Do not write PR descriptions that list a subset of specific passing tests — run `yarn test`, `yarn test:ssr` and (when relevant) `yarn test:browser` — do not run the Chromatic VRT suites (see above).
- **Run lint and formatting before committing** (`yarn lint`, `yarn format`).
- **Test at the right level.** For any change at the RAC level or below (including hooks), write the test at the RAC level ideally. If the change lives at a higher level, test at that level.
- **Move to browser tests when needed.** If a test requires mocking specific browser behavior, consider moving it to the browser run (`yarn test:browser`).
- **Cover the reported issue.** When fixing a reported issue, add a test that reproduces the specific example given in the issue.
- **Check whether the test already exists.** Find a home for it near other similar tests.
- **Check code coverage** to help decide whether a new test adds value — this is subjective.
- **In unit tests, prefer** fake timers, our test utils, and user event. Aside from those, prefer not mocking other modules, instead, move the test to a higher level.
- **Combine tests** that share the same setup before an assertion.
- **Ground test titles in the goal**, not the implementation — double-check they are accurate.

---

### Contributing Tooling (`docs/contributing/tooling.md`)

# Tooling

This repo does **not** use the conventional JS toolchain — reach for these, and don't hand-format code or swap in defaults:

- **Format** — `oxfmt` (`yarn format`), not Prettier. The style is opinionated (single quotes, no bracket spacing → `{foo}`, no trailing commas). Always run the tool rather than formatting by hand.
- **Lint** — `oxlint` (`oxlint packages --fix`) plus repo-local rules, not ESLint. `yarn lint` bundles format-check, type-check, `oxlint`, and Yarn `constraints` (`yarn constraints --fix`) (which enforce cross-package dependency versions).
- **Type-check** — `tsc` (`yarn check-types`), TypeScript 7's native compiler.
- **Build** — Parcel driven by `make` (`yarn build`), not plain `tsc`/rollup.
- **Yarn 4 workspaces** monorepo; use `yarn workspaces foreach` for cross-package operations.

## Storybook

Storybook is the main way to develop and view components: `yarn start` (v3/RAC) and `yarn start:s2` (S2).

---

### Packages @Internationalized Date Docs Calendar (`packages/@internationalized/date/docs/Calendar.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription, renderHTMLfromMarkdown} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';
import tableStyles from '@adobe/spectrum-css-temp/components/table/vars.css';
import styles from '@react-spectrum/docs/src/docs.css';
import typographyStyles from '@adobe/spectrum-css-temp/components/typography/vars.css';

---
category: Date and Time
keywords: [date, calendar, internationalization]
---

# Calendar

<PageDescription>{docs.exports.Calendar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Calendar']}
  sourceData={[]} />

## Introduction

While the Gregorian calendar is the most common, many other calendar systems are used throughout the world. The `Calendar` interface represents calendar systems in the `@internationalized/date` library. It encapsulates information such as the number of days in a month, the number of months in a year, and the list of eras in a calendar system, as well as methods that handle correct arithmetic of dates in that calendar system, as well as converting dates between calendar systems. Many implementations of this interface are provided in `@internationalized/date` to handle the most commonly used calendar systems.

As described in the docs for [CalendarDate](CalendarDate.html#calendar-systems) and other date objects, you can pass a `Calendar` instance to a date to represent a date in that calendar. Date manipulation follows the rules defined by that calendar system. You can also convert between calendar systems using the <TypeLink links={docs.links} type={docs.exports.toCalendar} /> function.

```tsx
import {HebrewCalendar, GregorianCalendar, toCalendar} from '@internationalized/date';

let hebrewDate = new CalendarDate(new HebrewCalendar(), 5781, 1, 1);
toCalendar(hebrewDate, new GregorianCalendar());
// => new CalendarDate(new GregorianCalendar(), 2020, 9, 19);
```

### Calendar identifiers

While it is possible to construct `Calendar` objects manually, a common usecase is to get a calendar object for a certain locale. Each calendar has an associated string identifier that can be used to retrieve an instance of that calendar using the <TypeLink links={docs.links} type={docs.exports.createCalendar} /> function. A list of supported calendar identifiers is available [below](#implementations).

```tsx
import {createCalendar} from '@internationalized/date';

createCalendar('gregory');
createCalendar('hebrew');
createCalendar('japanese');
```

Locales are typically represented as strings such as `en-US`, and represent information about a user's preferences, such as language, script, number format, and calendar. Most of this is automatically determined based on data, but it can also be provided in the locale string itself via a [locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string). For example, the locale `"hi-IN-u-ca-indian"` represents the Hindi language, in the country of India, using the `indian` calendar.

The [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) object can be used to get the calendar identifier from a locale string, either provided explicitly or implicitly. This can then be passed to the `createCalendar` function to retrieve a `Calendar` instance.

```tsx
// Get the calendar identifier for the current user.
let calendarIdentifier = new Intl.DateTimeFormat().resolvedOptions().calendar; // e.g. 'gregory'
createCalendar(calendarIdentifier); // new GregorianCalendar()

// Language and region provided, calendar inferred.
let calendarIdentifier = new Intl.DateTimeFormat('th-TH').resolvedOptions().calendar; // 'buddhist'
createCalendar(calendarIdentifier); // new BuddhistCalendar()

// Calendar system set explicitly.
let calendarIdentifier = new Intl.DateTimeFormat('hi-IN-u-ca-indian').resolvedOptions().calendar; // 'indian'
createCalendar(calendarIdentifier); // new IndianCalendar()
```

**Note**: importing `createCalendar` into your project will result in all available calendars being included in your bundle. If you wish to limit the supported calendars to reduce bundle sizes, you can create your own implementation that only imports the desired classes. This way, your bundler can tree-shake the unused calendar implementations.

```tsx
import {GregorianCalendar, JapaneseCalendar} from '@internationalized/date';

function createCalendar(identifier) {
  switch (identifier) {
    case 'gregory':
      return new GregorianCalendar();
    case 'japanese':
      return new JapaneseCalendar();
    default:
      throw new Error(`Unsupported calendar ${identifier}`);
  }
}
```

## Implementations

<table className={`${tableStyles['spectrum-Table']} ${tableStyles['spectrum-Table--quiet']} ${styles.propTable}`}>
  <thead>
    <tr>
      <th className={tableStyles['spectrum-Table-headCell']}>Class</th>
      <th className={tableStyles['spectrum-Table-headCell']}>Identifier</th>
      <th className={tableStyles['spectrum-Table-headCell']}>Description</th>
    </tr>
  </thead>
  <tbody className={tableStyles['spectrum-Table-body']}>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.GregorianCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'gregory'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.GregorianCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.BuddhistCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'buddhist'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.BuddhistCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.EthiopicCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'ethiopic'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.EthiopicCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.EthiopicAmeteAlemCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'ethioaa'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.EthiopicAmeteAlemCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.CopticCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'coptic'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.CopticCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.HebrewCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'hebrew'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.HebrewCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.IndianCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'indian'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{docs.exports.IndianCalendar.description}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.IslamicCivilCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'islamic-civil'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.IslamicCivilCalendar.description)}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.IslamicTabularCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'islamic-tbla'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.IslamicTabularCalendar.description)}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.IslamicUmalquraCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'islamic-umalqura'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.IslamicUmalquraCalendar.description)}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.JapaneseCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'japanese'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.JapaneseCalendar.description)}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.PersianCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'persian'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.PersianCalendar.description)}</td>
    </tr>
    <tr className={tableStyles['spectrum-Table-row']}>
      <td className={tableStyles['spectrum-Table-cell']}><TypeLink links={docs.links} type={docs.exports.TaiwanCalendar} /></td>
      <td className={tableStyles['spectrum-Table-cell']}>
        <code className={typographyStyles['spectrum-Code4']}>
          <span className="token hljs-string">'roc'</span>
        </code>
      </td>
      <td className={tableStyles['spectrum-Table-cell']}>{renderHTMLfromMarkdown(docs.exports.TaiwanCalendar.description)}</td>
    </tr>
  </tbody>
</table>

## Interface

<ClassAPI links={docs.links} class={docs.exports.Calendar} />

## Custom calendars

You can create your own custom calendar system by implementing the `Calendar` interface shown above. This enables calendars that follow custom business rules. An example would be a fiscal year calendar that follows a [4-5-4 format](https://nrf.com/resources/4-5-4-calendar), where month ranges don't follow the usual Gregorian calendar.

To implement a calendar, either extend an existing implementation (e.g. `GregorianCalendar`) or implement the `Calendar` interface from scratch. The most important methods are `fromJulianDay` and `toJulianDay`, which convert between the calendar's year/month/day numbering system and a [Julian Day Number](https://en.wikipedia.org/wiki/Julian_day). This allows converting dates between calendar systems. Other methods such as `getDaysInMonth` and `getMonthsInYear` can be implemented to define how dates are organized in your calendar system.

The following code is an example of how you might implement a custom 4-5-4 calendar (though implementing a true 4-5-4 calendar would be more nuanced than this).

```
/* Detailed source-code truncated for AI context efficiency. */
```

This enables dates to be converted between calendar systems.

```tsx
import {GregorianCalendar, toCalendar} from '@internationalized/date';

let date = new CalendarDate(new Custom454(), 2024, 2, 1);
let gregorianDate = toCalendar(date, new GregorianCalendar());
// => new CalendarDate(new GregorianCalendar(), 2024, 1, 29);
```

---

### Packages @Internationalized Date Docs CalendarDate (`packages/@internationalized/date/docs/CalendarDate.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [date, calendar, internationalization]
---

# CalendarDate

<PageDescription>{docs.exports.CalendarDate.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['CalendarDate']}
  sourceData={[]} />

## Introduction

A `CalendarDate` object represents a date without any time components, in a specific calendar system such as the Gregorian calendar. Use this type to represent dates where the time is not important, such as a birthday or an all day calendar event. If you need to refer to a specific time, use a [CalendarDateTime](CalendarDateTime.html) or [ZonedDateTime](ZonedDateTime.html) instead.

A `CalendarDate` can be created using the constructor. This example creates a date that represents February 3rd, 2022 in the Gregorian calendar system.

```tsx
import {CalendarDate} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
```

You can also create a `CalendarDate` by parsing an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the <TypeLink links={docs.links} type={docs.exports.parseDate} /> function.

```tsx
import {parseDate} from '@internationalized/date';

let date = parseDate('2022-02-03');
```

Today's date can be retrieved using the <TypeLink links={docs.links} type={docs.exports.today} /> function. This requires a time zone identifier to be provided, which is used to determine the local date. The <TypeLink links={docs.links} type={docs.exports.getLocalTimeZone} /> function can be used to retrieve the user's current time zone.

**Note:** the local time zone is cached after the first call. You can reset it by calling <TypeLink links={docs.links} type={docs.exports.resetLocalTimeZone} />, or mock it in unit tests by calling <TypeLink links={docs.links} type={docs.exports.setLocalTimeZone} />.

```tsx
import {today, getLocalTimeZone} from '@internationalized/date';

let nyDate = today('America/New_York');
let localDate = today(getLocalTimeZone());
```

Once you have a `CalendarDate` object, you can read its properties, or manipulate it as described in the [Manipulating dates](#manipulating-dates) section below. You can also convert it to an ISO 8601 string, native JavaScript `Date` object, or another representation. See the [Conversion](#conversion) section below for details.

```tsx
let date = new CalendarDate(2022, 2, 3);
date.toString(); // '2022-02-03'
```

## Interface

<ClassAPI links={docs.links} class={docs.exports.CalendarDate} />

## Calendar systems

By default, `CalendarDate` uses the Gregorian calendar system, but many other calendar systems that are used around the world are supported, such as Hebrew, Indian, Islamic, Buddhist, Ethiopic, and more. A <TypeLink links={docs.links} type={docs.exports.Calendar} /> instance can be passed to the `CalendarDate` constructor to represent dates in that calendar system.

This example creates a date in the Buddhist calendar system, which is equivalent to April 30th, 2020 in the Gregorian calendar.

```tsx
import {BuddhistCalendar} from '@internationalized/date';

let date = new CalendarDate(new BuddhistCalendar(), 2563, 4, 30);
```

See the [Calendar](Calendar.html#implementations) docs for details about the supported calendars.

### Eras

Many calendar systems have only one era, or a modern era and a pre-modern era (e.g. AD and BC in the Gregorian calendar). However, other calendar systems may have many eras. For example, the Japanese calendar has eras for the reign of each Emperor. `CalendarDate` represents eras using string identifiers, which can be passed as an additional parameter to the constructor before the year. When eras are present, years are numbered starting from 1 within the era.

This example creates a date in the Japanese calendar system, which is equivalent to April 30th, 2019 in the Gregorian calendar.

```tsx
import {JapaneseCalendar} from '@internationalized/date';

let date = new CalendarDate(new JapaneseCalendar(), 'heisei', 31, 4, 30)
```

A list of valid era identifiers can be retrieved using the `getEras` method of a `Calendar` instance. If an era is not provided, the date is assumed to be in the current era.

### Converting between calendars

The <TypeLink links={docs.links} type={docs.exports.toCalendar} /> function can be used to convert a date from one calendar system to another.

This example converts a Gregorian date to a Hebrew one.

```tsx
import {toCalendar, HebrewCalendar} from '@internationalized/date';

let gregorianDate = new CalendarDate(2020, 9, 19);
let hebrewDate = toCalendar(gregorianDate, new HebrewCalendar());
// => new CalendarDate(new HebrewCalendar(), 5781, 1, 1)
```

## Manipulating dates

### Adding and subtracting durations

A <TypeLink links={docs.links} type={docs.exports.DateDuration} /> is an object that represents an amount of time, with fields such as `years`, `months`, and `days`. The `add` and `subtract` methods of `CalendarDate` objects can be used to adjust the date by the given duration. These methods return a new date, and do not mutate the original.

```tsx
let date = new CalendarDate(2022, 2, 3);

date.add({weeks: 1}); // 2022-02-10
date.add({months: 1}); // 2022-03-03
date.add({years: 1, months: 1, days: 1}); // 2023-03-04

date.subtract({weeks: 1}); // 2022-01-27
date.subtract({months: 1}); // 2022-01-03
date.subtract({years: 1, months: 1, days: 1}); // 2021-01-02
```

Adding or subtracting a duration that goes beyond the limits of a particular field will cause the date to be _balanced_. For example, adding one day to August 31st results in September 1st. In addition, if adding or subtracting one field causes another to be invalid, the date will be _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

### Parsing durations

The <TypeLink links={docs.links} type={docs.exports.parseDuration} /> function can be used to convert a [ISO 8601 duration string](https://en.wikipedia.org/wiki/ISO_8601#Durations) into a <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> object. Negative values can be written by prefixing the entire string with a minus sign.

```tsx
parseDuration('P3Y6M6W4D');
// => {years: 3, months: 6, weeks: 6, days: 4}

parseDuration('-P3Y6M6W4D');
// => {years: -3, months: -6, weeks: -6, days: -4}
```

### Setting fields

`CalendarDate` objects are immutable, which means their properties cannot be set directly. Instead, use the `set` method, and pass the fields to be modified. This will return a new `CalendarDate` with the updated values.

```tsx
let date = new CalendarDate(2022, 2, 3);
date.set({day: 10}); // 2022-02-10
date.set({month: 5}); // 2022-05-03
date.set({year: 2023, month: 10, day: 16}); // 2023-10-16
```

Setting a field to a value that is outside the valid range will cause it to be _constrained_. For example, setting the day to a value that is greater than the number of days in the month, will result in the last day of the month.

```tsx
let date = new CalendarDate(2022, 2, 3);
date.set({day: 100}); // 2022-02-28
date.set({month: 20}); // 2022-12-03
```

### Cycling fields

The `cycle` method allows incrementing or decrementing a single field. It is similar to the `add` and `subtract` methods, but when the value reaches the minimum or maximum, it wraps around rather than affecting other fields.

```tsx
let date = new CalendarDate(2022, 12, 31);
date.cycle('day', 1); // 2022-12-01
date.cycle('month', 1); // 2022-01-31

let date = new CalendarDate(2022, 1, 1);
date.cycle('day', -1); // 2022-01-31
date.cycle('month', -1); // 2022-12-01
```

The `round` option may also be passed, which causes the value to be rounded to increments of the given amount. For example, you could round the year to increments of 5.

```tsx
let date = new CalendarDate(2022, 2, 3);

date.cycle('year', 5); // 2027-02-03
date.cycle('year', 5, {round: true}); // 2025-02-03

date.cycle('year', -5); // 2017-02-03
date.cycle('year', -5, {round: true}); // 2020-02-03
```

Note that if cycling a field causes another field to become invalid, the date is _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

## Conversion

### To a string

`CalendarDate` objects can be converted to an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the `toString` method.

```tsx
let date = new CalendarDate(2022, 2, 3);
date.toString(); // '2022-02-03'
```

### To a native Date object

A `CalendarDate` can be converted to a native JavaScript `Date` object using the `toDate` method. In general, the `Date` object should be avoided because it has many internationalization issues and other flaws. However, it is necessary to use some functionality like date formatting.

Because a `Date` represents an exact time, a time zone identifier is required to be passed to the `toDate` method. The time of the returned date will be set to midnight in that time zone. The <TypeLink links={docs.links} type={docs.exports.getLocalTimeZone} /> function can be used to retrieve the user's current time zone.

**Note:** the local time zone is cached after the first call. You can reset it by calling <TypeLink links={docs.links} type={docs.exports.resetLocalTimeZone} />, or mock it in unit tests by calling <TypeLink links={docs.links} type={docs.exports.setLocalTimeZone} />.

```tsx
import {getLocalTimeZone} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
date.toDate('America/Los_Angeles'); // Thu Feb 03 2022 00:00:00 GMT-0800 (Pacific Standard Time)
date.toDate(getLocalTimeZone()); // e.g. Thu Feb 03 2022 00:00:00 GMT-0500 (Eastern Standard Time)
```

### To a date with time

A `CalendarDate` can be converted to a [CalendarDateTime](CalendarDateTime.html) or [ZonedDateTime](ZonedDateTime.html) by providing an optional [Time](Time.html) object and/or time zone identifier.

A <TypeLink links={docs.links} type={docs.exports.CalendarDateTime} /> represents a date with a time, but not in any specific time zone. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a `ZonedDateTime`.

Use the <TypeLink links={docs.links} type={docs.exports.toCalendarDateTime} /> function to convert a `CalendarDate` to a `CalendarDateTime`. By default, the time will be set to midnight. You can also pass a <TypeLink links={docs.links} type={docs.exports.Time} /> object to set the time to a specific value.

```tsx
import {toCalendarDateTime, Time} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);

toCalendarDateTime(date); // 2022-02-03T00:00:00
toCalendarDateTime(date, new Time(8, 30)); // 2022-02-03T08:30:00
```

A <TypeLink links={docs.links} type={docs.exports.ZonedDateTime} /> represents a date with a time in a specific time zone. Use this type to represent an exact moment in time at a particular location on Earth.

Use the <TypeLink links={docs.links} type={docs.exports.toZoned} /> function to convert a `CalendarDate` to a `ZonedDateTime`. The time will be set to midnight in the given time zone. If you need to set a specific time, convert the `CalendarDate` to a `CalendarDateTime` first as described above, and pass the result to `toZoned`.

```tsx
import {toZoned, toCalendarDateTime, Time} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
toZoned(date, 'America/Los_Angeles'); // 2021-02-03T00:00-07:00[America/Los_Angeles]

let dateTime = toCalendarDateTime(date, new Time(8, 30));
toZoned(dateTime, 'America/Los_Angeles'); // 2021-02-03T08:30-07:00[America/Los_Angeles]
```

## Queries

### Comparison

`CalendarDate` objects can be compared either for full or partial equality, or in order to determine which date is before or after another.

The `compare` method can be used to determine if a date is before or after another. It returns a number less than zero if the first date is before the second, zero if the values are equal, or a number greater than zero if the first date is after the second.

```tsx
let a = new CalendarDate(2022, 2, 3);
let b = new CalendarDate(2022, 3, 4);

a.compare(b) < 0; // true
b.compare(a) > 0; // true
```

In addition, the following functions can be used to perform a partial comparison. These functions accept dates in different calendar systems, and the second date is converted to the calendar system of the first date before comparison.

* <TypeLink links={docs.links} type={docs.exports.isSameYear} /> – <span>{docs.exports.isSameYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameMonth} /> – <span>{docs.exports.isSameMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameDay} /> – <span>{docs.exports.isSameDay.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isToday} /> – <span>{docs.exports.isToday.description}</span>

```tsx
import {isSameMonth, IslamicUmalquraCalendar} from '@internationalized/date';

isSameMonth(new CalendarDate(2021, 4, 16), new CalendarDate(2021, 4, 30)); // true
isSameMonth(new CalendarDate(2021, 4, 16), new CalendarDate(2021, 8, 2)); // false
isSameMonth(new CalendarDate(2021, 4, 16), new CalendarDate(new IslamicUmalquraCalendar(), 1442, 9, 4)); // true
```

A similar set of functions is also available that does not convert between calendar systems and requires the calendars to be equal.

* <TypeLink links={docs.links} type={docs.exports.isEqualYear} /> – <span>{docs.exports.isEqualYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualMonth} /> – <span>{docs.exports.isEqualMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualDay} /> – <span>{docs.exports.isEqualDay.description}</span>

```tsx
import {isEqualMonth, IslamicUmalquraCalendar} from '@internationalized/date';

isEqualMonth(new CalendarDate(2021, 4, 16), new CalendarDate(2021, 4, 30)); // true
isEqualMonth(new CalendarDate(2021, 4, 16), new CalendarDate(2021, 8, 2)); // false
isEqualMonth(new CalendarDate(2021, 4, 16), new CalendarDate(new IslamicUmalquraCalendar(), 1442, 9, 4)); // false
```

### Start and end dates

The following functions can be used to find the start or end dates of a particular unit of time.

* <TypeLink links={docs.links} type={docs.exports.startOfYear} /> – <span>{docs.exports.startOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfYear} /> – <span>{docs.exports.endOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfMonth} /> – <span>{docs.exports.startOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfMonth} /> – <span>{docs.exports.endOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfWeek} /> – <span>{docs.exports.startOfWeek.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfWeek} /> – <span>{docs.exports.endOfWeek.description}</span>


Note that `startOfWeek` and `endOfWeek` require a locale string to be provided. This is because the first day of the week changes depending on the locale. For example, in the United States, the first day of the week is on Sunday, but in France it is on Monday.

```tsx
import {startOfYear, startOfMonth, startOfWeek} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);

startOfYear(date); // 2022-01-01
startOfMonth(date); // 2022-02-01
startOfWeek(date, 'en-US'); // 2022-01-30
startOfWeek(date, 'fr-FR'); // 2022-01-31
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
startOfWeek(date, 'en-US', 'mon'); // 2022-01-31
```

### Day of week

The <TypeLink links={docs.links} type={docs.exports.getDayOfWeek} /> function returns the day of the week for the given date and locale. Days are numbered from zero to six, where zero is the first day of the week in the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getDayOfWeek} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 6); // a Sunday

getDayOfWeek(date, 'en-US'); // 0
getDayOfWeek(date, 'fr-FR'); // 6
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getDayOfWeek(date, 'en-US', 'mon'); // 6
```

### Weekdays and weekends

The <TypeLink links={docs.links} type={docs.exports.isWeekday} /> and <TypeLink links={docs.links} type={docs.exports.isWeekend} /> functions can be used to determine if a date is weekday or weekend respectively. This depends on the locale. For example, in the United States, weekends are Saturday and Sunday, but in Israel they are Friday and Saturday.

```tsx
import {isWeekday, isWeekend} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 6); // a Sunday

isWeekday(date, 'en-US'); // false
isWeekday(date, 'he-IL'); // true

isWeekend(date, 'en-US'); // true
isWeekend(date, 'he-IL'); // false
```

### Weeks in month

The <TypeLink links={docs.links} type={docs.exports.getWeeksInMonth} /> function returns the number of weeks in the given month. This depends on the number of days in the month, what day of the week the month starts on, and the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getWeeksInMonth} from '@internationalized/date';

let date = new CalendarDate(2021, 1, 1);

getWeeksInMonth(date, 'en-US'); // 6
getWeeksInMonth(date, 'fr-FR'); // 5
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getWeeksInMonth(date, 'en-US', 'mon'); // 5
```

---

### Packages @Internationalized Date Docs CalendarDateTime (`packages/@internationalized/date/docs/CalendarDateTime.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [date, time, calendar, internationalization]
---

# CalendarDateTime

<PageDescription>{docs.exports.CalendarDateTime.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['CalendarDateTime']}
  sourceData={[]} />

## Introduction

A `CalendarDateTime` object represents a date and time without a time zone, in a specific calendar system such as the Gregorian calendar. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a [ZonedDateTime](ZonedDateTime.html).

A `CalendarDateTime` can be created using the constructor. This example creates a date that represents February 3rd, 2022 at 9:15 AM in the Gregorian calendar system.

```tsx
import {CalendarDateTime} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 15);
```

You can also create a `CalendarDateTime` by parsing an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the <TypeLink links={docs.links} type={docs.exports.parseDateTime} /> function.

```tsx
import {parseDateTime} from '@internationalized/date';

let date = parseDateTime('2022-02-03T09:15');
```

Once you have a `CalendarDateTime` object, you can read its properties, or manipulate it as described in the [Manipulating dates](#manipulating-dates) section below. You can also convert it to an ISO 8601 string, native JavaScript `Date` object, or another representation. See the [Conversion](#conversion) section below for details.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 15);
date.toString(); // '2022-02-03T09:15:00'
```

## Interface

<ClassAPI links={docs.links} class={docs.exports.CalendarDateTime} />

## Calendar systems

By default, `CalendarDateTime` uses the Gregorian calendar system, but many other calendar systems that are used around the world are supported, such as Hebrew, Indian, Islamic, Buddhist, Ethiopic, and more. A <TypeLink links={docs.links} type={docs.exports.Calendar} /> instance can be passed to the `CalendarDateTime` constructor to represent dates in that calendar system.

This example creates a date in the Buddhist calendar system, which is equivalent to April 4th, 2020 at 9:15 AM in the Gregorian calendar.

```tsx
import {BuddhistCalendar} from '@internationalized/date';

let date = new CalendarDateTime(new BuddhistCalendar(), 2563, 4, 30, 9, 15);
```

See the [Calendar](Calendar.html#implementations) docs for details about the supported calendars.

### Eras

Many calendar systems have only one era, or a modern era and a pre-modern era (e.g. AD and BC in the Gregorian calendar). However, other calendar systems may have many eras. For example, the Japanese calendar has eras for the reign of each Emperor. `CalendarDateTime` represents eras using string identifiers, which can be passed as an additional parameter to the constructor before the year. When eras are present, years are numbered starting from 1 within the era.

This example creates a date in the Japanese calendar system, which is equivalent to April 4th, 2020 at 9:15 AM in the Gregorian calendar.

```tsx
import {JapaneseCalendar} from '@internationalized/date';

let date = new CalendarDateTime(
  new JapaneseCalendar(),
  'heisei', 31, 4, 30, 9, 15
);
```

A list of valid era identifiers can be retrieved using the `getEras` method of a `Calendar` instance. If an era is not provided, the date is assumed to be in the current era.

### Converting between calendars

The <TypeLink links={docs.links} type={docs.exports.toCalendar} /> function can be used to convert a date from one calendar system to another.

This example converts a Gregorian date to a Hebrew one.

```tsx
import {toCalendar, HebrewCalendar} from '@internationalized/date';

let gregorianDate = new CalendarDateTime(2020, 9, 19, 10, 30);
let hebrewDate = toCalendar(gregorianDate, new HebrewCalendar());
// => new CalendarDateTime(new HebrewCalendar(), 5781, 1, 1, 10, 30)
```

## Manipulating dates

### Adding and subtracting durations

A <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> is an object that represents an amount of time, with fields such as `years`, `months`, `hours`, and `minutes`. The `add` and `subtract` methods of `CalendarDateTime` objects can be used to adjust the date by the given duration. These methods return a new date, and do not mutate the original.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 45);

date.add({weeks: 1}); // 2022-02-10T09:45
date.add({months: 1}); // 2022-03-03T09:45
date.add({years: 1, months: 1, days: 1}); // 2023-03-04T09:45
date.add({hours: 1}); // 2022-02-03T10:45
date.add({minutes: 30}); // 2022-02-03T10:15

date.subtract({weeks: 1}); // 2022-01-27T09:45
date.subtract({months: 1}); // 2022-01-03T09:45
date.subtract({years: 1, months: 1, days: 1}); // 2021-01-02T09:45
date.subtract({hours: 1}); // 2022-02-03T8:45
date.subtract({minutes: 30}); // 2022-02-03T09:15
```

Adding or subtracting a duration that goes beyond the limits of a particular field will cause the date to be _balanced_. For example, adding one day to August 31st results in September 1st. In addition, if adding or subtracting one field causes another to be invalid, the date will be _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

### Parsing durations

The <TypeLink links={docs.links} type={docs.exports.parseDuration} /> function can be used to convert a [ISO 8601 duration string](https://en.wikipedia.org/wiki/ISO_8601#Durations) into a <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> object. The smallest time unit may include decimal values written with a comma or period, and negative values can be written by prefixing the entire string with a minus sign.

```tsx
parseDuration('P3Y6M6W4DT12H30M5S');
// => {years: 3, months: 6, weeks: 6, days: 4, hours: 12, minutes: 30, seconds: 5}

parseDuration('-P3Y6M6W4DT12H30M5S');
// => {years: -3, months: -6, weeks: -6, days: -4, hours: -12, minutes: -30, seconds: -5}

parseDuration('P3Y6M6W4DT12H30M5.5S');
// => {years: 3, months: 6, weeks: 6, days: 4, hours: 12, minutes: 30, seconds: 5.5}
```

### Setting fields

`CalendarDateTime` objects are immutable, which means their properties cannot be set directly. Instead, use the `set` method, and pass the fields to be modified. This will return a new `CalendarDateTime` with the updated values.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 45);
date.set({day: 10}); // 2022-02-10T09:45
date.set({month: 5}); // 2022-05-03T09:45
date.set({year: 2023, month: 10, day: 16}); // 2023-10-16T09:45
date.set({hour: 18}); // 2022-02-03T18:45
date.set({minute: 15}); // 2022-02-03T09:15
```

Setting a field to a value that is outside the valid range will cause it to be _constrained_. For example, setting the day to a value that is greater than the number of days in the month, will result in the last day of the month.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 45);
date.set({day: 100}); // 2022-02-28T09:45
date.set({month: 20}); // 2022-12-03T09:45
date.set({hour: 30}); // 2022-02-03T23:45
```

### Cycling fields

The `cycle` method allows incrementing or decrementing a single field. It is similar to the `add` and `subtract` methods, but when the value reaches the minimum or maximum, it wraps around rather than affecting other fields.

```tsx
let date = new CalendarDateTime(2022, 12, 31, 23, 59);
date.cycle('day', 1); // 2022-12-01T23:59
date.cycle('month', 1); // 2022-01-31T23:59
date.cycle('hour', 1); // 2022-12-31T00:59
date.cycle('minute', 1); // 2022-12-31T23:00

let date = new CalendarDateTime(2022, 1, 1, 0, 0);
date.cycle('day', -1); // 2022-01-31T00:00
date.cycle('month', -1); // 2022-12-01T00:00
date.cycle('hour', -1); // 2022-01-01T23:00
date.cycle('minute', -1); // 2022-01-01T00:59
```

Note that if cycling a field causes another field to become invalid, the date is _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

The `round` option may also be passed, which causes the value to be rounded to increments of the given amount. For example, you could round the minute to increments of 15.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 22);

date.cycle('minute', 15); // 2027-02-03T09:37
date.cycle('minute', 15, {round: true}); // 2025-02-03T09:30

date.cycle('minute', -15); // 2017-02-03T09:07
date.cycle('minute', -15, {round: true}); // 2020-02-03T09:15
```

By default, the `hour` field is cycled within a 24 hour range. The `hourCycle` option can be set to `12` to use a 12 hour clock instead, which will preserve the AM/PM value when formatted.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 11);
date.cycle('hour', 1); // 2022-02-03T12:00
date.cycle('hour', 1, {hourCycle: 12}); // 2022-02-03T00:00

let date = new CalendarDateTime(2022, 2, 3, 23);
date.cycle('hour', 1); // 2022-02-03T00:00
date.cycle('hour', 1, {hourCycle: 12}); // 2022-02-03T12:00
```

## Conversion

### To a string

`CalendarDateTime` objects can be converted to an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the `toString` method.

```tsx
let date = new CalendarDateTime(2022, 2, 3, 9, 45);
date.toString(); // '2022-02-03T09:45:00'
```

### To a date or time only

A `CalendarDateTime` can be converted to a [CalendarDate](CalendarDate.html) or [Time](Time.html) object if only one of these components is needed.

Use the <TypeLink links={docs.links} type={docs.exports.toCalendarDate} /> function to convert a `CalendarDateTime` to a `CalendarDate`.

```tsx
import {toCalendarDate} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 45);
toCalendarDate(date); // 2022-02-03
```

Use the <TypeLink links={docs.links} type={docs.exports.toTime} /> function to convert a `CalendarDateTime` to a `Time`.

```tsx
import {toTime} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 45);
toTime(date); // 09:45:00
```

### To a ZonedDateTime

A `CalendarDateTime` can be converted to a local time in a specific time zone using the <TypeLink links={docs.links} type={docs.exports.toZoned} /> function. This returns a <TypeLink links={docs.links} type={docs.exports.ZonedDateTime} /> object, which represents an exact moment in time at a particular location on Earth.

```tsx
import {toZoned} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 45);
toZoned(date, 'America/Los_Angeles'); // 2022-02-03T09:45-07:00[America/Los_Angeles]
```

Some time values during daylight saving transitions may be _ambiguous_. For example, in the United States, the 2 AM hour is skipped in the spring, and the 1 AM hour occurs twice in the fall. When converting a `CalendarDateTime` to a `ZonedDateTime`, this ambiguity must be resolved to determine the exact time. By default, the later of the two possible times is chosen for "spring forward" transitions, and the earlier time is chosen for "fall back" transitions. This can be controlled by passing the `disambiguation` parameter to the `toZoned` function.

* `'earlier'` – choose the earlier of the two possible times
* `'later'` – choose the later of the two possible times
* `'compatible'` (default) – choose the later of the two times during "spring forward" transitions, and the earlier time during "fall back" transitions.
* `'reject'` – throws an error when the time is ambiguous

```tsx
// A "spring forward" transition
let date = new CalendarDateTime(2020, 3, 8, 2);
toZoned(date, 'America/Los_Angeles'); // 2020-03-08T03:00:00-07:00[America/Los_Angeles]
toZoned(date, 'America/Los_Angeles', 'earlier'); // 2020-03-08T01:00:00-08:00[America/Los_Angeles]
toZoned(date, 'America/Los_Angeles', 'later'); // 2020-03-08T03:00:00-07:00[America/Los_Angeles]

// A "fall back" transition
let date = new CalendarDateTime(2020, 11, 1, 1);
toZoned(date, 'America/Los_Angeles'); // 2020-11-01T01:00:00-07:00[America/Los_Angeles]
toZoned(date, 'America/Los_Angeles', 'earlier'); // 2020-11-01T01:00:00-07:00[America/Los_Angeles]
toZoned(date, 'America/Los_Angeles', 'later'); // 2020-11-01T01:00:00-08:00[America/Los_Angeles]
```

### To a native Date object

A `CalendarDateTime` can be converted to a native JavaScript `Date` object using the `toDate` method. In general, the `Date` object should be avoided because it has many internationalization issues and other flaws. However, it is necessary to use some functionality like date formatting.

Because a `Date` represents an exact time, a time zone identifier is required to be passed to the `toDate` method. The <TypeLink links={docs.links} type={docs.exports.getLocalTimeZone} /> function can be used to retrieve the user's current time zone.

**Note:** the local time zone is cached after the first call. You can reset it by calling <TypeLink links={docs.links} type={docs.exports.resetLocalTimeZone} />, or mock it in unit tests by calling <TypeLink links={docs.links} type={docs.exports.setLocalTimeZone} />.

```tsx
import {getLocalTimeZone} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 45);
date.toDate('America/Los_Angeles'); // Thu Feb 03 2022 09:45:00 GMT-0800 (Pacific Standard Time)
date.toDate(getLocalTimeZone()); // e.g. Thu Feb 03 2022 09:45:00 GMT-0500 (Eastern Standard Time)
```

Some time values during daylight saving transitions may be _ambiguous_. For example, in the United States, the 2 AM hour is skipped in the spring, and the 1 AM hour occurs twice in the fall. When converting a `CalendarDateTime` to a `Date`, this ambiguity must be resolved to determine the exact time. This behavior can be controlled using the `disambiguation` parameter, as described [above](#to-a-zoneddatetime).

```tsx
// A "spring forward" transition
let date = new CalendarDateTime(2020, 3, 8, 2);
date.toDate('America/Los_Angeles', 'earlier');
// => Sun Mar 08 2020 01:00:00 GMT-0800 (Pacific Daylight Time)
```

## Queries

### Comparison

`CalendarDateTime` objects can be compared either for full or partial equality, or in order to determine which date is before or after another.

The `compare` method can be used to determine if a date is before or after another. It returns a number less than zero if the first date is before the second, zero if the values are equal, or a number greater than zero if the first date is after the second.

```tsx
let a = new CalendarDateTime(2022, 2, 3, 9, 45);
let b = new CalendarDateTime(2022, 3, 4, 12, 20);

a.compare(b) < 0; // true
b.compare(a) > 0; // true
```

In addition, the following functions can be used to perform a partial comparison. These functions accept dates in different calendar systems, and the second date is converted to the calendar system of the first date before comparison.

* <TypeLink links={docs.links} type={docs.exports.isSameYear} /> – <span>{docs.exports.isSameYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameMonth} /> – <span>{docs.exports.isSameMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameDay} /> – <span>{docs.exports.isSameDay.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isToday} /> – <span>{docs.exports.isToday.description}</span>

```tsx
import {isSameMonth, IslamicUmalquraCalendar} from '@internationalized/date';

isSameMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(2021, 4, 30, 5, 15)); // true
isSameMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(2021, 8, 2, 5, 15)); // false
isSameMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(new IslamicUmalquraCalendar(), 1442, 9, 4, 5, 15)); // true
```

A similar set of functions is also available that does not convert between calendar systems and requires the calendars to be equal.

* <TypeLink links={docs.links} type={docs.exports.isEqualYear} /> – <span>{docs.exports.isEqualYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualMonth} /> – <span>{docs.exports.isEqualMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualDay} /> – <span>{docs.exports.isEqualDay.description}</span>

```tsx
import {isEqualMonth, IslamicUmalquraCalendar} from '@internationalized/date';

isEqualMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(2021, 4, 30, 5, 15)); // true
isEqualMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(2021, 8, 2, 5, 15)); // false
isEqualMonth(new CalendarDateTime(2021, 4, 16, 9, 45), new CalendarDateTime(new IslamicUmalquraCalendar(), 1442, 9, 4, 5, 15)); // false
```

### Start and end dates

The following functions can be used to find the start or end dates of a particular unit of time. These only affect the date components of a `CalendarDateTime`. The time fields are left unchanged.

* <TypeLink links={docs.links} type={docs.exports.startOfYear} /> – <span>{docs.exports.startOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfYear} /> – <span>{docs.exports.endOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfMonth} /> – <span>{docs.exports.startOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfMonth} /> – <span>{docs.exports.endOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfWeek} /> – <span>{docs.exports.startOfWeek.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfWeek} /> – <span>{docs.exports.endOfWeek.description}</span>


Note that `startOfWeek` and `endOfWeek` require a locale string to be provided. This is because the first day of the week changes depending on the locale. For example, in the United States, the first day of the week is on Sunday, but in France it is on Monday.

```tsx
import {startOfYear, startOfMonth, startOfWeek} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 3, 9, 45);

startOfYear(date); // 2022-01-01T09:45
startOfMonth(date); // 2022-02-01T09:45
startOfWeek(date, 'en-US'); // 2022-01-30T09:45
startOfWeek(date, 'fr-FR'); // 2022-01-31T09:45
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
startOfWeek(date, 'en-US', 'mon'); // 2022-01-31T09:45
```

### Day of week

The <TypeLink links={docs.links} type={docs.exports.getDayOfWeek} /> function returns the day of the week for the given date and locale. Days are numbered from zero to six, where zero is the first day of the week in the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getDayOfWeek} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 6, 8, 30); // a Sunday

getDayOfWeek(date, 'en-US'); // 0
getDayOfWeek(date, 'fr-FR'); // 6
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getDayOfWeek(date, 'en-US', 'mon'); // 6
```

### Weekdays and weekends

The <TypeLink links={docs.links} type={docs.exports.isWeekday} /> and <TypeLink links={docs.links} type={docs.exports.isWeekend} /> functions can be used to determine if a date is weekday or weekend respectively. This depends on the locale. For example, in the United States, weekends are Saturday and Sunday, but in Israel they are Friday and Saturday.

```tsx
import {isWeekday, isWeekend} from '@internationalized/date';

let date = new CalendarDateTime(2022, 2, 6, 8, 30); // a Sunday

isWeekday(date, 'en-US'); // false
isWeekday(date, 'he-IL'); // true

isWeekend(date, 'en-US'); // true
isWeekend(date, 'he-IL'); // false
```

### Weeks in month

The <TypeLink links={docs.links} type={docs.exports.getWeeksInMonth} /> function returns the number of weeks in the given month. This depends on the number of days in the month, what day of the week the month starts on, and the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getWeeksInMonth} from '@internationalized/date';

let date = new CalendarDateTime(2021, 1, 1, 8, 30);

getWeeksInMonth(date, 'en-US'); // 6
getWeeksInMonth(date, 'fr-FR'); // 5
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getWeeksInMonth(date, 'en-US', 'mon'); // 5
```

---

### Packages @Internationalized Date Docs DateFormatter (`packages/@internationalized/date/docs/DateFormatter.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [date, internationalization]
order: 10
---

# DateFormatter

<PageDescription>{docs.exports.DateFormatter.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DateFormatter']}
  sourceData={[]} />

## Introduction

`DateFormatter` is a wrapper around the native [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) API. It exposes the same API, but works around several browser bugs and provides polyfills for newer features. These are currently:

* A simple polyfill for the `formatRange` and `formatRangeToParts` methods for older browsers.
* A workaround for a bug involving the `hour12` option in [Chrome](https://bugs.chromium.org/p/chromium/issues/detail?id=1045791) and and the [ECMAScript spec](https://github.com/tc39/ecma402/issues/402).
* A workaround for a bug involving the `hourCycle` option in [Safari](https://bugs.webkit.org/show_bug.cgi?id=229313).

See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) for full details on how to use the API.

## Interface

<ClassAPI links={docs.links} class={docs.exports.DateFormatter} />

---

### Packages @Internationalized Date Docs Time (`packages/@internationalized/date/docs/Time.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [time, internationalization]
---

# Time

<PageDescription>{docs.exports.Time.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Time']}
  sourceData={[]} />

## Introduction

A `Time` object represents a clock time without any date components. If you need to refer to a time on a specific date, use a [CalendarDateTime](CalendarDateTime.html) or [ZonedDateTime](ZonedDateTime.html) instead.

A `Time` can be created using the constructor. This example creates a time that represents 9:45 AM.

```tsx
import {Time} from '@internationalized/date';

let time = new Time(9, 45);
```

You can also create a `Time` by parsing an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the <TypeLink links={docs.links} type={docs.exports.parseTime} /> function.

```tsx
import {parseTime} from '@internationalized/date';

let time = parseTime('09:45');
```

Once you have a `Time` object, you can read its properties, or manipulate it as described in the [Manipulating times](#manipulating-times) section below. You can also convert it to an ISO 8601 string, or another representation. See the [Conversion](#conversion) section below for details.

```tsx
let time = new Time(9, 45);
time.toString(); // '09:45:00'
```

## Interface

<ClassAPI links={docs.links} class={docs.exports.Time} />

## Manipulating times

### Adding and subtracting durations

A <TypeLink links={docs.links} type={docs.exports.TimeDuration} /> is an object that represents an amount of time, with fields such as `hours`, `minutes`, and `seconds`. The `add` and `subtract` methods of `Time` objects can be used to adjust the time by the given duration. These methods return a new time, and do not mutate the original.

```tsx
let time = new Time(9, 45);
time.add({hours: 1}); // 10:45:00
time.add({minutes: 1}); // 09:46:00
time.add({seconds: 1}); // 09:45:01
```

Adding or subtracting a duration that goes beyond the limits of a particular field will cause the time to be _balanced_. For example, adding one minute to `09:59` results in `10:00`.

### Parsing durations

The <TypeLink links={docs.links} type={docs.exports.parseDuration} /> function can be used to convert a [ISO 8601 duration string](https://en.wikipedia.org/wiki/ISO_8601#Durations) into a <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> object. The smallest time unit may include decimal values written with a comma or period, and negative values can be written by prefixing the entire string with a minus sign.

```tsx
parseDuration('PT20H35M15S')
// => {hours: 20, minutes: 35, seconds: 15}

parseDuration('-PT20H35M15S')
// =>  {hours: -20, minutes: -35, seconds: -15}

parseDuration('PT20H35M15,75S')
// => {hours: 20, minutes: 35, seconds: 15.75}
```

### Setting fields

`Time` objects are immutable, which means their properties cannot be set directly. Instead, use the `set` method, and pass the fields to be modified. This will return a new `Time` with the updated values.

```tsx
let time = new Time(9, 45);
time.set({hour: 12}); // 12:45
time.set({minute: 5}); // 9:05
```

Setting a field to a value that is outside the valid range will cause it to be _constrained_.

```tsx
let time = new Time(9, 45);
time.set({hour: 36}); // 23:45
time.set({minute: 75}); // 09:59
```

### Cycling fields

The `cycle` method allows incrementing or decrementing a single field. It is similar to the `add` and `subtract` methods, but when the value reaches the minimum or maximum, it wraps around rather than affecting other fields.

```tsx
let time = new Time(23, 59);
time.cycle('hour', 1); // 00:59
time.cycle('minute', 1); // 23:00

let time = new Time(0, 0);
time.cycle('hour', -1); // 23:00
time.cycle('minute', -1); // 00:59
```

The `round` option may also be passed, which causes the value to be rounded to increments of the given amount. For example, you could round the minute to increments of 15.

```tsx
let time = new Time(9, 22);

time.cycle('minute', 15); // 09:37
time.cycle('minute', 15, {round: true}); // 09:30

time.cycle('minute', -15); // 09:07
time.cycle('minute', -15, {round: true}); // 09:15
```

By default, the `hour` field is cycled within a 24 hour range. The `hourCycle` option can be set to `12` to use a 12 hour clock instead, which will preserve the AM/PM value when formatted.

```tsx
let time = new Time(11);
time.cycle('hour', 1); // 12:00
time.cycle('hour', 1, {hourCycle: 12}); // 00:00

let time = new Time(23);
time.cycle('hour', 1); // 00:00
time.cycle('hour', 1, {hourCycle: 12}); // 12:00
```

## Conversion

### To a string

`Time` objects can be converted to an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the `toString` method.

```tsx
let date = new Time(9, 45);
date.toString(); // '09:45:00'
```

### To a date and time

A `Time` can be combined with a [CalendarDate](CalendarDate.html) to produce a [CalendarDateTime](CalendarDateTime.html) object using the <TypeLink links={docs.links} type={docs.exports.toCalendarDateTime} /> function.

```tsx
import {toCalendarDateTime, CalendarDate} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
let time = new Time(8, 30);

toCalendarDateTime(date, time); // 2022-02-03T08:30:00
```

A <TypeLink links={docs.links} type={docs.exports.CalendarDateTime} /> represents a date with a time, but not in any specific time zone. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a <TypeLink links={docs.links} type={docs.exports.ZonedDateTime} />, which represents a date with a time in a specific time zone. Use this type to represent an exact moment in time at a particular location on Earth.

The <TypeLink links={docs.links} type={docs.exports.toZoned} /> function can be used to convert a `CalendarDateTime` to a `ZonedDateTime`.

```tsx
import {toZoned, toCalendarDateTime, CalendarDate} from '@internationalized/date';

let date = new CalendarDate(2022, 2, 3);
let time = new Time(8, 30);

let dateTime = toCalendarDateTime(date, time); // 2022-02-03T08:30:00
toZoned(dateTime, 'America/Los_Angeles'); // 2021-02-03T08:30-07:00[America/Los_Angeles]
```

## Queries

### Comparison

`Time` objects can be compared in order to determine which time is before or after another using the `compare` method. It returns a number less than zero if the first time is before the second, zero if the values are equal, or a number greater than zero if the first time is after the second.

```tsx
let a = new Time(9, 45);
let b = new Time(12, 20);

a.compare(b) < 0; // true
b.compare(a) > 0; // true
```

---

### Packages @Internationalized Date Docs ZonedDateTime (`packages/@internationalized/date/docs/ZonedDateTime.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/date';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/date/package.json';

---
category: Date and Time
keywords: [date, time, timezone, calendar, internationalization]
---

# ZonedDateTime

<PageDescription>{docs.exports.ZonedDateTime.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ZonedDateTime']}
  sourceData={[]} />

## Introduction

A `ZonedDateTime` object represents an exact date and time in a specific time zone, in a specific calendar system such as the Gregorian calendar. Use this type to represent an exact moment in time at a particular location on Earth.

A `ZonedDateTime` can be created using the constructor. This example creates a date that represents February 3rd, 2022 at 9:15 AM in the Gregorian calendar system, with a time zone of `"America/Los Angeles"`.

```tsx
import {ZonedDateTime} from '@internationalized/date';

let date = new ZonedDateTime(
  // Date
  2022, 2, 3,
  // Time zone and UTC offset
  'America/Los_Angeles', -28800000,
  // Time
  9, 15, 0
);
```

You can also create a `ZonedDateTime` by parsing an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the one of the following functions:

* <TypeLink links={docs.links} type={docs.exports.parseZonedDateTime} /> – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `"2021-11-07T00:45[America/Los_Angeles]"` or `"2021-11-07T00:45-07:00[America/Los_Angeles]"`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.
* <TypeLink links={docs.links} type={docs.exports.parseAbsolute} /> – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `"2021-11-07T07:45:00Z"`), or stored with a particular offset (e.g. `"2021-11-07T07:45:00-07:00"`). A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone.
* <TypeLink links={docs.links} type={docs.exports.parseAbsoluteToLocal} /> – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for `parseAbsolute`, and accepts the same formats.

```tsx
import {parseZonedDateTime} from '@internationalized/date';

let date = parseZonedDateTime('2022-11-07T00:45[America/Los_Angeles]');
let date = parseAbsolute('2021-11-07T07:45:00Z', 'America/Los_Angeles');
let date = parseAbsoluteToLocal('2021-11-07T07:45:00Z');
```

You can also create a `ZonedDateTime` using a `Date` object or epoch time (milliseconds) using one of the following functions:

* <TypeLink links={docs.links} type={docs.exports.fromDate} /> – This function creates a `ZonedDateTime` from a `Date` object. A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone.
* <TypeLink links={docs.links} type={docs.exports.fromDateToLocal} /> – This function creates a `ZonedDateTime` from a `Date` object. The time zone identifier is automatically resolved from the current user’s environment, and the result is converted into that local time zone.
* <TypeLink links={docs.links} type={docs.exports.fromAbsolute} /> – This function creates a `ZonedDateTime` from a Unix epoch (e.g. `1688023843144`, representing milliseconds since 1970). A time zone identifier, e.g. `America/Los_Angeles`, must be provided, and the result will be converted into that time zone.

```tsx
import {fromDate, fromDateToLocal, fromAbsolute} from '@internationalized/date';

let date = fromDate(new Date(), 'America/Los_Angeles');
let date = fromDateToLocal(new Date());
let date = fromAbsolute(1688023843144, 'America/Los_Angeles');
```


The current time can be retrieved using the <TypeLink links={docs.links} type={docs.exports.now} /> function. This requires a time zone identifier to be provided, which is used to determine the local time. The <TypeLink links={docs.links} type={docs.exports.getLocalTimeZone} /> function can be used to retrieve the user's current time zone.

**Note:** the local time zone is cached after the first call. You can reset it by calling <TypeLink links={docs.links} type={docs.exports.resetLocalTimeZone} />, or mock it in unit tests by calling <TypeLink links={docs.links} type={docs.exports.setLocalTimeZone} />.

```tsx
import {now, getLocalTimeZone} from '@internationalized/date';

let nyTime = now('America/New_York');
let localTime = now(getLocalTimeZone());
```

Once you have a `ZonedDateTime` object, you can read its properties, or manipulate it as described in the [Manipulating dates](#manipulating-dates) section below. You can also convert it to an ISO 8601 string, native JavaScript `Date` object, or another representation. See the [Conversion](#conversion) section below for details.

```tsx
let date = new ZonedDateTime(
  2022, 2, 3,
  'America/Los_Angeles', -28800000,
  12, 24, 45
);

date.toString(); // '2022-02-03T12:24:45-08:00[America/Los_Angeles]'
```

## Interface

<ClassAPI links={docs.links} class={docs.exports.ZonedDateTime} />

## Calendar systems

By default, `ZonedDateTime` uses the Gregorian calendar system, but many other calendar systems that are used around the world are supported, such as Hebrew, Indian, Islamic, Buddhist, Ethiopic, and more. A <TypeLink links={docs.links} type={docs.exports.Calendar} /> instance can be passed to the `ZonedDateTime` constructor to represent dates in that calendar system.

This example creates a date in the Buddhist calendar system, which is equivalent to April 30th, 2020 at 9:15 AM in the Gregorian calendar.

```tsx
import {BuddhistCalendar} from '@internationalized/date';

let date = new ZonedDateTime(
  new BuddhistCalendar(), 2563, 4, 30,
  'America/Los_Angeles', -28800000,
  9, 15
);
```

See the [Calendar](Calendar.html#implementations) docs for details about the supported calendars.

### Eras

Many calendar systems have only one era, or a modern era and a pre-modern era (e.g. AD and BC in the Gregorian calendar). However, other calendar systems may have many eras. For example, the Japanese calendar has eras for the reign of each Emperor. `ZonedDateTime` represents eras using string identifiers, which can be passed as an additional parameter to the constructor before the year. When eras are present, years are numbered starting from 1 within the era.

This example creates a date in the Japanese calendar system, which is equivalent to April 30th, 2019 at 9:15 AM in the Gregorian calendar.

```tsx
import {JapaneseCalendar} from '@internationalized/date';

let date = new ZonedDateTime(
  new JapaneseCalendar(), 'heisei', 31, 4, 30,
  'America/Los_Angeles', -28800000,
  9, 15
);
```

A list of valid era identifiers can be retrieved using the `getEras` method of a `Calendar` instance. If an era is not provided, the date is assumed to be in the current era.

### Converting between calendars

The <TypeLink links={docs.links} type={docs.exports.toCalendar} /> function can be used to convert a date from one calendar system to another.

This example converts a Gregorian date to a Hebrew one.

```tsx
import {toCalendar, HebrewCalendar} from '@internationalized/date';

let gregorianDate = new ZonedDateTime(
  2020, 9, 19,
  'America/Los_Angeles', -28800000,
  10, 30
);

let hebrewDate = toCalendar(gregorianDate, new HebrewCalendar());
```

## Manipulating dates

### Adding and subtracting durations

A <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> is an object that represents an amount of time, with fields such as `years`, `months`, `hours`, and `minutes`. The `add` and `subtract` methods of `ZonedDateTime` objects can be used to adjust the date by the given duration. These methods return a new date, and do not mutate the original.

```tsx
let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');

date.add({weeks: 1}); // 2022-02-10T09:45[America/Los_Angeles]
date.add({months: 1}); // 2022-03-03T09:45[America/Los_Angeles]
date.add({years: 1, months: 1, days: 1}); // 2023-03-04T09:45[America/Los_Angeles]
date.add({hours: 1}); // 2022-02-03T10:45[America/Los_Angeles]
date.add({minutes: 30}); // 2022-02-03T10:15[America/Los_Angeles]

date.subtract({weeks: 1}); // 2022-01-27T09:45[America/Los_Angeles]
date.subtract({months: 1}); // 2022-01-03T09:45[America/Los_Angeles]
date.subtract({years: 1, months: 1, days: 1}); // 2021-01-02T09:45[America/Los_Angeles]
date.subtract({hours: 1}); // 2022-02-03T8:45[America/Los_Angeles]
date.subtract({minutes: 30}); // 2022-02-03T09:15[America/Los_Angeles]
```

Adding or subtracting a duration that goes beyond the limits of a particular field will cause the date to be _balanced_. For example, adding one day to August 31st results in September 1st. In addition, if adding or subtracting one field causes another to be invalid, the date will be _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

Adding and subtracting is time zone aware. When adjusting a date around a daylight saving time transition, the hour may be adjusted accordingly. For example, in the United States, adding one hour during a "spring forward" transition skips the 2 AM hour, and adding an hour in a "fall back" transition repeats the 1 AM hour. Under the hood, the UTC offset is changing instead.

```tsx
// A "spring forward" transition
let date = parseZonedDateTime('2020-03-08T01:00-08:00[America/Los_Angeles]');
date.add({hours: 1}); // 2020-03-08T03:00-07:00[America/Los_Angeles]

// A "fall back" transition
let date = parseZonedDateTime('2020-11-01T01:00-07:00[America/Los_Angeles]');
date.add({hours: 1}); // 2020-11-01T01:00-08:00[America/Los_Angeles]
date.add({hours: 2}); // 2020-11-01T02:00-08:00[America/Los_Angeles]
```

In addition, when changing the date portion of a `ZonedDateTime` around a daylight saving time transition, the hour may change if it is invalid in the target date. For example, during a "spring forward" transition, the 2 AM hour is skipped.

```tsx
// A "spring forward" transition
let date = parseZonedDateTime('2020-03-07T02:00-08:00[America/Los_Angeles]');
date.add({days: 1}); // 2020-03-08T03:00-07:00[America/Los_Angeles]
```

### Parsing durations

The <TypeLink links={docs.links} type={docs.exports.parseDuration} /> function can be used to convert a [ISO 8601 duration string](https://en.wikipedia.org/wiki/ISO_8601#Durations) into a <TypeLink links={docs.links} type={docs.exports.DateTimeDuration} /> object. The smallest time unit may include decimal values written with a comma or period, and negative values can be written by prefixing the entire string with a minus sign.

```tsx
parseDuration('P3Y6M6W4DT12H30M5S');
// => {years: 3, months: 6, weeks: 6, days: 4, hours: 12, minutes: 30, seconds: 5}

parseDuration('-P3Y6M6W4DT12H30M5S');
// => {years: -3, months: -6, weeks: -6, days: -4, hours: -12, minutes: -30, seconds: -5}

parseDuration('P3Y6M6W4DT12H30M5.5S');
// => {years: 3, months: 6, weeks: 6, days: 4, hours: 12, minutes: 30, seconds: 5.5}
```

### Setting fields

`ZonedDateTime` objects are immutable, which means their properties cannot be set directly. Instead, use the `set` method, and pass the fields to be modified. This will return a new `ZonedDateTime` with the updated values.

```tsx
let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
date.set({day: 10}); // 2022-02-10T09:45[America/Los_Angeles]
date.set({month: 5}); // // 2022-05-03T09:45[America/Los_Angeles]
date.set({year: 2023, month: 10, day: 16}); // 2023-10-16T09:45[America/Los_Angeles]
date.set({hour: 18}); // 2022-02-03T18:45[America/Los_Angeles]
date.set({minute: 15}); // 2022-02-03T09:15[America/Los_Angeles]
```

Setting a field to a value that is outside the valid range will cause it to be _constrained_. For example, setting the day to a value that is greater than the number of days in the month, will result in the last day of the month.

```tsx
let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
date.set({day: 100}); // 2022-02-28T09:45[America/Los_Angeles]
date.set({month: 20}); // 2022-12-03T09:45[America/Los_Angeles]
date.set({hour: 30}); // 2022-02-03T23:45[America/Los_Angeles]
```

Setting fields is time zone aware. When setting fields around a daylight saving time transition, the UTC offset will be adjusted accordingly. For example, when changing the `day` field from before a daylight saving transition to after, the time remains the same but the UTC offset changes.

```tsx
let date = parseZonedDateTime('2020-03-01T10:00-08:00[America/Los_Angeles]');
date.set({day: 14}); // 2020-03-14T10:00-07:00[America/Los_Angeles]
```

In addition, some time values during daylight saving transitions may be _ambiguous_. For example, in the United States, the 2 AM hour is skipped in the spring, and the 1 AM hour occurs twice in the fall. When setting date fields, this ambiguity must be resolved to determine the exact time. By default, the later of the two possible times is chosen for "spring forward" transitions, and the earlier time is chosen for "fall back" transitions. This can be controlled by passing the `disambiguation` parameter to the `set` method.

* `'earlier'` – choose the earlier of the two possible times
* `'later'` – choose the later of the two possible times
* `'compatible'` (default) – choose the later of the two times during "spring forward" transitions, and the earlier time during "fall back" transitions.
* `'reject'` – throws an error when the time is ambiguous

```tsx
// A "spring forward" transition
let date = parseZonedDateTime('2020-03-01T02:00-08:00[America/Los_Angeles]');
date.set({day: 8}); // 2020-03-08T03:00:00-07:00[America/Los_Angeles]
date.set({day: 8}, 'earlier'); // 2020-03-08T01:00:00-08:00[America/Los_Angeles]
date.set({day: 8}, 'later'); // 2020-03-08T03:00:00-07:00[America/Los_Angeles]

// A "fall back" transition
let date = parseZonedDateTime('2020-10-01T01:00-07:00[America/Los_Angeles]');
date.set({month: 11}); // 2020-11-01T01:00:00-07:00[America/Los_Angeles]
date.set({month: 11}, 'earlier'); // 2020-11-01T01:00:00-07:00[America/Los_Angeles]
date.set({month: 11}, 'later'); // 2020-11-01T01:00:00-08:00[America/Los_Angeles]
```

### Cycling fields

The `cycle` method allows incrementing or decrementing a single field. It is similar to the `add` and `subtract` methods, but when the value reaches the minimum or maximum, it wraps around rather than affecting other fields.

```tsx
let date = parseZonedDateTime('2022-12-31T23:59[America/Los_Angeles]');
date.cycle('day', 1); // 2022-12-01T23:59[America/Los_Angeles]
date.cycle('month', 1); // 2022-01-31T23:59[America/Los_Angeles]
date.cycle('hour', 1); // 2022-12-31T00:59[America/Los_Angeles]
date.cycle('minute', 1); // 2022-12-31T23:00[America/Los_Angeles]

let date = parseZonedDateTime('2022-01-01T00:00[America/Los_Angeles]');
date.cycle('day', -1); // 2022-01-31T00:00[America/Los_Angeles]
date.cycle('month', -1); // 2022-12-01T00:00[America/Los_Angeles]
date.cycle('hour', -1); // 2022-01-01T23:00[America/Los_Angeles]
date.cycle('minute', -1); // 2022-01-01T00:59[America/Los_Angeles]
```

Note that if cycling a field causes another field to become invalid, the date is _constrained_. For example, adding one month to August 31st results in September 30th because September 31st does not exist.

The `round` option may also be passed, which causes the value to be rounded to increments of the given amount. For example, you could round the minute to increments of 15.

```tsx
let date = parseZonedDateTime('2022-02-03T09:22[America/Los_Angeles]');

date.cycle('minute', 15); // 2022-02-03T09:37:00-08:00[America/Los_Angeles]
date.cycle('minute', 15, {round: true}); // 2022-02-03T09:30:00-08:00[America/Los_Angeles]

date.cycle('minute', -15); // 2022-02-03T09:07:00-08:00[America/Los_Angeles]
date.cycle('minute', -15, {round: true}); // 2022-02-03T09:15:00-08:00[America/Los_Angeles]
```

By default, the `hour` field is cycled within a 24 hour range. The `hourCycle` option can be set to `12` to use a 12 hour clock instead, which will preserve the AM/PM value when formatted.

```tsx
let date = parseZonedDateTime('2022-02-03T11:00[America/Los_Angeles]');
date.cycle('hour', 1); // 2022-02-03T12:00[America/Los_Angeles]
date.cycle('hour', 1, {hourCycle: 12}); // 2022-02-03T00:00[America/Los_Angeles]

let date = parseZonedDateTime('2022-02-03T23:00[America/Los_Angeles]');
date.cycle('hour', 1); // 2022-02-03T00:00[America/Los_Angeles]
date.cycle('hour', 1, {hourCycle: 12}); // 2022-02-03T12:00[America/Los_Angeles]
```

Cycling fields is time zone aware. When adjusting a date around a daylight saving time transition, the hour may be adjusted accordingly. For example, in the United States, adding one hour during a "spring forward" transition skips the 2 AM hour, and adding an hour in a "fall back" transition repeats the 1 AM hour. Under the hood, the UTC offset is changing instead.

```tsx
// A "spring forward" transition
let date = parseZonedDateTime('2020-03-08T01:00-08:00[America/Los_Angeles]');
date.cycle('hour', 1); // 2020-03-08T03:00-07:00[America/Los_Angeles]

// A "fall back" transition
let date = parseZonedDateTime('2020-11-01T01:00-07:00[America/Los_Angeles]');
date.cycle('hour', 1); // 2020-11-01T01:00-08:00[America/Los_Angeles]
```

In addition, when changing the date portion of a `ZonedDateTime` around a daylight saving time transition, the hour may change if it is invalid in the target date. For example, during a "spring forward" transition, the 2 AM hour is skipped.

```tsx
// A "spring forward" transition
let date = parseZonedDateTime('2020-03-07T02:00-08:00[America/Los_Angeles]');
date.cycle('day', 1); // 2020-03-08T03:00-07:00[America/Los_Angeles]
```

## Conversion

### To a string

`ZonedDateTime` objects can be converted to an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string using the `toString` method. This format preserves the maximum amount of information, including the UTC offset and time zone identifier, in the same format used in other languages like Java.

```tsx
let date = new ZonedDateTime(
  2022, 2, 3,
  'America/Los_Angeles', -28800000,
  12, 24, 45
);

date.toString(); // '2022-02-03T12:24:45-08:00[America/Los_Angeles]'
```

If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.

You can also use the `toAbsoluteString` method to convert the date to a UTC string. Use this format if the exact time no matter the time zone is needed.

```tsx
date.toAbsoluteString(); // '2022-02-03T20:24:45.000Z'
```

### To a native Date object

A `ZonedDateTime` can be converted to a native JavaScript `Date` object using the `toDate` method. In general, the `Date` object should be avoided because it has many internationalization issues and other flaws. However, it is necessary to use some functionality like date formatting.

```tsx
let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
date.toDate('America/Los_Angeles'); // Thu Feb 03 2022 09:45:00 GMT-0800 (Pacific Standard Time)
```

### To a date or time only

A `ZonedDateTime` can be converted to a [CalendarDate](CalendarDate.html) or [Time](Time.html) object if only one of these components is needed.

Use the <TypeLink links={docs.links} type={docs.exports.toCalendarDate} /> function to convert a `ZonedDateTime` to a `CalendarDate`.

```tsx
import {toCalendarDate} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
toCalendarDate(date); // 2022-02-03
```

Use the <TypeLink links={docs.links} type={docs.exports.toTime} /> function to convert a `ZonedDateTime` to a `Time`.

```tsx
import {toTime} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
toTime(date); // 09:45
```

### To a date and time without a time zone

A `ZonedDateTime` can be converted to a [CalendarDateTime](CalendarDateTime.html), which represents a date and time that is not in any specific time zone. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a `ZonedDateTime`.

Use the <TypeLink links={docs.links} type={docs.exports.toCalendarDateTime} /> function to convert a `ZonedDateTime` to a `CalendarDateTime`.

```tsx
import {toCalendarDateTime} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
toCalendarDateTime(date); // 2022-02-03T09:45:00
```

### Between time zones

A `ZonedDateTime` can be converted to a different time zone using the <TypeLink links={docs.links} type={docs.exports.toTimeZone} /> function. The <TypeLink links={docs.links} type={docs.exports.toLocalTimeZone} /> function can also be used to convert to the current user's local time zone.

```tsx
import {toTimeZone, toLocalTimeZone} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
toTimeZone(date, 'America/Chicago'); // 2022-02-03T11:45[America/Chicago]
toLocalTimeZone(date); // e.g. 2022-02-03T12:45[America/New_York]
```

## Queries

### Comparison

`ZonedDateTime` objects can be compared either for full or partial equality, or in order to determine which date is before or after another.

The `compare` method can be used to determine if a date is before or after another. It returns a number less than zero if the first date is before the second, zero if the values are equal, or a number greater than zero if the first date is after the second.

```tsx
let a = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');
let b = parseZonedDateTime('2022-03-04T09:45[America/Los_Angeles]');

a.compare(b) < 0; // true
b.compare(a) > 0; // true
```

In addition, the following functions can be used to perform a partial comparison. These functions accept dates in different calendar systems, and the second date is converted to the calendar system of the first date before comparison.

* <TypeLink links={docs.links} type={docs.exports.isSameYear} /> – <span>{docs.exports.isSameYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameMonth} /> – <span>{docs.exports.isSameMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isSameDay} /> – <span>{docs.exports.isSameDay.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isToday} /> – <span>{docs.exports.isToday.description}</span>

```tsx
import {isSameMonth} from '@internationalized/date';

isSameMonth(
  parseZonedDateTime('2022-04-16T09:45[America/Los_Angeles]'),
  parseZonedDateTime('2022-04-30T05:15[America/Los_Angeles]'),
); // true

isSameMonth(
  parseZonedDateTime('2022-04-16T09:45[America/Los_Angeles]'),
  parseZonedDateTime('2022-08-020T05:15[America/Los_Angeles]'),
); // false
```

A similar set of functions is also available that does not convert between calendar systems and requires the calendars to be equal.

* <TypeLink links={docs.links} type={docs.exports.isEqualYear} /> – <span>{docs.exports.isEqualYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualMonth} /> – <span>{docs.exports.isEqualMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.isEqualDay} /> – <span>{docs.exports.isEqualDay.description}</span>

### Start and end dates

The following functions can be used to find the start or end dates of a particular unit of time. These only affect the date components of a `ZonedDateTime`. The time fields are left unchanged.

* <TypeLink links={docs.links} type={docs.exports.startOfYear} /> – <span>{docs.exports.startOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfYear} /> – <span>{docs.exports.endOfYear.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfMonth} /> – <span>{docs.exports.startOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfMonth} /> – <span>{docs.exports.endOfMonth.description}</span>
* <TypeLink links={docs.links} type={docs.exports.startOfWeek} /> – <span>{docs.exports.startOfWeek.description}</span>
* <TypeLink links={docs.links} type={docs.exports.endOfWeek} /> – <span>{docs.exports.endOfWeek.description}</span>


Note that `startOfWeek` and `endOfWeek` require a locale string to be provided. This is because the first day of the week changes depending on the locale. For example, in the United States, the first day of the week is on Sunday, but in France it is on Monday.

```tsx
import {startOfYear, startOfMonth, startOfWeek} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-03T09:45[America/Los_Angeles]');

startOfYear(date); // 2022-01-01T09:45[America/Los_Angeles]
startOfMonth(date); // 2022-02-01T09:45[America/Los_Angeles]
startOfWeek(date, 'en-US'); // 2022-01-30T09:45[America/Los_Angeles]
startOfWeek(date, 'fr-FR'); // 2022-01-31T09:45[America/Los_Angeles]
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
startOfWeek(date, 'en-US', 'mon'); // 2022-01-31T09:45[America/Los_Angeles]
```

### Day of week

The <TypeLink links={docs.links} type={docs.exports.getDayOfWeek} /> function returns the day of the week for the given date and locale. Days are numbered from zero to six, where zero is the first day of the week in the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getDayOfWeek} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-06T08:30[America/Los_Angeles]'); // a Sunday

getDayOfWeek(date, 'en-US'); // 0
getDayOfWeek(locale, 'fr-FR'); // 6
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getDayOfWeek(date, 'en-US', 'mon'); // 6
```

### Weekdays and weekends

The <TypeLink links={docs.links} type={docs.exports.isWeekday} /> and <TypeLink links={docs.links} type={docs.exports.isWeekend} /> functions can be used to determine if a date is weekday or weekend respectively. This depends on the locale. For example, in the United States, weekends are Saturday and Sunday, but in Israel they are Friday and Saturday.

```tsx
import {isWeekday, isWeekend} from '@internationalized/date';

let date = parseZonedDateTime('2022-02-06T08:30[America/Los_Angeles]'); // a Sunday

isWeekday(date, 'en-US'); // false
isWeekday(date, 'he-IL'); // true

isWeekend(date, 'en-US'); // true
isWeekend(date, 'he-IL'); // false
```

### Weeks in month

The <TypeLink links={docs.links} type={docs.exports.getWeeksInMonth} /> function returns the number of weeks in the given month. This depends on the number of days in the month, what day of the week the month starts on, and the given locale. For example, in the United States, the first day of the week is Sunday, but in France it is Monday.

```tsx
import {getWeeksInMonth} from '@internationalized/date';

let date = parseZonedDateTime('2023-01-01T08:30[America/Los_Angeles]');

getWeeksInMonth(date, 'en-US'); // 5
getWeeksInMonth(date, 'fr-FR'); // 6
```

You can also provide an optional `firstDayOfWeek` argument to override the default first day of the week determined by the locale. It accepts a week day abbreviation, e.g. `sun`, `mon`, `tue`, etc.

```tsx
getWeeksInMonth(date, 'en-US', 'mon'); // 6
```

---

### Packages @Internationalized Number Docs NumberFormatter (`packages/@internationalized/number/docs/NumberFormatter.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/number';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/number/package.json';

---
category: Numbers
keywords: [number, internationalization]
order: 2
---

# NumberFormatter

<PageDescription>{docs.exports.NumberFormatter.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['NumberFormatter']}
  sourceData={[]} />

## Introduction

`NumberFormatter` is a wrapper around the native [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) API. It exposes the same API, but works around several browser bugs.

See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) for full details on how to use the API.

## Interface

<ClassAPI links={docs.links} class={docs.exports.NumberFormatter} />

---

### Packages @Internationalized Number Docs NumberParser (`packages/@internationalized/number/docs/NumberParser.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@internationalized/number';
import {HeaderInfo, FunctionAPI, ClassAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@internationalized/number/package.json';

---
category: Numbers
keywords: [number, parser, internationalization]
order: 1
---

# NumberParser

<PageDescription>{docs.exports.NumberParser.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['NumberParser']}
  sourceData={[]} />

## Introduction

Numbers can be formatted in many different ways, including percentages, units, decimals, currencies, and more. In addition, number formatting varies around the world. For example, currency symbols, units, decimal separators, and even digits themselves may be different across languages and regions. While Latin numerals are the most commonly used, many other numbering systems are also used around the world. For example, in the Latin numbering system, the number twelve is represented as “12”, and in the Arabic decimal system, it is “١٢”.

`NumberParser` is designed to validate and parse numbers from user input according to a specific locale and format. It supports several different numbering systems including the Latin, Arabic, and Han positional numbering systems, as well as parsing decimals, percentages, currencies, and unit values. The numbering system is automatically detected from the input string. This means that users may input numbers in a different numbering system than the default for their locale, e.g. a Latin number in an Arabic locale.

Parsing numbers while taking into account all locale-specific detail is quite complex and error-prone. `NumberParser` uses information about the locale and expected format for a number in order to parse it correctly. This means it is somewhat strict about the accepted formats. It is not designed to handle use cases where the user can enter numbers in an unknown format (e.g. either a unit value _or_ a percentage), this must be known up front or selected via an external UI control.

Read our [blog post](../../blog/how-we-internationalized-our-numberfield.html) for more details on how the number parser is implemented.

### Example

To create a `NumberParser`, call the constructor with a locale string and optional format options. The same options as supported by the [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) object are supported. See the docs on MDN linked above for full details.

This example creates a parser than accepts values in inches in the `en-US` locale.

```tsx
import {NumberParser} from '@internationalized/number';

let parser = new NumberParser('en-US', {style: 'unit', unit: 'inch'});
parser.parse('10 in'); // 10
```

## Interface

<ClassAPI links={docs.links} class={docs.exports.NumberParser} />

## Parsing

Numbers can be parsed using the `parse` method. If the input is not a valid number according to the locale and format options, `NaN` is returned instead.

### Decimals

By default, or with the `style: 'decimal'` option, `NumberParser` supports parsing decimal values.

```tsx
let parser = new NumberParser('en-US');
parser.parse('10.5'); // 10.5
parser.parse('-25.6'); // -25.6
parser.parse('1,000,000'); // 1000000
parser.parse('١٢'); // 12
parser.parse('X'); // NaN
```

### Percentages

The `style: 'percent'` option can be provided to the constructor to parse percentage values. In this mode, parsed values are divided by 100, for example the string `"45%"` is parsed as `0.45`. The `maximumFractionDigits` option is also taken into account during parsing, and the resulting value is rounded accordingly.

```tsx
let parser = new NumberParser('en-US', {
  style: 'percent',
  maximumFractionDigits: 2
});

parser.parse('45%'); // 0.45
parser.parse('62.3333%'); // 0.6233
```

### Currency values

The `style: 'currency'` option can be provided to the constructor to parse currency values. The `currency` option must also be passed to set the currency code (e.g. `USD`) to use. In addition, the `currencyDisplay` option can be used to choose whether to display the currency symbol, currency code, or currency name. Finally, the `currencySign` option can be set to `accounting` to use accounting notation for negative numbers, which uses parentheses rather than a minus sign in some locales.

Note that partial input is not accepted by this method. For example, if a partial currency symbol is included in the string, `NaN` will be returned. The `isValidPartialNumber` method, described below, can be used in scenarios where you have partial user input.

```tsx
let parser = new NumberParser('en-US', {
  style: 'currency',
  currency: 'EUR',
  currencyDisplay: 'code',
  currencySign: 'accounting'
});

parser.parse('45'); // 45
parser.parse('EUR 45'); // 45
parser.parse('EUR 26.45'); // 26.45
parser.parse('EUR -25'); // -25
parser.parse('(EUR 25)'); // -25
parser.parse('EU 45'); // NaN (partial currency symbol)
parser.parse('$45'); // NaN (different currency symbol)
```

### Unit values

The `style: 'unit'` option can be passed to the constructor to parse values with a unit of measurement. The `unit` option must also be passed to set which unit to use (e.g. `inch`). In addition, the `unitDisplay` option can be used to choose whether the unit is accepted in long, short, or narrow format.

```tsx
let parser = new NumberParser('en-US', {
  style: 'unit',
  unit: 'inch',
  unitDisplay: 'long'
});

parser.parse('12'); // 12
parser.parse('12 inches'); // 12
parser.parse('1 inch'); // 1
parser.parse('12 in'); // NaN (partial unit)
parser.parse('23 ft'); // NaN (different unit)
```

## Validation

`NumberParser` can also be used to validate partial user input using the `isValidPartialNumber` method, for example, as the user types into an input field. The `parse` method only accepts complete input, whereas `isValidPartialNumber` determines if the given input _might_ be valid but incomplete. For example, only entering a decimal point is invalid when passed to `parse`, but accepted by `isValidPartialNumber`.

Note that partial units and currency symbols are _not_ accepted. Since the unit itself must be known upfront and passed to the constructor, it is better to only allow entering a number rather and autocompleting the unit rather than typing it in one letter at a time.

```tsx
let parser = new NumberParser('en-US', {style: 'unit', unit: 'inch'});
parser.isValidPartialNumber('.'); // true
parser.isValidPartialNumber('.2'); // true
parser.isValidPartialNumber('10 in'); // true
parser.isValidPartialNumber('10 i'); // false
parser.isValidPartialNumber('10 x'); // false
```

## Detecting the numbering system

Under the hood, `NumberParser` automatically detects the numbering system used in the input. This is also exposed by the `getNumberingSystem` method, which returns a Unicode script identifier. For example, this can be used to create a number formatter based on the numbering system used in the input.

```tsx
import {NumberParser, NumberFormatter} from '@internationalized/number';

let parser = new NumberParser('en-US', {style: 'decimal'});
let numberingSystem = parser.getNumberingSystem('١٢'); // -> 'arab'

let formatter = new NumberFormatter('en-US', {style: 'decimal', numberingSystem});
formatter.format(12); // '١٢'
```

---

### Packages Dev Docs Pages Architecture (`packages/dev/docs/pages/architecture.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Flex} from '@react-spectrum/layout';
import {View} from '@react-spectrum/view';
import style from '@react-spectrum/docs/src/docs.css';
import {Layout} from '@react-spectrum/docs';
export default Layout;

---
category: Foundation
keywords: [react stately, react aria, react spectrum, hooks, react, spectrum]
---

# Architecture

This page discusses the architecture of React Spectrum, and how
behavior and core logic for many common components can be shared
between design systems and across platforms.

## Introduction

Today, many companies are implementing their own component libraries for their
design systems from scratch. On the web, the primitives are very low level.
There are very few built-in browser controls that are fully styleable, so
each company needs to reimplement many of the same components from scratch.
This has become easier to do with React and other modern view libraries, but
implementing full support for accessibility, internationalization, keyboard,
mouse, and touch interactions, and other features is still extraordinarily
difficult.

In addition, JavaScript has spread beyond only the web platform. Platforms
like React Native allow React to render native widgets across mobile
and desktop operating systems as well. This will continue to expand in the
future as new platforms and interaction models are developed.

While each design system is unique, there is often more in common between
components than different. Most components typically found in a design
system, like buttons, checkboxes, selects, and even
tables, usually have very similar behavior and logic. There are even
specifications that describe how many of the most common components should
behave in terms of [accessibility semantics](https://www.w3.org/TR/wai-aria-1.2/)
and [keyboard interactions](https://www.w3.org/TR/wai-aria-practices-1.2/).
The main difference between design systems is the styling.

This opens up to the possibility of sharing much of the behavior and
component logic between design systems and across platforms. For example,
user interactions, accessibility, internationalization, and behavior
can be reused, while allowing custom styling and rendering to live
within individual design systems. This has the potential to improve
the overall quality of applications, while saving companies money
and time, and reducing duplicated effort across the industry.

## Architecture

<figure className={style.float}>
  <Flex direction="column" gap="size-125">
    <View backgroundColor="static-magenta-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>Component</span>
      </Flex>
    </View>
    <View backgroundColor="static-green-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>Behavior Hook</span>
      </Flex>
    </View>
    <View backgroundColor="static-blue-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>State Hook</span>
      </Flex>
    </View>
  </Flex>
</figure>

In order to allow reusing component behavior between design systems,
React Spectrum splits each component into three parts: state, behavior,
and the rendered component.

Some components don't have all of these pieces. For example, some simple
components do not require any state, and others are only compositions of
other components, so each component has the pieces of this architecture
that make sense for their purpose.

This architecture is made possible by
[React Hooks](https://react.dev/reference/react/hooks), which enable
the ability to reuse behavior between multiple components. Hooks allow
accessing React features like state and effects from functions which
can be called from any component. If you're unfamiliar with hooks,
we recommend reading the documentation linked above first.

### State hook

At the bottom is the state hook. This hook is shared across platforms —
it could work on the web, react-native, or any other platform, and makes
no assumptions about the view system it is running on. It also has no
theme or design system specific logic.

The state hook accepts common props from the component and provides
state management. It implements the core logic for the component and
returns an interface for reading and updating the component state.

Not all components have a state hook. For example, many components are
read-only — they display something to the user but don't allow them
to change it. State hooks are found in interactive components that allow
data entry, or have some kind of visual state that the user can update
(e.g. expanding/collapsing).

### Behavior hook

In the middle is the behavior hook. This hook is platform specific, and
depends on the platform API (e.g. the DOM or react-native). It also has
no theme or design system specific logic. It implements event
handling, accessibility, internationalization, etc. — all the parts of a
component that could be shared across multiple design systems.

The behavior hook uses the state hook in order to implement component behavior.
It returns one or more sets of platform specific props (e.g. DOM props) that
can be spread onto the elements rendered by the component. These include
semantic properties like [ARIA](https://www.w3.org/TR/wai-aria-1.2/), and
event handlers. The event handlers in turn call methods on
the state interface to implement the behavior for the component.

Some components may not have any user interactions, but still have a behavior
hook. Most components have some kind of semantics that they need to expose
for accessibility (a form of behavior). The only components that won't have
a behavior hook of their own are those that only compose together other
components.

### Component

At the top is the component, which lives in each design system and composes
all of these pieces together. It provides the theme and design system specific
logic, and renders the actual platform elements. It applies styles, which could
be implemented in many different ways (e.g. CSS classes, CSS-in-JS, etc.).

The component uses props returned by the behavior hook and state from the state
hook to implement the visual appearance. It spreads props returned from the behavior
hook onto elements that it renders to apply semantics and interactions, and can use
the state from the state hook to adjust its visual appearance.
This allows complete control over the rendering of the component, including
things like adding extra elements as needed for styling or layout control.

The component itself may be split into unstyled and styled parts. Unstyled components
compose together hooks and abstract away the glue code necessary to connect them together
by providing reusable contexts, DOM structure, and styling APIs. This simplifies design system
components while retaining the flexibility to drop down to lower-level APIs when needed.

<div style={{clear: 'both'}} />

## Implementation

<figure className={style.float}>
  <Flex direction="column" gap="size-125">
    <View backgroundColor="static-magenta-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>React Spectrum</span>
      </Flex>
    </View>
    <View backgroundColor="static-green-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>React Aria</span>
      </Flex>
    </View>
    <View backgroundColor="static-blue-600" height="size-900">
      <Flex alignItems="center" justifyContent="center" height="100%">
        <span style={{color: 'white', fontSize: 18}}>React Stately</span>
      </Flex>
    </View>
  </Flex>
</figure>

Our implementation of this architecture splits each piece into three npm
scopes, with individually versioned packages for each component. This
allows you **incrementally adopt** this approach in your own design system
and reuse as much or as little as makes sense for your usecases.

Within a component, the hooks are designed to be **highly composable**,
with individual features split into many hooks. This allows you to combine
them together and achieve your design with only the features you need in
your design system.

The overall goal for the project is to make reusing behavior across design
systems as easy as possible, while allowing full design customizability
and avoiding code bloat.

<div style={{clear: 'both'}} />

### React Stately

[React Stately](react-stately/index.html) implements state management and
core logic for each component. It handles complex logic for things
like [collections](react-stately/collections.html) and [selection](react-stately/selection.html)
in a fully cross-platform way that you could reuse on the web, in
react-native, etc.

React Stately hooks can be used independently in your own components,
or paired with React Aria hooks to get more of the behavior and user
interactions for web applications out of the box. We do not yet have
behavior hooks for other platforms however, so if you're working in
react-native or another view system, you'll need to use React Stately
directly.

Read more about React Stately and [get started](react-stately/getting-started.html)
by reading the docs.

### React Aria

[React Aria](react-aria/index.html) implements behavior and [accessibility](react-aria/accessibility.html)
for the web according to the W3C's [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/).
It includes full screen reader and keyboard navigation support, along with
mouse and touch [interactions](react-aria/interactions.html) that have been
tested across a wide variety of devices and browsers. It also implements
[internationalization](react-aria/internationalization.html) for over 30
languages, including right-to-left specific behavior, localized date and
number formatting, and more.

Most importantly, React Aria is **fully customizable**. It offers both high-level
unstyled components and low-level hooks depending on the level of customization you need.
The components provide a default DOM structure and styling API, and handle all
of the glue code necessary to connect the hooks together on your behalf.
If you need even more control, you can drop down to the lower-level hook-based API,
which enables [advanced customization](react-aria/advanced.html) use cases such
as overriding DOM elements, intercepting events, customizing behavior, and more.

[Read more](react-aria/why.html) about React Aria and
the problems it solves, and check out the docs to [get started](react-aria/getting-started.html)
building your own design system.

### React Spectrum

[React Spectrum](react-spectrum/index.html) puts all of these pieces together
and implements the Adobe-specific styling. It's designed to be adaptive, and
works across mouse, touch, and keyboard interactions, on devices of any screen
size. It supports [theming](react-spectrum/theming.html), including automatic
support for dark mode and responsive scaling for large hit targets on touch
devices.

If you're integrating with Adobe software, React Spectrum is a great way to
make your UI consistent. It's also a really great example of how to use
React Aria and React Stately to build a full design system, so if you're
developing your own component library, you can check out the
[source code](https://github.com/adobe/react-spectrum) for
inspiration.

[Get started](react-spectrum/getting-started.html) building an application
with React Spectrum, and read the docs for each component to learn more.

## Learn more

The following talk from React Europe discusses how this project came to be, its architecture, high quality
cross-device interactions, and how we can share behavior between design systems.

<div className={style.responsiveVideo}>
  <iframe
    title="YouTube embedded video: Design system and accessibility - Devon Govett aka @devongovett at @ReactEurope 2020"
    width="840"
    height="471"
    src="https://www.youtube.com/embed/dxDcBB7Xoxs"
    frameBorder="0"
    allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
    allowFullScreen />
</div>

---

### Packages Dev Docs Pages Contribute (`packages/dev/docs/pages/contribute.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
import Contributing from '../../../../CONTRIBUTING.md';
export default Layout;

---
category: Foundation
title: Contribute
description: How to contribute features, report bugs, or make suggestions to improve React Spectrum.
keywords: [react spectrum contributions, bug reports, feature requests]
---

<Contributing />

---

### Packages Dev Docs Pages Error (`packages/dev/docs/pages/error.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import {Content} from '@react-spectrum/view';
import {Flex} from '@react-spectrum/layout';
import {Heading} from '@react-spectrum/text';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';

---
title: Page not found
---

<Flex alignItems="center" direction="row" height="50vh" justifyContent="center">
  <IllustratedMessage>
    <NotFound />
    <Heading>Error 404: Page not found</Heading>
    <Content>This page isn't available. Try checking the URL or visit a different page.</Content>
  </IllustratedMessage>
</Flex>

---

### Packages Dev Docs Src Template (`packages/dev/docs/src/template.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/COMPONENT_NAME';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/COMPONENT_NAME/package.json';

```jsx import
import {Component} from '@react-spectrum/COMPONENT_NAME';
```

---
category: Categoryname
keywords: []
---

# Component Name

<PageDescription>{docs.exports.Component.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Component']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/web/rsp/components/button'}
  ]} />

## Example

```tsx example
<Button variant="accent">Button</Button>
```

## Content

*If the component has a children prop that accepts any type of content (e.g. `ReactNode`), include this section. Please include a note about how to internationalize the content.*

## Value

*If the component displays or allows a user to input a value, include this section.*

## Labeling

*If the component supports a label prop, include this section. Please include a note about how to internationalize the content.*

## Events

*If the component supports event props, include this section. Only cover the events that are important to the main functionality of the component.*

## Validation

*If the component supports validation props, include this section.*

## Props

<PropTable component={docs.exports.Component} links={docs.links} />

## Visual options

*Show examples of all variants and visual props here with links to the design website for more usage details. Examples can be grouped together for conciseness.*

### Sample Option
[View guidelines](https://spectrum.adobe.com/web/rsp/components/button#component-options)

---

### Packages @Adobe React Spectrum Docs Accordion Accordion (`packages/@adobe/react-spectrum/docs/accordion/Accordion.mdx`)

{/* Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/accordion';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/accordion/package.json';

---
category: Navigation
keywords: [disclosure, accordion, collapse, expand]
---

```jsx import
import {Accordion, Disclosure, DisclosureTitle, DisclosurePanel} from '@react-spectrum/accordion';
```

# Accordion

<PageDescription>{docs.exports.Accordion.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Accordion', 'Disclosure', 'DisclosureTitle', 'DisclosurePanel']}
  since="3.38.0" />

## Example

```tsx example
<Accordion defaultExpandedKeys={['personal']}>
  <Disclosure id="personal">
    <DisclosureTitle>Personal Information</DisclosureTitle>
    <DisclosurePanel>
      Personal information form here.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="billing">
    <DisclosureTitle>Billing Address</DisclosureTitle>
    <DisclosurePanel>
      Billing address form here.
    </DisclosurePanel>
  </Disclosure>
</Accordion>
```


## Content

Accordion accepts multiple [Disclosure](Disclosure.html) elements as children. Each disclosure accepts an `id` prop which is passed to the `onExpandedChange` handler to identify the expanded disclosure within the accordion. See the [Events](#events) section for more details about expansion.

### Internationalization
In order to internationalize an Accordion, all text content within the accordion should be localized.

## Events

Accordion accepts an `onExpandedChange` prop which is triggered when a disclosure is expanded or collapsed. The example below uses `onExpandedChange` to programmatically control disclosure expansion.

```tsx example
import {Key} from "@react-types/shared";

function ControlledExpansion() {
  let [expandedKeys, setExpandedKeys] = React.useState<Set<Key>>(new Set(['personal']))

  return (
    <>
      <Accordion expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
        <Disclosure id="personal">
          <DisclosureTitle>Personal Information</DisclosureTitle>
          <DisclosurePanel>
            Personal information form here.
          </DisclosurePanel>
        </Disclosure>
        <Disclosure id="billing">
          <DisclosureTitle>Billing Address</DisclosureTitle>
          <DisclosurePanel>
            Billing address form here.
          </DisclosurePanel>
        </Disclosure>
      </Accordion>
      <div style={{marginTop: '20px'}}>You have expanded: {expandedKeys}</div>
    </>
  )
}
```

## Expanded

By default, only one disclosure will be expanded at a time. To expand multiple disclosures, apply the `allowsMultipleExpanded` prop to Accordion.

```tsx example
<Accordion allowsMultipleExpanded defaultExpandedKeys={['personal', 'billing']}>
  <Disclosure id="personal">
    <DisclosureTitle>Personal Information</DisclosureTitle>
    <DisclosurePanel>
      Personal information form here.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="billing">
    <DisclosureTitle>Billing Address</DisclosureTitle>
    <DisclosurePanel>
      Billing address form here.
    </DisclosurePanel>
  </Disclosure>
</Accordion>
```
## Props

### Accordion

<PropTable component={docs.exports.Accordion} links={docs.links} />

### Disclosure

<PropTable component={docs.exports.Disclosure} links={docs.links} />

### Disclosure Title

<PropTable component={docs.exports.DisclosureTitle} links={docs.links} />

### Disclosure Panel

<PropTable component={docs.exports.DisclosurePanel} links={docs.links} />

## Visual Options

### Disabled

```tsx example
<Accordion isDisabled>
  <Disclosure id="personal">
    <DisclosureTitle>Personal Information</DisclosureTitle>
    <DisclosurePanel>
      Personal information form here.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="billing">
    <DisclosureTitle>Billing Address</DisclosureTitle>
    <DisclosurePanel>
      Billing address form here.
    </DisclosurePanel>
  </Disclosure>
</Accordion>
```

### Quiet

```tsx example
<Accordion isQuiet>
  <Disclosure id="personal">
    <DisclosureTitle>Personal Information</DisclosureTitle>
    <DisclosurePanel>
      Personal information form here.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="billing">
    <DisclosureTitle>Billing Address</DisclosureTitle>
    <DisclosurePanel>
      Billing address form here.
    </DisclosurePanel>
  </Disclosure>
</Accordion>
```

---

### Packages @Adobe React Spectrum Docs Accordion Disclosure (`packages/@adobe/react-spectrum/docs/accordion/Disclosure.mdx`)

{/* Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/accordion';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/accordion/package.json';

---
category: Navigation
keywords: [disclosure, accordion, collapse, expand]
---

```jsx import
import {Disclosure, DisclosureTitle, DisclosurePanel} from '@react-spectrum/accordion';
```

# Disclosure

<PageDescription>{docs.exports.Disclosure.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Disclosure', 'DisclosureTitle', 'DisclosurePanel']}
  since="3.38.0" />

## Example

```tsx example
<Disclosure>
  <DisclosureTitle>System Requirements</DisclosureTitle>
  <DisclosurePanel>
    Details about system requirements here.
  </DisclosurePanel>
</Disclosure>
```

## Content

Disclosure follows the [ARIA Disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) and consists of two children: `DisclosureTitle` and `DisclosurePanel`. The `DisclosureTitle` controls the expansion of the `DisclosurePanel` and the contents inside.

Disclosure can be used as a standalone collapsible section of content. However, multiple discosures can be combined to form an [Accordion](Accordion.html).

### Internationalization

In order to internationalize a disclosure, all text content within the disclosure should be localized.

## Events

Disclosure accepts an `onExpandedChange` prop which is triggered when it is expanded or collapsed. The example below uses `onExpandedChange` to programmatically control disclosure expansion.

```tsx example
function ControlledExpansion() {
  let [isExpanded, setIsExpanded] = React.useState<boolean>(false);

  return (
    <>
      <Disclosure isExpanded={isExpanded} onExpandedChange={setIsExpanded}>
        <DisclosureTitle>System Requirements</DisclosureTitle>
        <DisclosurePanel>
          Details about system requirements here.
        </DisclosurePanel>
      </Disclosure>
      <div style={{marginTop: '20px'}}>{isExpanded ? 'The disclosure is expanded' : 'The disclosure is collapsed'}</div>
    </>
  )
}
```

## Props

### Disclosure

<PropTable component={docs.exports.Disclosure} links={docs.links} />

### DisclosureTitle

<PropTable component={docs.exports.DisclosureTitle} links={docs.links} />

### DisclosurePanel

<PropTable component={docs.exports.DisclosurePanel} links={docs.links} />


## Visual Options

### Disabled

```tsx example
<Disclosure isDisabled>
  <DisclosureTitle>System Requirements</DisclosureTitle>
  <DisclosurePanel>
    Details about system requirements here.
  </DisclosurePanel>
</Disclosure>
```

### Expanded

```tsx example
<Disclosure defaultExpanded>
  <DisclosureTitle>System Requirements</DisclosureTitle>
  <DisclosurePanel>
    Details about system requirements here.
  </DisclosurePanel>
</Disclosure>
```

### Quiet

```tsx example
<Disclosure isQuiet>
  <DisclosureTitle>System Requirements</DisclosureTitle>
  <DisclosurePanel>
    Details about system requirements here.
  </DisclosurePanel>
</Disclosure>
```

---

### Packages @Adobe React Spectrum Docs Actionbar ActionBar (`packages/@adobe/react-spectrum/docs/actionbar/ActionBar.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import Anatomy from './ActionBarAnatomy.svg';
import docs from 'docs:@react-spectrum/actionbar';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/actionbar/package.json';

```jsx import
import {ActionBar, ActionBarContainer, Item} from '@react-spectrum/actionbar';
import {ListView} from '@react-spectrum/list';
import Edit from '@spectrum-icons/workflow/Edit';
import Copy from '@spectrum-icons/workflow/Copy';
import Delete from '@spectrum-icons/workflow/Delete';
import {Flex} from '@react-spectrum/layout';
import {Text} from '@react-spectrum/text';
import {TableView, TableHeader, TableBody, Row, Column, Cell} from '@react-spectrum/table';
```

---
category: Collections
keywords: [actionbar, selection, actions, collections, toolbar]
---

# ActionBar

<PageDescription>{docs.exports.ActionBar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ActionBar', 'ActionBarContainer']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/action-bar/'}
  ]}
  since="3.27.0"  />

## Example
```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set(['photoshop']));

  return (
    <ActionBarContainer height={300} maxWidth="size-6000">
      <ListView aria-label="ListView with action bar" selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
        <Item key="photoshop">Adobe Photoshop</Item>
        <Item key="illustrator">Adobe Illustrator</Item>
        <Item key="xd">Adobe XD</Item>
      </ListView>
      <ActionBar
        isEmphasized
        selectedItemCount={selectedKeys === 'all' ? 'all' : selectedKeys.size}
        onAction={(key) => alert(`Performing ${key} action...`)}
        onClearSelection={() => setSelectedKeys(new Set())}>
        <Item key="edit">
          <Edit />
          <Text>Edit</Text>
        </Item>
        <Item key="copy">
          <Copy />
          <Text>Copy</Text>
        </Item>
        <Item key="delete">
          <Delete />
          <Text>Delete</Text>
        </Item>
      </ActionBar>
    </ActionBarContainer>
  );
}

<Example />
```

## Content
<Anatomy role="img" aria-label="Action bar anatomy diagram, showing a close button, item counter, and action group." />

An ActionBar is a companion component intended to facilitate bulk actions on selected items within a collection component. It consists of an ActionGroup, a clear button, and a count of selected items. It accepts a list of <TypeLink links={docs.links} type={docs.exports.Item} />
elements as children, each with a `key` prop. Alternatively, a function that returns `Item` elements is also supported as seen below. See the [collection components](collections.html)
docs for more details about this API. These `Item` elements are used to populate the buttons in the ActionBar, and follows the [ActionGroup content guidelines](./ActionGroup.html#content) for customization and labeling.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let barItems = [
    {key: 'edit', label: 'Edit'},
    {key: 'copy', label: 'Copy'},
    {key: 'delete', label: 'Delete'}
  ];

  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set(['photoshop']));

  return (
    <ActionBarContainer height={300} maxWidth="size-6000">
      <ListView aria-label="ListView with action bar" selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
        <Item key="photoshop">Adobe Photoshop</Item>
        <Item key="illustrator">Adobe Illustrator</Item>
        <Item key="xd">Adobe XD</Item>
      </ListView>
      <ActionBar
        items={barItems}
        selectedItemCount={selectedKeys === 'all' ? 'all' : selectedKeys.size}
        onAction={(key) => alert(`Performing ${key} action...`)}
        onClearSelection={() => setSelectedKeys(new Set())}
        isEmphasized>
        {item => (
          <Item key={item.key}>
            {item.label}
          </Item>
        )}
      </ActionBar>
    </ActionBarContainer>
  );
}

<Example />
```

### Accessibility
The contents of the ActionBar should follow the same accessibility guidelines as ActionGroup's items, see the [ActionGroup docs](./ActionGroup.html#accessibility) for more details.

### Internationalization
To internationalize an ActionBar, the content provided to all child items should be localized. A localized string for the selection count and clear button `aria-label` will be provided
automatically. For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ActionBar is automatically flipped.

## Events
Use the `onClearSelection` prop as a callback to handle when the clear button in the ActionBar is pressed. Additionally, the `onAction` prop can be used as a callback for when the user
presses any of the buttons in the ActionBar. The `key` from the pressed `<Item>` will be passed to the callback.

The following example clears row selection within the TableView when the clear button is pressed and alerts the user as to what
action is being taken on the selected rows when the buttons are pressed.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Props

### ActionBarContainer props
<PropTable component={docs.exports.ActionBarContainer} links={docs.links} style={{marginBottom: '40px'}} />

### ActionBar props
<PropTable component={docs.exports.ActionBar} links={docs.links} />

## Visual options

### isEmphasized
`isEmphasized` should be applied to the ActionBar when it should call attention, such as when floating in a TableView. It should be omitted if the ActionBar should blend in
with the rest of the UI, directing a user’s focus to elsewhere in a view.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example({isEmphasized}: {isEmphasized?: boolean}) {
  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set(['photoshop']));

  return (
    <ActionBarContainer height={300} width="size-5000">
      <ListView aria-label="ListView with action bar" selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
        <Item key="photoshop">Adobe Photoshop</Item>
        <Item key="illustrator">Adobe Illustrator</Item>
        <Item key="xd">Adobe XD</Item>
      </ListView>
      <ActionBar
        /*- begin highlight -*/
        isEmphasized={isEmphasized}
        /*- end highlight -*/
        selectedItemCount={selectedKeys === 'all' ? 'all' : selectedKeys.size}
        onAction={(key) => alert(`Performing ${key} action...`)}
        onClearSelection={() => setSelectedKeys(new Set())}>
        <Item key="edit">
          <Edit />
          <Text>Edit</Text>
        </Item>
        <Item key="copy">
          <Copy />
          <Text>Copy</Text>
        </Item>
        <Item key="delete">
          <Delete />
          <Text>Delete</Text>
        </Item>
      </ActionBar>
    </ActionBarContainer>
  );
}

<Flex direction="row" gap="size-200" wrap>
  <Example />
  <Example isEmphasized />
</Flex>
```

### isDisabled
To disable individual items, a list of disabledKeys can be provided.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set(['photoshop']));

  return (
    <ActionBarContainer height={300} width="size-5000">
      <ListView aria-label="ListView with action bar" selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
        <Item key="photoshop">Adobe Photoshop</Item>
        <Item key="illustrator">Adobe Illustrator</Item>
        <Item key="xd">Adobe XD</Item>
      </ListView>
      <ActionBar
        /*- begin highlight -*/
        disabledKeys={['edit']}
        /*- end highlight -*/
        isEmphasized={true}
        selectedItemCount={selectedKeys === 'all' ? 'all' : selectedKeys.size}
        onAction={(key) => alert(`Performing ${key} action...`)}
        onClearSelection={() => setSelectedKeys(new Set())}>
        <Item key="edit">
          <Edit />
          <Text>Edit</Text>
        </Item>
        <Item key="copy">
          <Copy />
          <Text>Copy</Text>
        </Item>
        <Item key="delete">
          <Delete />
          <Text>Delete</Text>
        </Item>
      </ActionBar>
    </ActionBarContainer>
  );
}

<Example />
```

---

### Packages @Adobe React Spectrum Docs Actiongroup ActionGroup (`packages/@adobe/react-spectrum/docs/actiongroup/ActionGroup.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/actiongroup';
import collectionsDocs from 'docs:@react-stately/collections';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/actiongroup/package.json';

```jsx import
import {ActionGroup, Item} from '@react-spectrum/actiongroup';
import Brush from '@spectrum-icons/workflow/Brush';
import RegionSelect from '@spectrum-icons/workflow/RegionSelect';
import Select from '@spectrum-icons/workflow/Select';
import {Flex} from '@react-spectrum/layout';
import {View} from '@react-spectrum/view';
import ViewList from '@spectrum-icons/workflow/ViewList';
import ViewGrid from '@spectrum-icons/workflow/ViewGrid';
import ViewCard from '@spectrum-icons/workflow/ViewCard';
import Move from '@spectrum-icons/workflow/Move';
import Duplicate from '@spectrum-icons/workflow/Duplicate';
import TagBold from '@spectrum-icons/workflow/TagBold';
import TagItalic from '@spectrum-icons/workflow/TagItalic';
import TagUnderline from '@spectrum-icons/workflow/TagUnderline';
import TextStrikethrough from '@spectrum-icons/workflow/TextStrikethrough';
import TextAlignCenter from '@spectrum-icons/workflow/TextAlignCenter';
import TextAlignJustify from '@spectrum-icons/workflow/TextAlignJustify';
import TextAlignLeft from '@spectrum-icons/workflow/TextAlignLeft';
import TextAlignRight from '@spectrum-icons/workflow/TextAlignRight';
```

---
category: Buttons
keywords: [toolbar, actiongroup, collections]
---

# ActionGroup

<PageDescription>{docs.exports.ActionGroup.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ActionGroup', 'Item']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/action-group/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
function Example() {
  let [action, setAction] = React.useState(null);

  return (
    <>
      <ActionGroup onAction={setAction}>
        <Item key="add">Add</Item>
        <Item key="delete">Delete</Item>
        <Item key="edit">Edit</Item>
      </ActionGroup>
      <p>Action: {action}</p>
    </>
  );
}
```

## Content

ActionGroups accept a list of <TypeLink links={docs.links} type={docs.exports.Item} /> elements as children, each with a `key` prop. Alternatively, a function that returns `Item` elements is also supported. See the [collection components](collections.html) docs for more details about this API.

```tsx example
const items = [
  {label: 'React', name: 'React'},
  {label: 'Add', name: 'Add'},
  {label: 'Delete', name: 'Delete'}
];

<ActionGroup items={items}>
  {item => <Item key={item.name}>{item.label}</Item>}
</ActionGroup>
```

### Icons

Icons can be added to ActionGroup items by wrapping the label in a [Text](Text.html) element, and adding the icon as a sibling.

```tsx example
import Draw from '@spectrum-icons/workflow/Draw';
import Copy from '@spectrum-icons/workflow/Copy';
import Delete from '@spectrum-icons/workflow/Delete';
import {Text} from '@react-spectrum/text';

<ActionGroup>
  <Item key="edit">
    <Draw />
    <Text>Edit</Text>
  </Item>
  <Item key="copy">
    <Copy />
    <Text>Copy</Text>
  </Item>
  <Item key="delete">
    <Delete />
    <Text>Delete</Text>
  </Item>
</ActionGroup>
```

You can also hide the label text within the buttons using the `buttonLabelBehavior` prop. When set to `"hide"`, the label is
hidden and automatically shown in a tooltip on hover.

```tsx example
<ActionGroup buttonLabelBehavior="hide">
  <Item key="edit">
    <Draw />
    <Text>Edit</Text>
  </Item>
  <Item key="copy">
    <Copy />
    <Text>Copy</Text>
  </Item>
  <Item key="delete">
    <Delete />
    <Text>Delete</Text>
  </Item>
</ActionGroup>
```

### Accessibility

Icon only ActionGroups should usually include a tooltip to describe the button via the `buttonLabelBehavior` prop as described above. This also automatically handles
labeling the button for assistive technology users.

In rare cases where no tooltip is desired, an alternative text label must be provided to identify the control for accessibility.
This should be added using the `aria-label` prop to each Item.

```tsx example
<ActionGroup>
  <Item key="brush" aria-label="Brush"><Brush /></Item>
  <Item key="select" aria-label="Select"><Select /></Item>
  <Item key="regionSelect" aria-label="Select Region"><RegionSelect /></Item>
</ActionGroup>
```

### Internationalization

In order to internationalize an ActionGroup, the content provided to all child items should be localized.

## Selection
ActionGroup supports multiple selection modes. By default, selection is disabled, however this can be changed using the `selectionMode` prop.
Use `defaultSelectedKeys` to provide a default set of selected items (uncontrolled) and `selectedKeys` to set the selected items (controlled). The value of the selected keys must match the `key` prop of the items.
See the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
<ActionGroup selectionMode="single" defaultSelectedKeys={['list']}>
  <Item key="grid">Grid view</Item>
  <Item key="list">List view</Item>
  <Item key="gallery">Gallery view</Item>
</ActionGroup>
```

The `selectedKeys` prop can be used to make the selected state controlled.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set(['list']));

  return (
    <>
      <ActionGroup selectionMode="single" selectedKeys={selected} onSelectionChange={setSelected}>
        <Item key="grid">Grid view</Item>
        <Item key="list">List view</Item>
        <Item key="gallery">Gallery view</Item>
      </ActionGroup>
      <p>Current selection (controlled): {[...selected]}</p>
    </>
  );
}
```

Set `selectionMode` prop to `multiple` to allow more than one selection.
```tsx example
function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set(['list']));

  return (
    <>
      <ActionGroup selectionMode="multiple" selectedKeys={selected} onSelectionChange={setSelected}>
        <Item key="grid">Grid view</Item>
        <Item key="list">List view</Item>
        <Item key="gallery">Gallery view</Item>
      </ActionGroup>
      <p>Current selections (controlled): {[...selected].join(', ')}</p>
    </>
  );
}
```

## Events
Use the `onSelectionChange` prop as a callback to handle press events on items when selectionMode is either `single` or `multiple`.
The `key` prop from the selected item will be passed into the callback.

To continue to capturing actions when `selectionMode` is `none`, utilize the `onAction` prop.
```tsx example
import type {Key} from '@adobe/react-spectrum';

function Example() {
  let [actionKey, setActionKey] = React.useState<Key>('');
  return (
    <>
      <ActionGroup onAction={setActionKey}>
        <Item key="add">Add</Item>
        <Item key="delete">Delete</Item>
        <Item key="edit">Edit</Item>
      </ActionGroup>
      <p>Action: {actionKey}</p>
    </>
  );
}
```

## Collapsing behavior

By default, ActionGroup items wrap to form a new line when horizontal space is limited. However, this can cause content to shift below the
ActionGroup. If the ActionGroup should always appear in a single line, the `overflowMode` prop can be set to `collapse`. In this mode, when
horizontal space is limited, the ActionGroup will collapse into a menu. The exact behavior depends on the `selectionMode`.

### Non-selectable

When selection is not enabled, ActionGroup displays as many items as possible and collapses the remaining items into a more actions menu.

```tsx example
<ActionGroup overflowMode="collapse" maxWidth={250}>
  <Item key="edit">
    <Draw />
    <Text>Edit</Text>
  </Item>
  <Item key="copy">
    <Copy />
    <Text>Copy</Text>
  </Item>
  <Item key="delete">
    <Delete />
    <Text>Delete</Text>
  </Item>
  <Item key="move">
    <Move />
    <Text>Move</Text>
  </Item>
  <Item key="duplicate">
    <Duplicate />
    <Text>Duplicate</Text>
  </Item>
</ActionGroup>
```

### Selection

When selection is enabled, ActionGroup collapses all items into a menu together when space is limited. The menu button indicates when one of
the options within it is selected by showing a highlighted state. A `summaryIcon` should be specified to visually communicate the purpose of
the ActionGroup when collapsed, and an `aria-label` should be provided to describe the ActionGroup to assistive technology.

This example shows a multi-selectable ActionGroup that can be used to select text styles. When space is limited, it collapses into a dropdown
menu, and displays the `TextStyle` icon passed to the `summaryIcon` prop.

```tsx example
import TextStyle from '@spectrum-icons/workflow/TextStyle';

<ActionGroup
  aria-label="Text style"
  overflowMode="collapse"
  selectionMode="multiple"
  isEmphasized
  summaryIcon={<TextStyle />}
  maxWidth={100}>
  <Item key="bold">
    <TagBold />
    <Text>Bold</Text>
  </Item>
  <Item key="italic">
    <TagItalic />
    <Text>Italic</Text>
  </Item>
  <Item key="underline">
    <TagUnderline />
    <Text>Underline</Text>
  </Item>
  <Item key="strike">
    <TextStrikethrough />
    <Text>Strikethrough</Text>
  </Item>
</ActionGroup>
```

### Single selection

A special case where a `summaryIcon` is not needed is a single selectable ActionGroup (`selectionMode="single"`) which enforces that an item
is always selected (`disallowEmptySelection`). In this case, the selected item is displayed inside the menu button when collapsed.

```tsx example
<ActionGroup
  aria-label="Text alignment"
  overflowMode="collapse"
  selectionMode="single"
  defaultSelectedKeys={['left']}
  disallowEmptySelection
  buttonLabelBehavior="hide"
  isEmphasized
  maxWidth={100}>
  <Item key="left">
    <TextAlignLeft />
    <Text>Align Left</Text>
  </Item>
  <Item key="center">
    <TextAlignCenter />
    <Text>Align Center</Text>
  </Item>
  <Item key="right">
    <TextAlignRight />
    <Text>Align Right</Text>
  </Item>
  <Item key="justify">
    <TextAlignJustify />
    <Text>Justify</Text>
  </Item>
</ActionGroup>
```

### Collapsing button labels

In addition to collapsing items that don't fit into a menu, the button labels can also be automatically hidden when space is limited.
This keeps more buttons visible at a time before needing to collapse into a menu. This behavior can be enabled by setting the
`buttonLabelBehavior` prop to `"collapse"`. The labels will be automatically shown in tooltips when collapsed.

```tsx example
<ActionGroup overflowMode="collapse" buttonLabelBehavior="collapse" maxWidth={180}>
  <Item key="edit">
    <Draw />
    <Text>Edit</Text>
  </Item>
  <Item key="copy">
    <Copy />
    <Text>Copy</Text>
  </Item>
  <Item key="delete">
    <Delete />
    <Text>Delete</Text>
  </Item>
  <Item key="move">
    <Move />
    <Text>Move</Text>
  </Item>
  <Item key="duplicate">
    <Duplicate />
    <Text>Duplicate</Text>
  </Item>
</ActionGroup>
```

### Vertical collapsing behavior

Non-selectable vertical ActionGroups also support collapsing when the height is too small to fit all of the buttons.
The behavior is the same as for horizontal ActionGroups, except for the positioning of the tooltips and menu.

Vertical ActionGroups with selection do not currently support collapsing. When selection is enabled, we recommend placing
the ActionGroup in a scrollable container so that the user can access all items.

```tsx example
<ActionGroup overflowMode="collapse" orientation="vertical" buttonLabelBehavior="hide" maxHeight={150}>
  <Item key="edit">
    <Draw />
    <Text>Edit</Text>
  </Item>
  <Item key="copy">
    <Copy />
    <Text>Copy</Text>
  </Item>
  <Item key="delete">
    <Delete />
    <Text>Delete</Text>
  </Item>
  <Item key="move">
    <Move />
    <Text>Move</Text>
  </Item>
  <Item key="duplicate">
    <Duplicate />
    <Text>Duplicate</Text>
  </Item>
</ActionGroup>
```

## Props

<PropTable component={docs.exports.ActionGroup} links={docs.links} />

## Visual options

### Quiet

```tsx example
<ActionGroup isQuiet>
  <Item key="add">Add</Item>
  <Item key="delete">Delete</Item>
  <Item key="edit">Edit</Item>
</ActionGroup>
```

### Emphasized

The additional styling provided by the `isEmphasized` prop is only applied when items are selected.

```tsx example
<ActionGroup
  isEmphasized
  selectionMode="single"
  defaultSelectedKeys={['list']}>
  <Item key="grid">Grid view</Item>
  <Item key="list">List view</Item>
  <Item key="gallery">Gallery view</Item>
</ActionGroup>
```

### Static color

The `staticColor` prop can be used when the ActionGroup is displayed over a color background. When selected, the icon and text in each
button automatically take on the color of the background. You are responsible for choosing the static color variant that ensures the
text meets an [accessible contrast ratio](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast)
with the background.

```tsx example
<Flex wrap gap="size-250">
  <View backgroundColor="static-blue-700" padding="size-500">
    <ActionGroup staticColor="white">
      <Item key="edit">
        <Draw />
        <Text>Edit</Text>
      </Item>
      <Item key="copy">
        <Copy />
        <Text>Copy</Text>
      </Item>
      <Item key="delete">
        <Delete />
        <Text>Delete</Text>
      </Item>
    </ActionGroup>
  </View>
  <View backgroundColor="static-yellow-400" padding="size-500">
    <ActionGroup
      staticColor="black"
      isQuiet
      buttonLabelBehavior="hide"
      selectionMode="single"
      disallowEmptySelection
      defaultSelectedKeys={['list']}>
      <Item key="list">
        <ViewList />
        <Text>List view</Text>
      </Item>
      <Item key="grid">
        <ViewGrid />
        <Text>Grid view</Text>
      </Item>
      <Item key="gallery">
        <ViewCard />
        <Text>Gallery view</Text>
      </Item>
    </ActionGroup>
  </View>
</Flex>
```

### Disabled

To disable the entire ActionGroup, use the `isDisabled` prop on the root.

```tsx example
<ActionGroup isDisabled>
  <Item key="add">Add</Item>
  <Item key="delete">Delete</Item>
  <Item key="edit">Edit</Item>
</ActionGroup>
```

To disable individual items, a list of `disabledKeys` can be provided.

```tsx example
<ActionGroup disabledKeys={['add', 'delete']}>
  <Item key="add">Add</Item>
  <Item key="delete">Delete</Item>
  <Item key="edit">Edit</Item>
</ActionGroup>
```

### Orientation

Using the `orientation` prop with value `vertical` changes the alignment of the items to follow the y-axis.

```tsx example
<ActionGroup orientation="vertical">
  <Item key="brush" aria-label="Brush"><Brush /></Item>
  <Item key="select" aria-label="Select"><Select /></Item>
  <Item key="regionSelect" aria-label="Select Region"><RegionSelect /></Item>
</ActionGroup>
```

### Density

Using the `density` prop with value `compact` changes the margins between the buttons.
In the default case, this merges the borders of neighboring ActionButtons. In the
quiet case, it just reduces the margin size between the buttons.

```tsx example
<ActionGroup density="compact">
  <Item key="brush" aria-label="Brush"><Brush /></Item>
  <Item key="select" aria-label="Select"><Select /></Item>
  <Item key="regionSelect" aria-label="Select Region"><RegionSelect /></Item>
</ActionGroup>
```

```tsx example
<ActionGroup isQuiet density="compact">
  <Item key="brush" aria-label="Brush"><Brush /></Item>
  <Item key="select" aria-label="Select"><Select /></Item>
  <Item key="regionSelect" aria-label="Select Region"><RegionSelect /></Item>
</ActionGroup>
```

### Justified
The `isJustified` prop will divide all available horizontal space evenly among the buttons.

```tsx example
<Flex width="size-2000" direction="column">
  <ActionGroup isJustified>
    <Item key="brush" aria-label="Brush"><Brush /></Item>
    <Item key="select" aria-label="Select"><Select /></Item>
    <Item key="regionSelect" aria-label="Select Region"><RegionSelect /></Item>
  </ActionGroup>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Autocomplete SearchAutocomplete (`packages/@adobe/react-spectrum/docs/autocomplete/SearchAutocomplete.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/autocomplete';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/autocomplete/package.json';

```jsx import
import {SearchAutocomplete, Section, Item} from '@react-spectrum/autocomplete';
import {useFilter} from '@react-aria/i18n';
import Email from '@spectrum-icons/workflow/Email';
import Document from '@spectrum-icons/workflow/Document';
import WebPages from '@spectrum-icons/workflow/WebPages';
import SocialNetwork from '@spectrum-icons/workflow/SocialNetwork';
import ShoppingCart from '@spectrum-icons/workflow/ShoppingCart';
import Folder from '@spectrum-icons/workflow/Folder';
import {Text} from '@react-spectrum/text';
import {Avatar} from "@react-spectrum/avatar";
```

---
category: Pickers
keywords: [search field, input]
after_version: 3.0.0
---

# SearchAutocomplete

<PageDescription>{docs.exports.SearchAutocomplete.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['SearchAutocomplete', 'Section', 'Item']} />

## Example

```tsx example
<SearchAutocomplete label="Search with Autocomplete">
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

## Content
SearchAutocomplete follows the [Collection Components](collections.html) API, accepting both static and dynamic collections.
Similar to [ComboBox](ComboBox.html), SearchAutocomplete accepts `<Item>` elements as children, each with a `key` prop. Basic usage of SearchAutocomplete, seen in the example above, shows multiple options populated with a string.
Static collections, as in this example, can be used when the full list of options is known ahead of time.

Dynamic collections, as shown below, can be used when the options come from an external data source such as an API call, or update over time.
Providing the data in this way allows SearchAutocomplete to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of options is passed to the SearchAutocomplete using the `defaultItems` prop.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aerospace'},
    {id: 2, name: 'Mechanical'},
    {id: 3, name: 'Civil'},
    {id: 4, name: 'Biomedical'},
    {id: 5, name: 'Nuclear'},
    {id: 6, name: 'Industrial'},
    {id: 7, name: 'Chemical'},
    {id: 8, name: 'Agricultural'},
    {id: 9, name: 'Electrical'}
  ];

  return (
    <SearchAutocomplete
      label="Search engineering majors"
      defaultItems={options}>
      {item => <Item>{item.name}</Item>}
    </SearchAutocomplete>
  );
}
```

Alternatively, passing your list of options to SearchAutocomplete's `items` prop will cause the list of items to be controlled, useful for when you want to provide your own
filtering logic. See the [Custom Filtering](#custom-filtering) section for more detail.

### Internationalization
To internationalize a SearchAutocomplete, a localized string should be passed to the `children` of each `Item`.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the SearchAutocomplete is automatically flipped.

## Labeling
SearchAutocomplete can be labeled using the `label` prop. If the SearchAutocomplete is a required field, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<SearchAutocomplete label="Favorite Animal" isRequired necessityIndicator="icon">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```
```tsx example
<SearchAutocomplete label="Favorite Animal" isRequired necessityIndicator="label">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```
```tsx example
<SearchAutocomplete label="Favorite Animal" necessityIndicator="label">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the SearchAutocomplete for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a SearchAutocomplete, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Links

By default, interacting with an item in a SearchAutocomplete updates the input value. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Interacting with link items navigates to the provided URL and does not update the input value.

```tsx example
<SearchAutocomplete label="Tech company websites">
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</SearchAutocomplete>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
SearchAutocomplete supports sections in order to group options. Sections can be used by wrapping groups of items in a `Section` element. Each `Section` takes a `title` and `key` prop.

### Static items
```tsx example
<SearchAutocomplete label="Preferred fruit or vegetable">
  <Section title="Fruit">
    <Item key="Apple">Apple</Item>
    <Item key="Banana">Banana</Item>
    <Item key="Orange">Orange</Item>
    <Item key="Honeydew">Honeydew</Item>
    <Item key="Grapes">Grapes</Item>
    <Item key="Watermelon">Watermelon</Item>
    <Item key="Cantaloupe">Cantaloupe</Item>
    <Item key="Pear">Pear</Item>
  </Section>
  <Section title="Vegetable">
    <Item key="Cabbage">Cabbage</Item>
    <Item key="Broccoli">Broccoli</Item>
    <Item key="Carrots">Carrots</Item>
    <Item key="Lettuce">Lettuce</Item>
    <Item key="Spinach">Spinach</Item>
    <Item key="Bok Choy">Bok Choy</Item>
    <Item key="Cauliflower">Cauliflower</Item>
    <Item key="Potatoes">Potatoes</Item>
  </Section>
</SearchAutocomplete>
```

### Dynamic items
Sections used with dynamic items are populated from a hierarchical data structure. Please note that `Section` takes an array of data using the `items` prop only.

```tsx example
function Example() {
  let options = [
    {name: 'Fruit', children: [
      {name: 'Apple'},
      {name: 'Banana'},
      {name: 'Orange'},
      {name: 'Honeydew'},
      {name: 'Grapes'},
      {name: 'Watermelon'},
      {name: 'Cantaloupe'},
      {name: 'Pear'}
    ]},
    {name: 'Vegetable', children: [
      {name: 'Cabbage'},
      {name: 'Broccoli'},
      {name: 'Carrots'},
      {name: 'Lettuce'},
      {name: 'Spinach'},
      {name: 'Bok Choy'},
      {name: 'Cauliflower'},
      {name: 'Potatoes'}
    ]}
  ];

  return (
    <SearchAutocomplete label="Preferred fruit or vegetable" defaultItems={options}>
      {item => (
        <Section key={item.name} items={item.children} title={item.name}>
          {item => <Item key={item.name}>{item.name}</Item>}
        </Section>
      )}
    </SearchAutocomplete>
  );
}
```

## Complex items
Items within SearchAutocomplete also allow for additional content used to better communicate options. Icons, avatars, and descriptions can be added to the `children` of `Item` as shown in the example below.
If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
See Icon's [labeling](workflow-icons.html#labeling) section and Avatar's [accessibility](Avatar.html#accessibility) section for more information on how to label these elements.

```tsx example
<SearchAutocomplete label="Search apps">
  <Section title="Productivity">
    <Item textValue="Mail">
      <Email size="S" />
      <Text>Mail</Text>
      <Text slot="description">Send and receive emails</Text>
    </Item>
    <Item textValue="File Explorer">
      <Folder size="S" />
      <Text>File Explorer</Text>
      <Text slot="description">Navigate directories and open files</Text>
    </Item>
    <Item textValue="Document Editor">
      <Document size="S" />
      <Text>Document Editor</Text>
      <Text slot="description">Edit documents</Text>
    </Item>
  </Section>
  <Section title="Internet">
    <Item textValue="Web Browser">
      <WebPages size="S" />
      <Text>Web Browser</Text>
      <Text slot="description">Browse the internet</Text>
    </Item>
    <Item textValue="Social Media">
      <SocialNetwork size="S" />
      <Text>Social Media</Text>
      <Text slot="description">Connect with friends</Text>
    </Item>
    <Item textValue="Shopping">
      <ShoppingCart size="S" />
      <Text>Shopping</Text>
      <Text slot="description">Shop online</Text>
    </Item>
  </Section>
</SearchAutocomplete>
```

### With avatars

```tsx example
<SearchAutocomplete label="Search users">
  <Item textValue="User 1">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 1</Text>
  </Item>
  <Item textValue="User 2">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 2</Text>
  </Item>
  <Item textValue="User 3">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 3</Text>
  </Item>
  <Item textValue="User 4">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 4</Text>
  </Item>
</SearchAutocomplete>
```

## Asynchronous loading

SearchAutocomplete supports loading data asynchronously, and will display a progress circle reflecting the current load state,
set by the `loadingState` prop. It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data. See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Character {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Character>({
    async load({signal, cursor, filterText}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      // If no cursor is available, then we're loading the first page,
      // filtering the results returned via a query string that
      // mirrors the SearchAutocomplete input text.
      // Otherwise, the cursor is the next URL to load,
      // as returned from the previous page.
      let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=${filterText}`, {signal});
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <SearchAutocomplete
      label="Star Wars Character Lookup"
      items={list.items}
      inputValue={list.filterText}
      onInputChange={list.setFilterText}
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}>
      {item => <Item key={item.name}>{item.name}</Item>}
    </SearchAutocomplete>
  );
}
```

## Validation

SearchAutocomplete supports the `isRequired` prop to ensure the user enters a value, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](../forms) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the search field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <SearchAutocomplete label="Favorite animal" name="animal" isRequired>
  {/*- end highlight -*/}
    <Item>Aardvark</Item>
    <Item>Cat</Item>
    <Item>Dog</Item>
    <Item>Kangaroo</Item>
    <Item>Panda</Item>
    <Item>Snake</Item>
  </SearchAutocomplete>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `SearchAutocomplete` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Custom Filtering
By default, SearchAutocomplete uses a string "contains" filtering strategy when deciding what items to display in the dropdown menu. This filtering strategy can be overwritten
by filtering the list of items yourself and passing the filtered list to the SearchAutocomplete via the `items` prop.

The example below uses a string "startsWith" filter function obtained from the `useFilter` hook to display items that start with the SearchAutocomplete's current input
value only. By using the `menuTrigger` returned by `onOpenChange`, it also handles displaying the entire option list regardless of the current filter value when the SearchAutocomplete menu is
opened via the trigger button or arrow keys. `menuTrigger` tells you if the menu was opened manually by the user ("manual"), by focusing the SearchAutocomplete ("focus"), or by
changes in the input field ("input"), allowing you to make updates to other controlled aspects of your SearchAutocomplete accordingly.

```tsx example
function Example() {
  let options = [
    {id: 1, email: 'fake@email.com'},
    {id: 2, email: 'anotherfake@email.com'},
    {id: 3, email: 'bob@email.com'},
    {id: 4, email: 'joe@email.com'},
    {id: 5, email: 'yourEmail@email.com'},
    {id: 6, email: 'valid@email.com'},
    {id: 7, email: 'spam@email.com'},
    {id: 8, email: 'newsletter@email.com'},
    {id: 9, email: 'subscribe@email.com'}
  ];

  let [showAll, setShowAll] = React.useState(false);
  let [filterValue, setFilterValue] = React.useState('');
  let {startsWith} = useFilter({sensitivity: 'base'});
  let filteredItems = React.useMemo(() => options.filter(item => startsWith(item.email, filterValue)), [options, filterValue]);

  return (
    <SearchAutocomplete
      onOpenChange={(isOpen, menuTrigger) => {
        // Show all items if menu is opened manually
        // i.e. by the arrow keys or trigger button
        if (menuTrigger === 'manual' && isOpen) {
          setShowAll(true);
        }
      }}
      width="size-3000"
      label="Search Email Addresses"
      items={showAll ? options : filteredItems}
      inputValue={filterValue}
      onInputChange={(value) => {
        setShowAll(false);
        setFilterValue(value);
      }}>
      {item => <Item>{item.email}</Item>}
    </SearchAutocomplete>
  );
}
```

## Trigger options
By default, the SearchAutocomplete's menu is opened when the user types into the input field ("input"). There are two other supported modes: one where the menu opens when the SearchAutocomplete is focused ("focus") and
the other where the menu only opens when the user clicks or taps on the SearchAutocomplete's field button ("manual"). These can be set by providing "focus" or "manual" to the `menuTrigger` prop.
Guidelines on when to use a specific mode can be found [here](https://spectrum.adobe.com/page/combo-box/#Menu-trigger). Note that the mobile SearchAutocomplete experience requires the end user to press the SearchAutocomplete button
to open the tray regardless of the `menuTrigger` setting.

```tsx example
<SearchAutocomplete label="Favorite Animal" menuTrigger="focus">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```
```tsx example
<SearchAutocomplete label="Favorite Animal" menuTrigger="manual">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

## Props

<PropTable component={docs.exports.SearchAutocomplete} links={docs.links} />

## Visual options

### Label alignment and position

By default, the label is positioned above the SearchAutocomplete. The `labelPosition` prop can be used to position the label to the side.
The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the SearchAutocomplete and "end" refers to the right most edge.
For right-to-left (RTL) languages, this is flipped.

```tsx example
<SearchAutocomplete label="Favorite Animal" labelPosition="side" labelAlign="end">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Quiet

```tsx example
<SearchAutocomplete label="Favorite Animal" isQuiet>
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Disabled

```tsx example
<SearchAutocomplete label="Favorite Animal" isDisabled>
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Read only

```tsx example
<SearchAutocomplete label="Search Animals" isReadOnly>
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Custom widths

```tsx example
<SearchAutocomplete label="Favorite Animal" width="size-6000" maxWidth="100%">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

### Menu direction
```tsx example
<SearchAutocomplete label="Favorite Animal" direction="top">
  <Item>Red Panda</Item>
  <Item>Cat</Item>
  <Item>Dog</Item>
  <Item>Aardvark</Item>
  <Item>Kangaroo</Item>
  <Item>Snake</Item>
</SearchAutocomplete>
```

## Testing

The SearchAutocomplete features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your device configuration, this overlay may render as a tray or a dropdown and the trigger itself may render as a button or a input. Additionally,
the SearchAutocomplete features automatic virtualization and may need specific mocks in a test environment to enable said virtualization properly.
Please see the following sections in the testing docs for more information on how to handle these
behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/autocomplete/test/SearchAutocomplete.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Avatar Avatar (`packages/@adobe/react-spectrum/docs/avatar/Avatar.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/avatar';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/avatar/package.json';

```jsx import
import {Avatar} from '@react-spectrum/avatar';
import {Flex} from '@react-spectrum/layout';
```

---
category: Content
keywords: [avatar]
---

# Avatar

<PageDescription>{docs.exports.Avatar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Avatar']}
  sourceData={[{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/avatar/'}]}
  since="3.26.0" />

## Example

```tsx example
<Avatar src="https://i.imgur.com/kJOwAdv.png" alt="default Adobe avatar" />
```

## Content

The Avatar component is a thumbnail representation of an entity, such as a user or an organization. They accept a `src` attribute defining the image URL, and an `alt` attribute for an accessible description.

### Accessibility

By default, avatars are decorative and have an empty `alt` attribute. Standalone avatars with no surrounding context must have a custom `alt` prop defined for accessibility.

### Internationalization

To internationalize an Avatar, a localized string should be passed to the `alt` prop.

## Props

<PropTable component={docs.exports.Avatar} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/avatar/#Disabled)
```tsx example
<Avatar src="https://i.imgur.com/kJOwAdv.png" alt="default Adobe avatar" isDisabled />
```

### Size
[View guidelines](https://spectrum.adobe.com/page/avatar/#Size)

Sizes can either be one of the predefined avatar size variables, or a custom size in pixels.

```tsx example
<Flex gap="size-100" wrap>
  {[50, 75, 100, 200, 300, 400, 500, 600, 700].map(size => (
    <Avatar key={size} src="https://i.imgur.com/kJOwAdv.png" alt="default Adobe avatar" size={`avatar-size-${size}`} />
  ))}
  <Avatar src="https://i.imgur.com/kJOwAdv.png" alt="avatar with custom size" size={50} />
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Badge Badge (`packages/@adobe/react-spectrum/docs/badge/Badge.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/badge';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/badge/package.json';

```jsx import
import {Badge} from '@react-spectrum/badge';
```

---
category: Status
keywords: [badge]
---

# Badge

<PageDescription>{docs.exports.Badge.description}</PageDescription>

<HeaderInfo
packageData={packageData}
componentNames={['Badge']}
sourceData={[
{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/badge/'}
]}
since="3.22.0" />

## Example

```tsx example
<Badge variant="positive">Licensed</Badge>
```

## Content

Badges can have a label, an icon, or both. An icon is provided by passing an icon component as a child to the Badge.
A visible label can be provided by passing a string or a Text component as a child, depending on whether the Badge has an accompanying icon.

```tsx example
import {Text} from '@react-spectrum/text';
import CheckmarkCircle from '@spectrum-icons/workflow/CheckmarkCircle';

<Badge variant="positive">
  <CheckmarkCircle aria-label="Done" />
  <Text>Icon + Label</Text>
</Badge>
```

### Accessibility
If a visible label isn't specified, an `aria-label` must be provided to the icon for accessibility.


### Internationalization

To internationalize a Badge, a localized string should be set as the child content of the Badge.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the Badge is automatically flipped.

## Props

<PropTable component={docs.exports.Badge} links={docs.links} />

## Visual options

### Variant
[View guidelines](https://spectrum.adobe.com/page/badge/#Semantic-variants)

When badges have a semantic meaning, they should use semantic colors.
Use the appropriate color to indicate status as follows.

```tsx example
import {Flex} from '@react-spectrum/layout';

<Flex direction="column" gap={8}>
  <Badge variant="positive">Green: Approved, Complete, Success, New, Purchased, Licensed</Badge>
  <Badge variant="info">Blue: Active, In Use, Live, Published</Badge>
  <Badge variant="negative">Red: Error, Alert, Rejected, Failed</Badge>
  <Badge variant="neutral">Gray: Archived, Deleted, Paused, Draft, Not Started, Ended</Badge>
</Flex>
```

When badges are used to color code categories, they use label colors. The ideal usage for these is when there
are 8 or fewer categories being color coded.

```tsx example
import {Flex} from '@react-spectrum/layout';

<Flex direction="column" gap={8}>
  <Badge variant="seafoam">Seafoam</Badge>
  <Badge variant="indigo">Indigo</Badge>
  <Badge variant="purple">Purple</Badge>
  <Badge variant="fuchsia">Fuchsia</Badge>
  <Badge variant="magenta">Magenta</Badge>
  <Badge variant="yellow">Yellow</Badge>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Breadcrumbs Breadcrumbs (`packages/@adobe/react-spectrum/docs/breadcrumbs/Breadcrumbs.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/breadcrumbs';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/breadcrumbs/package.json';

```jsx import
import {Breadcrumbs, Item} from '@react-spectrum/breadcrumbs';
import {View} from '@react-spectrum/view';
```

---
category: Navigation
keywords: [collections, dropdown]
---

# Breadcrumbs

<PageDescription>{docs.exports.Breadcrumbs.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Breadcrumbs', 'Item']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/breadcrumbs/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<Breadcrumbs>
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
  <Item key="march 2020 assets">March 2020 Assets</Item>
</Breadcrumbs>
```

## Content
Breadcrumbs follow the [Collection Components](collections.html) API, accepting only static children.
Similar to [Menu](Menu.html), Breadcrumbs accepts &lt;<TypeLink links={docs.links} type={docs.exports.Item} />&gt; elements as children,
each with a `key` prop, which is passed to the `onAction` handler to identify the selected item.
Basic usage of Breadcrumbs, as seen in the example above, shows a list of <TypeLink links={docs.links} type={docs.exports.Item} /> elements,
populated with a string. See [Events](#events) for more information.

### Internationalization
In order to internationalize Breadcrumbs, the content of all child items should be localized.

## Events
Use the `onAction` prop as a callback to handle press events on items.

```tsx example
function Example() {
  let folders = [
    {id: 1, label: 'Home'},
    {id: 2, label: 'Trendy'},
    {id: 3, label: 'March 2020 Assets'}
  ];
  let [folderId, setFolderId] = React.useState(null);
  return (
    <div>
      <Breadcrumbs onAction={(a) => setFolderId(a)}>
        {folders.map(f => <Item key={f.id}>{f.label}</Item>)}
      </Breadcrumbs>
      <p>You pressed folder ID: {folderId}</p>
    </div>
  );
}
```

## Links

By default, interacting with an item in Breadcrumbs triggers `onAction`. Items may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component.

```tsx example
<Breadcrumbs>
  <Item href="#">Home</Item>
  <Item href="#">React Spectrum</Item>
  <Item>Breadcrumbs</Item>
</Breadcrumbs>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Props

<PropTable component={docs.exports.Breadcrumbs} links={docs.links} />

## Visual options

### Size
[View guidelines](https://spectrum.adobe.com/page/breadcrumbs/#Options)

Small
```tsx example
<Breadcrumbs size="S">
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
</Breadcrumbs>
```

Medium
```tsx example
<Breadcrumbs size="M">
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
</Breadcrumbs>
```

Large (default)
```tsx example
<Breadcrumbs size="L">
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
</Breadcrumbs>
```

### Multiline

Use the `isMultiline` prop to place the last item below the other items.
This adds emphasis to the current location as a page title or heading.

```tsx example
<Breadcrumbs isMultiline>
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
  <Item key="march 2020 assets">March 2020 Assets</Item>
</Breadcrumbs>
```

### Root context
[View guidelines](https://spectrum.adobe.com/page/breadcrumbs/#With-root-context)

Some applications find that always displaying the root item is useful to orient users.
This variation keeps the root visible when other items are truncated into the menu.

```tsx example
<View overflow="hidden" width="200px">
  <Breadcrumbs showRoot>
    <Item key="home">Home</Item>
    <Item key="trendy">Trendy</Item>
    <Item key="2020 assets">March 2020 Assets</Item>
    <Item key="winter">Winter</Item>
    <Item key="holiday">Holiday</Item>
  </Breadcrumbs>
</View>
```

### Disabled

Breadcrumbs in a disabled state shows items, but indicates that navigation is not available.
This can be used to maintain layout continuity.

```tsx example
<Breadcrumbs isDisabled>
  <Item key="home">Home</Item>
  <Item key="trendy">Trendy</Item>
  <Item key="march 2020 assets">March 2020 Assets</Item>
</Breadcrumbs>
```

### Visible items (overflow behavior)
[View guidelines](https://spectrum.adobe.com/page/breadcrumbs/#Truncation-and-overflow)

Breadcrumbs collapses items into a menu when space is limited. It will only show a maximum of 4 visible items including the root and menu button, if either are visible. If the root item cannot be rendered in the available horizontal
space, it will be collapsed into the menu regardless of `showRoot`. Note that the last breadcrumb item will automatically
truncate with an ellipsis instead of collapsing into the menu.

Resize your browser window to see the above behavior in the examples below.

```tsx example
<Breadcrumbs>
  <Item key="shared">My Shared Documents</Item>
  <Item key="catalogue">North America Spring Catalogue</Item>
  <Item key="march 2020">March 2020</Item>
  <Item key="assets">Downloaded Screenshots and Assets (approval required)</Item>
  <Item key="streetwear">Streetwear</Item>
  <Item key="jackets">Jackets</Item>
</Breadcrumbs>
```

```tsx example
<Breadcrumbs showRoot>
  <Item key="shared">My Shared Documents</Item>
  <Item key="catalogue">North America Spring Catalogue</Item>
  <Item key="march 2020">March 2020</Item>
  <Item key="assets">Downloaded Screenshots and Assets (approval required)</Item>
</Breadcrumbs>
```

---

### Packages @Adobe React Spectrum Docs Button ActionButton (`packages/@adobe/react-spectrum/docs/button/ActionButton.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/button';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/button/package.json';

```jsx import
import {ActionButton} from '@react-spectrum/button';
import {View} from '@react-spectrum/view';
import {Flex} from '@react-spectrum/layout';
```

---
category: Buttons
keywords: [action button]
---

# ActionButton

<PageDescription>{docs.exports.ActionButton.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ActionButton']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/action-button/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<ActionButton>Edit</ActionButton>
```

## Content

ActionButtons can have a label, an icon, or both. An icon is provided by passing an icon component as a child to the ActionButton.
A visible label can be provided by passing a string or a Text component as a child, depending on whether the ActionButton has an accompanying icon.

```tsx example
import {Text} from '@react-spectrum/text';
import Edit from '@spectrum-icons/workflow/Edit';

<ActionButton>
  <Edit />
  <Text>Icon + Label</Text>
</ActionButton>
```

### Accessibility

If no visible label is provided (e.g. an icon only button),
an alternative text label must be provided to identify the control for accessibility. This should be added using
the `aria-label` prop.

```tsx example
<ActionButton aria-label="Icon only">
  <Edit />
</ActionButton>
```

### Internationalization

In order to internationalize an ActionButton, a localized string should be passed to the `children` or `aria-label` prop.

## Events

ActionButtons support user interactions via mouse, keyboard, and touch. You can handle all of these via the `onPress`
prop.

The following example uses an `onPress` handler to update a counter stored in React state.

```tsx example
function Example() {
  let [count, setCount] = React.useState(0);

  return (
   <ActionButton onPress={() => setCount(c => c + 1)}>{count} Edits</ActionButton>
  );
}
```

## Props

<PropTable component={docs.exports.ActionButton} links={docs.links} />

## Visual options

### Quiet
[View guidelines](https://spectrum.adobe.com/page/action-button/#Quiet)

```tsx example
<ActionButton isQuiet>Action!</ActionButton>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/action-button/#Disabled)

```tsx example
<ActionButton isDisabled>Action!</ActionButton>
```

### Static color

The `staticColor` prop can be used when an ActionButton is displayed over a color background. You are responsible for
choosing the static color variant that ensures the text meets an
[accessible contrast ratio](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast)
with the background.

```tsx example
<Flex wrap gap="size-250">
  <View backgroundColor="static-blue-700" padding="size-500">
    <ActionButton staticColor="white">
      <Edit />
      <Text>Edit</Text>
    </ActionButton>
  </View>
  <View backgroundColor="static-yellow-400" padding="size-500">
    <ActionButton staticColor="black" isQuiet>
      <Edit />
      <Text>Edit</Text>
    </ActionButton>
  </View>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Button Button (`packages/@adobe/react-spectrum/docs/button/Button.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/button';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/button/package.json';

```jsx import
import {Button} from '@react-spectrum/button';
import Bell from '@spectrum-icons/workflow/Bell';
import {View} from '@react-spectrum/view';
import {Flex} from '@react-spectrum/layout';
```

---
category: Buttons
---

# Button

<PageDescription>{docs.exports.Button.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Button']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/button/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<Button variant="accent">Save</Button>
```

## Content

Buttons must have a visible label, and can optionally have an icon. Text only buttons accept a string
as children. Icons can also be added as children, with a sibling [Text](Text.html) element for the label.

```tsx example
import {Text} from '@react-spectrum/text';

<Button variant="primary">
  <Bell />
  <Text>Icon + Label</Text>
</Button>
```

### Accessibility

If no visible label is provided (e.g. an icon only button),
an alternative text label must be provided to identify the control for accessibility. This should be added using
the `aria-label` prop.

### Internationalization

In order to internationalize a button, a localized string should be passed to the `children` or `aria-label` prop.

## Events

Buttons support user interactions via mouse, keyboard, and touch. You can handle all of these via the `onPress`
prop.

The following example uses an `onPress` handler to update a counter stored in React state.

```tsx example
function Example() {
  let [count, setCount] = React.useState(0);

  return (
    <Button variant="primary" onPress={() => setCount(c => c + 1)}>{count} Dogs</Button>
  );
}
```

## Pending

Buttons can indicate that a quick progress task is taking place (e.g., saving settings on a server). After a 1 second delay, an indeterminate spinner will be displayed in place of the button label and icon. You can trigger this behavior with the `isPending` prop. Button events are disabled while `isPending` is true.

```tsx example
function Example() {
  let [isLoading, setIsLoading] = React.useState(false);

  let handlePress = () => {
    // Trigger button pending state
    setIsLoading(true);

    setTimeout(() => {
      // Cancel button pending state
      setIsLoading(false);
    }, 3000);
  };

  return (
    <Button variant="primary" isPending={isLoading} onPress={handlePress}>Click me!</Button>
  );
}
```

## Props

<PropTable component={docs.exports.Button} links={docs.links} />

## Visual options

### Accent
[View guidelines](https://spectrum.adobe.com/page/button/#Accent-variant)

```tsx example
<Flex wrap gap="size-250">
  <Button variant="accent" style="fill">Save</Button>
  <Button variant="accent" style="outline">Save</Button>
</Flex>
```

### Primary
[View guidelines](https://spectrum.adobe.com/page/button/#Primary-variant)

```tsx example
<Flex wrap gap="size-250">
  <Button variant="primary" style="fill">Save</Button>
  <Button variant="primary" style="outline">Save</Button>
</Flex>
```

### Secondary
[View guidelines](https://spectrum.adobe.com/page/button/#Secondary-variant)

```tsx example
<Flex wrap gap="size-250">
  <Button variant="secondary" style="fill">Save</Button>
  <Button variant="secondary" style="outline">Save</Button>
</Flex>
```

### Negative
[View guidelines](https://spectrum.adobe.com/page/button/#Negative-variant)

```tsx example
<Flex wrap gap="size-250">
  <Button variant="negative" style="fill">Save</Button>
  <Button variant="negative" style="outline">Save</Button>
</Flex>
```

### Static color
[View guidelines](https://spectrum.adobe.com/page/button/#Static-color)

```tsx example
<Flex wrap gap="size-250">
  <View backgroundColor="static-blue-700" padding="size-500">
    <Flex wrap gap="size-200">
      <Button variant="primary" staticColor="white" style="fill">Save</Button>
      <Button variant="primary" staticColor="white" style="outline">Save</Button>
    </Flex>
  </View>
  <View backgroundColor="static-yellow-400" padding="size-500">
    <Flex wrap gap="size-200">
      <Button variant="primary" staticColor="black" style="fill">Save</Button>
      <Button variant="primary" staticColor="black" style="outline">Save</Button>
    </Flex>
  </View>
</Flex>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/button/#Disabled)

```tsx example
<Button variant="accent" isDisabled>Save</Button>
```

### Icon only
[View guidelines](https://spectrum.adobe.com/page/button/#Label-and-icon)

```tsx example
<Flex direction="row" gap={8}>
  <Button variant="accent" aria-label="Ring for service"><Bell /></Button>
  <Button variant="primary" aria-label="Ring for service"><Bell /></Button>
  <Button variant="secondary" aria-label="Ring for service"><Bell /></Button>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Button LogicButton (`packages/@adobe/react-spectrum/docs/button/LogicButton.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/button';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/button/package.json';

```jsx import
import {LogicButton} from '@react-spectrum/button';
```

---
category: Buttons
keywords: [logic button]
---

# LogicButton

<PageDescription>{docs.exports.LogicButton.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['LogicButton']}
  since="3.0.0" />

## Example

```tsx example
<LogicButton variant="and">And</LogicButton>
```

## Content

LogicButtons must have a variant and optionally can have a label.
A visible label can be provided by passing children.

```tsx example
<LogicButton variant="or">Or</LogicButton>
```

### Internationalization

In order to internationalize a LogicButton, a localized string should be passed to the `children` or `aria-label` prop.

## Events

LogicButton supports user interactions via mouse, keyboard, and touch. You can handle all of these via the `onPress` prop.

The following example uses an `onPress` handler to update the variant.

```tsx example
function Example() {
  let [variant, setVariant] = React.useState<'and' | 'or'>('or');

  return (
    <LogicButton variant={variant} onPress={() => setVariant(variant === 'or' ? 'and' : 'or')}>{variant}</LogicButton>
  );
}
```

## Props

<PropTable component={docs.exports.LogicButton} links={docs.links} />

## Visual options

### Variant

```tsx example
<LogicButton variant="or" marginEnd="20px">Or</LogicButton>
<LogicButton variant="and">And</LogicButton>
```

### Disabled

```tsx example
<LogicButton variant="or" isDisabled>Or</LogicButton>
```

---

### Packages @Adobe React Spectrum Docs Button ToggleButton (`packages/@adobe/react-spectrum/docs/button/ToggleButton.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/button';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/button/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {ToggleButton} from '@react-spectrum/button';
import {View} from '@react-spectrum/view';
```

---
category: Buttons
keywords: [toggle button]
---

# ToggleButton

<PageDescription>{docs.exports.ToggleButton.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ToggleButton']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/action-button/'}
  ]}
  since="3.2.0" />

## Example

```tsx example
<ToggleButton>Pin</ToggleButton>
```

## Content

ToggleButtons can have a label, an icon, or both. An icon is provided by passing an icon component as a child to the ToggleButton.
A visible label can be provided by passing a string or a Text component as a child, depending on whether the ToggleButton has an accompanying icon.

```tsx example
import {Text} from '@react-spectrum/text';
import Pin from '@spectrum-icons/workflow/PinOff';

<ToggleButton>
  <Pin />
  <Text>Icon + Label</Text>
</ToggleButton>
```

### Accessibility

If no visible label is provided (e.g. an icon only button),
an alternative text label must be provided to identify the control for accessibility. This should be added using
the `aria-label` prop.

```tsx example
<ToggleButton aria-label="Icon only">
  <Pin />
</ToggleButton>
```

**Note:** `ToggleButton` should not be used when the content of the button changes between selection states, for example,
mute/unmute or play/pause. In these cases, use an [ActionButton](ActionButton.html) instead.

### Internationalization

In order to internationalize an ToggleButton, a localized string should be passed to the `children` or `aria-label` prop.

## Value

ToggleButtons are not selected by default. The `defaultSelected` prop can be used to set the default state (uncontrolled).
Alternatively, the `isSelected` prop can be used to make the selected state controlled. See React's documentation on
[uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html) for more info, and [Events](#events), below,
for an example of controlled behavior.

## Events

ToggleButtons support user interactions via mouse, keyboard, and touch. When pressing the button, the selection
state is toggled, and the `onChange` event is fired. The following example uses an `onChange` handler to update React state.

```tsx example
function Example() {
  let [isSelected, setSelected] = React.useState(false);

  return (
    <ToggleButton
      isEmphasized
      isSelected={isSelected}
      onChange={setSelected}
      aria-label="Pin">
      <Pin />
    </ToggleButton>
  );
}
```

## Props

<PropTable component={docs.exports.ToggleButton} links={docs.links} />

## Visual options

### Quiet
[View guidelines](https://spectrum.adobe.com/page/action-button/#Quiet)

```tsx example
<ToggleButton isQuiet>Pin</ToggleButton>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/action-button/#Disabled)

```tsx example
<ToggleButton isDisabled>Pin</ToggleButton>
```

### Emphasized
[View guidelines](https://spectrum.adobe.com/page/action-button/#Emphasis)

```tsx example
<ToggleButton isEmphasized defaultSelected>Pin</ToggleButton>
```

### Static color

The `staticColor` prop can be used when a ToggleButton is displayed over a color background. When selected, the icon and text
automatically take on the color of the background. You are responsible for choosing the static color variant that ensures the
text meets an [accessible contrast ratio](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast)
with the background.

```tsx example
<Flex wrap gap="size-250">
  <View backgroundColor="static-blue-700" padding="size-500">
    <ToggleButton staticColor="white">
      <Pin />
      <Text>Pin</Text>
    </ToggleButton>
  </View>
  <View backgroundColor="static-yellow-400" padding="size-500">
    <ToggleButton staticColor="black" isQuiet defaultSelected>
      <Pin />
      <Text>Pin</Text>
    </ToggleButton>
  </View>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Buttongroup ButtonGroup (`packages/@adobe/react-spectrum/docs/buttongroup/ButtonGroup.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/buttongroup';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/buttongroup/package.json';

---
category: Buttons
keywords: [button group]
---

# ButtonGroup

<PageDescription>{docs.exports.ButtonGroup.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ButtonGroup']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/button-group/'}
  ]}
  since="3.0.0" />

## Example
```tsx example
import {ButtonGroup} from '@react-spectrum/buttongroup';
import {Button} from '@react-spectrum/button';

<ButtonGroup>
  <Button variant="primary">Rate Now</Button>
  <Button variant="secondary">No, thanks</Button>
  <Button variant="secondary">Remind me later</Button>
</ButtonGroup>
```

## Content
ButtonGroup expects [Buttons](./Button.html) as children and is used to handle overflow. When horizontal space is limited, the ButtonGroup switches to a vertical layout. ButtonGroup should be used when there are two or more related Buttons in a group.
To see the orientation switch in the example above, resize the width of your window.

## Props

<PropTable component={docs.exports.ButtonGroup} links={docs.links} />

## Visual options

### Orientation
[View guidelines](https://spectrum.adobe.com/page/button-group/#Orientation)

Setting this to 'vertical' will prevent any dynamic orientation changes, the ButtonGroup will remain in vertical regardless of the available width.
```tsx example
<ButtonGroup orientation="vertical">
  <Button variant="secondary">No, thanks</Button>
  <Button variant="secondary">Remind me later</Button>
  <Button variant="primary">Rate Now</Button>
</ButtonGroup>
```

### Alignment
[View guidelines](https://spectrum.adobe.com/page/button-group/#Align-button-groups-based-on-content)

Button groups are aligned contextually. Generally, button groups should be start-aligned to follow content. However, they should be end-aligned inside container components, such as in dialogs, popovers, or cards. Center alignment should be used in the context of an empty state. In right-to-left languages, alignment is flipped automatically.

```tsx example
<ButtonGroup orientation="vertical" align="end">
  <Button variant="secondary">No, thanks</Button>
  <Button variant="secondary">Remind me later</Button>
  <Button variant="primary">Rate Now</Button>
</ButtonGroup>
```

```tsx example
<ButtonGroup orientation="vertical" align="center">
  <Button variant="secondary">No, thanks</Button>
  <Button variant="secondary">Remind me later</Button>
  <Button variant="primary">Rate Now</Button>
</ButtonGroup>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/button-group/#Disabled)

```tsx example
<ButtonGroup isDisabled>
  <Button variant="secondary">No, thanks</Button>
  <Button variant="secondary">Remind me later</Button>
  <Button variant="primary">Rate Now</Button>
</ButtonGroup>
```

---

### Packages @Adobe React Spectrum Docs Calendar Calendar (`packages/@adobe/react-spectrum/docs/calendar/Calendar.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/calendar';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/calendar/package.json';

```jsx import
import {Calendar} from '@react-spectrum/calendar';
import {Flex} from '@react-spectrum/layout';
import {ActionButton} from '@adobe/react-spectrum';
```

---
category: Date and Time
keywords: [date]
---

# Calendar

<PageDescription>{docs.exports.Calendar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Calendar']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<Calendar aria-label="Event date" />
```

## Value

A `Calendar` has no selection by default. An initial, uncontrolled value can be provided to the `Calendar` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Date values are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns.

`Calendar` supports values with both date and time components, but only allows users to modify the date. By default, `Calendar` will emit <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDate} /> objects in the `onChange` event, but if a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is passed as the `value` or `defaultValue`, values of that type will be emitted, changing only the date and preserving the time components.

```tsx example
import {parseDate} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState(parseDate('2020-02-03'));

  return (
    <Flex gap="size-300" wrap>
      <Calendar
        aria-label="Date (uncontrolled)"
        defaultValue={parseDate('2020-02-03')} />
      <Calendar
        aria-label="Date (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### International calendars

`Calendar` supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component.

Selected dates passed to `onChange` always use the same calendar system as the `value` or `defaultValue` prop. If no `value` or `defaultValue` is provided, then dates passed to `onChange` are always in the Gregorian calendar since this is the most commonly used. This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.

The below example displays a `Calendar` in the Hindi language, using the Indian calendar. Dates emitted from `onChange` are in the Gregorian calendar.

```tsx example
import {Provider} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(null);
  return (
    <Provider locale="hi-IN-u-ca-indian">
      <Calendar aria-label="Date" value={date} onChange={setDate} />
      <p>Selected date: {date?.toString()}</p>
    </Provider>
  );
}
```

### Custom calendar systems

`Calendar` also supports custom calendar systems that implement custom business rules. An example would be a fiscal year calendar that follows a [4-5-4 format](https://nrf.com/resources/4-5-4-calendar), where month ranges don't follow the usual Gregorian calendar.

The `createCalendar` prop accepts a function that returns an instance of the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.Calendar} /> interface. See the [@internationalized/date docs](react-aria:internationalized/date/Calendar#custom-calendars) for an example implementation.

```tsx import
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar} from '@internationalized/date';
```

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Labeling

An aria-label must be provided to the `Calendar` for accessibility. If it is labeled by a separate element, an `aria-labelledby` prop must be provided using the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `Calendar`, a localized string should be passed to the `aria-label` prop. For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the `Calendar` is automatically flipped. Dates are automatically formatted using the current locale.

## Events

`Calendar` accepts an `onChange` prop which is triggered whenever a date is selected by the user. The example below uses `onChange` to update a separate element with a formatted version of the date in the user's locale. This is done by converting the date to a native JavaScript `Date` object to pass to the formatter.

```tsx example
import {getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(parseDate('2022-07-04'));
  let formatter = useDateFormatter({dateStyle: 'full'});

  return (
    <>
      <Calendar aria-label="Event date" value={date} onChange={setDate} />
      <p>Selected date: {formatter.format(date.toDate(getLocalTimeZone()))}</p>
    </>
  );
}
```

## Validation

By default, `Calendar` allows selecting any date. The `minValue` and `maxValue` props can also be used to prevent the user from selecting dates outside a certain range.

This example only accepts dates after today.

```tsx example
import {today} from '@internationalized/date';

<Calendar aria-label="Appointment date" minValue={today(getLocalTimeZone())} />
```

### Unavailable dates

`Calendar` supports marking certain dates as _unavailable_. These dates cannot be selected by the user and are displayed with a crossed out appearance. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable.

This example includes multiple unavailable date ranges, e.g. dates when no appointments are available. In addition, all weekends are unavailable. The `minValue` prop is also used to prevent selecting dates before today.


```tsx example
import {today, isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let now = today(getLocalTimeZone());
  let disabledRanges = [
    [now, now.add({days: 5})],
    [now.add({days: 14}), now.add({days: 16})],
    [now.add({days: 23}), now.add({days: 24})],
  ];

  let {locale} = useLocale();
  let isDateUnavailable = (date) => isWeekend(date, locale) || disabledRanges.some((interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0);

  return <Calendar aria-label="Appointment date" minValue={today(getLocalTimeZone())} isDateUnavailable={isDateUnavailable} />
}
```

## Controlling the focused date

By default, the selected date is focused when a `Calendar` first mounts. If no `value` or `defaultValue` prop is provided, then the current date is focused.  However, `Calendar` supports controlling which date is focused using the `focusedValue` and `onFocusChange` props. This also determines which month is visible. The `defaultFocusedValue` prop allows setting the initial focused date when the `Calendar` first mounts, without controlling it.

This example focuses July 1, 2021 by default. The user may change the focused date, and the `onFocusChange` event updates the state. Clicking the button resets the focused date back to the initial value.

```tsx example
import {CalendarDate} from '@internationalized/date';

function Example() {
  let defaultDate = new CalendarDate(2021, 7, 1);
  let [focusedDate, setFocusedDate] = React.useState(defaultDate);

  return (
    <Flex direction="column" alignItems="start" gap="size-200">
      <ActionButton onPress={() => setFocusedDate(defaultDate)}>Reset focused date</ActionButton>
      <Calendar focusedValue={focusedDate} onFocusChange={setFocusedDate} />
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.Calendar} links={docs.links} />

## Visual options

### Disabled

```tsx example
<Calendar aria-label="Event date" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the Calendar's value immutable. Unlike `isDisabled`, the Calendar remains focusable.

```tsx example
<Calendar aria-label="Event date" value={today(getLocalTimeZone())} isReadOnly />
```

### Visible months

By default, the `Calendar` displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <Calendar aria-label="Event date" visibleMonths={3} />
</div>
```

### Page behavior

By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <Calendar aria-label="Event date" visibleMonths={3} pageBehavior="single" />
</div>
```

### Custom first day of week

By default, the first day of the week is automatically set based on the current locale. This can be changed by setting the `firstDayOfWeek` prop to `'sun'`, `'mon'`, `'tue'`, `'wed'`, `'thu'`, `'fri'`, or `'sat'`.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <Calendar aria-label="Event date" firstDayOfWeek="mon" />
</div>
```

---

### Packages @Adobe React Spectrum Docs Calendar RangeCalendar (`packages/@adobe/react-spectrum/docs/calendar/RangeCalendar.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/calendar';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/calendar/package.json';

```jsx import
import {RangeCalendar} from '@react-spectrum/calendar';
import {Flex} from '@react-spectrum/layout';
import {ActionButton} from '@adobe/react-spectrum';
```

---
category: Date and Time
keywords: [date]
---

# RangeCalendar

<PageDescription>{docs.exports.RangeCalendar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['RangeCalendar']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<RangeCalendar aria-label="Trip dates" />
```

## Value

A `RangeCalendar` has no selection by default. An initial, uncontrolled value can be provided to the `RangeCalendar` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Date ranges are objects with `start` and `end` properties containing date values, which are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns.

`RangeCalendar` supports values with both date and time components, but only allows users to modify the dates. By default, `RangeCalendar` will emit <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDate} /> objects in the `onChange` event, but if a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is passed as the `value` or `defaultValue`, values of that type will be emitted, changing only the date and preserving the time components.

```tsx example
import {parseDate} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState({
    start: parseDate('2020-02-03'),
    end: parseDate('2020-02-12')
  });

  return (
    <Flex gap="size-300" wrap>
      <RangeCalendar
        aria-label="Date range (uncontrolled)"
        defaultValue={{
          start: parseDate('2020-02-03'),
          end: parseDate('2020-02-12')
        }} />
      <RangeCalendar
        aria-label="Date range (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### International calendars

`RangeCalendar` supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component.

Selected dates passed to `onChange` always use the same calendar system as the `value` or `defaultValue` prop. If no `value` or `defaultValue` is provided, then dates passed to `onChange` are always in the Gregorian calendar since this is the most commonly used. This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.

The below example displays a `RangeCalendar` in the Hindi language, using the Indian calendar. Dates emitted from `onChange` are in the Gregorian calendar.

```tsx example
import {Provider} from '@adobe/react-spectrum';

function Example() {
  let [range, setRange] = React.useState(null);
  return (
    <Provider locale="hi-IN-u-ca-indian">
      <RangeCalendar aria-label="Date range" value={range} onChange={setRange} />
      <p>Start date: {range?.start.toString()}</p>
      <p>End date: {range?.end.toString()}</p>
    </Provider>
  );
}
```

### Custom calendar systems

`RangeCalendar` also supports custom calendar systems that implement custom business rules. An example would be a fiscal year calendar that follows a [4-5-4 format](https://nrf.com/resources/4-5-4-calendar), where month ranges don't follow the usual Gregorian calendar.

The `createCalendar` prop accepts a function that returns an instance of the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.Calendar} /> interface. See the [@internationalized/date docs](react-aria:internationalized/date/Calendar#custom-calendars) for an example implementation.

```tsx import
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar} from '@internationalized/date';
```

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Labeling

An aria-label must be provided to the `RangeCalendar` for accessibility. If it is labeled by a separate element, an `aria-labelledby` prop must be provided using the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `RangeCalendar`, a localized string should be passed to the `aria-label` prop. For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the `RangeCalendar` is automatically flipped. Dates are automatically formatted using the current locale.

## Events

`RangeCalendar` accepts an `onChange` prop which is triggered whenever a date is selected by the user. The example below uses `onChange` to update a separate element with a formatted version of the date in the user's locale. This is done by converting the date to a native JavaScript `Date` object to pass to the formatter.

```tsx example
import {getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [range, setRange] = React.useState({
    start: parseDate('2020-07-03'),
    end: parseDate('2020-07-10')
  });
  let formatter = useDateFormatter({dateStyle: 'long'});

  return (
    <>
      <RangeCalendar aria-label="Date range" value={range} onChange={setRange} />
      <p>
        Selected date:{' '}
        {formatter.formatRange(
          range.start.toDate(getLocalTimeZone()),
          range.end.toDate(getLocalTimeZone())
        )}
      </p>
    </>
  );
}
```

## Validation

By default, `RangeCalendar` allows selecting any date range. The `minValue` and `maxValue` props can also be used to prevent the user from selecting dates outside a certain range.

This example only accepts dates after today.

```tsx example
import {today} from '@internationalized/date';

<RangeCalendar aria-label="Trip dates" minValue={today(getLocalTimeZone())} />
```

### Unavailable dates

`RangeCalendar` supports marking certain dates as _unavailable_. These dates cannot be selected by the user and are displayed with a crossed out appearance. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable.

Note that by default, users may not select non-contiguous ranges, i.e. ranges that contain unavailable dates within them. Once a start date is selected, enabled dates will be restricted to subsequent dates until an unavailable date is hit. See [below](#non-contiguous-ranges) for an example of how to allow non-contiguous ranges.

This example includes multiple unavailable date ranges, e.g. dates when a rental house is not available. The `minValue` prop is also used to prevent selecting dates before today.

```tsx example
import {today} from '@internationalized/date';

function Example() {
  let now = today(getLocalTimeZone());
  let disabledRanges = [
    [now, now.add({days: 5})],
    [now.add({days: 14}), now.add({days: 16})],
    [now.add({days: 23}), now.add({days: 24})],
  ];

  let isDateUnavailable = (date) => disabledRanges.some((interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0);

  return <RangeCalendar aria-label="Trip dates" minValue={today(getLocalTimeZone())} isDateUnavailable={isDateUnavailable} />
}
```

### Non-contiguous ranges

The `allowsNonContiguousRanges` prop enables a range to be selected even if there are unavailable dates in the middle. The value emitted in the `onChange` event will still be a single range with a `start` and `end` property, but unavailable dates will not be displayed as selected. It is up to applications to split the full selected range into multiple as needed for business logic.

This example prevents selecting weekends, but allows selecting ranges that span multiple weeks.

```tsx example
import {isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let {locale} = useLocale();

  return <RangeCalendar aria-label="Time off request" isDateUnavailable={date => isWeekend(date, locale)} allowsNonContiguousRanges />
}
```

## Controlling the focused date

By default, the first selected date is focused when a `RangeCalendar` first mounts. If no `value` or `defaultValue` prop is provided, then the current date is focused.  However, `RangeCalendar` supports controlling which date is focused using the `focusedValue` and `onFocusChange` props. This also determines which month is visible. The `defaultFocusedValue` prop allows setting the initial focused date when the `RangeCalendar` first mounts, without controlling it.

This example focuses July 1, 2021 by default. The user may change the focused date, and the `onFocusChange` event updates the state. Clicking the button resets the focused date back to the initial value.

```tsx example
import {CalendarDate} from '@internationalized/date';

function Example() {
  let defaultDate = new CalendarDate(2021, 7, 1);
  let [focusedDate, setFocusedDate] = React.useState(defaultDate);

  return (
    <Flex direction="column" alignItems="start" gap="size-200">
      <ActionButton onPress={() => setFocusedDate(defaultDate)}>Reset focused date</ActionButton>
      <RangeCalendar focusedValue={focusedDate} onFocusChange={setFocusedDate} />
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.RangeCalendar} links={docs.links} />

## Visual options

### Disabled

```tsx example
<RangeCalendar aria-label="Trip dates" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the RangeCalendar's value immutable. Unlike `isDisabled`, the RangeCalendar remains focusable.

```tsx example
<RangeCalendar aria-label="Trip dates" value={{start: today(getLocalTimeZone()), end: today(getLocalTimeZone()).add({ weeks: 1 })}} isReadOnly />
```

### Visible months

By default, a `RangeCalendar` displays a single month. The `visibleMonths` prop allows displaying up to 3 months at a time.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <RangeCalendar aria-label="Trip dates" visibleMonths={3} />
</div>
```

### Page behavior

By default, when pressing the next or previous buttons, pagination will advance by the `visibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <RangeCalendar aria-label="Trip dates" visibleMonths={3} pageBehavior="single" />
</div>
```

### Custom first day of week

By default, the first day of the week is automatically set based on the current locale. This can be changed by setting the `firstDayOfWeek` prop to `'sun'`, `'mon'`, `'tue'`, `'wed'`, `'thu'`, `'fri'`, or `'sat'`.

```tsx example
<div style={{maxWidth: '100%', overflow: 'auto'}}>
  <RangeCalendar aria-label="Trip dates" firstDayOfWeek="mon" />
</div>
```

---

### Packages @Adobe React Spectrum Docs Checkbox Checkbox (`packages/@adobe/react-spectrum/docs/checkbox/Checkbox.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/checkbox';
import packageData from '@react-spectrum/checkbox/package.json';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';

```jsx import
 import {Checkbox} from '@react-spectrum/checkbox';
 import {View} from '@react-spectrum/view';
 import {Flex} from '@react-spectrum/layout';
 ```

---
category: Forms
keywords: [input]
---

# Checkbox

<PageDescription>{docs.exports.Checkbox.description}</PageDescription>

<HeaderInfo
 packageData={packageData}
 componentNames={['Checkbox']}
 sourceData={[
 {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/checkbox/'}
 ]}
 since="3.0.0" />

## Example

```tsx example
<Checkbox>Unsubscribe</Checkbox>
```

## Content

Checkboxes accept children, which are rendered as the label.

### Accessibility

In certain cases a visible label isn't needed. For example, a checkbox used to select a table row.
If a visible label isn't specified, an `aria-label` must be provided to the Checkbox for accessibility.
If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

### Internationalization

To internationalize a Checkbox, a localized label should be passed to the `children` or `aria-label` prop.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the checkbox is automatically flipped.

## Value

Checkboxes are not selected by default. The `defaultSelected` prop can be used to set the default state (uncontrolled).
Alternatively, the `isSelected` prop can be used to make the selected state controlled. See React's documentation on [uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html) for more info.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState(true);

  return (
    <Flex direction="row">
      <Checkbox defaultSelected>Subscribe (uncontrolled)</Checkbox>
      <Checkbox isSelected={selected} onChange={setSelected}>Subscribe (controlled)</Checkbox>
    </Flex>
  );
}
```

### Indeterminate
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Mixed-value)

A Checkbox can be in an indeterminate state, controlled using the `isIndeterminate` prop.
This overrides the appearance of the Checkbox, whether selection is controlled or uncontrolled.
The Checkbox will visually remain indeterminate until the `isIndeterminate` prop is set to false, regardless of user interaction.

```tsx example
<Checkbox isIndeterminate>Subscribe</Checkbox>
```

### HTML forms

Checkbox supports the `name` and `value` props for integration with HTML forms.

```tsx example
<Checkbox name="newsletter" value="subscribe">Subscribe</Checkbox>
```

## Events

Checkboxes accept a user defined `onChange` prop, triggered whenever the Checkbox is clicked.
The example below uses `onChange` to alert the user to changes in the checkbox's state.

```tsx example
function Example() {
  let [selected, setSelection] = React.useState(false);

  return (
    <Flex direction="column">
      <Checkbox isSelected={selected} onChange={setSelection}>
        Subscribe
      </Checkbox>
      <View>{`You are ${selected ? 'subscribed' : 'unsubscribed'}`}</View>
    </Flex>
  );
 }
```

## Validation

Checkboxes can display a validation state to communicate to the user if the current value is invalid.
Implement your own validation logic in your app and set the `isInvalid` prop accordingly.
The invalid state is only communicated via a color change so in order to be accessible the validation error must also be communicated in another way.
```tsx example
<Checkbox isInvalid>I accept the terms and conditions</Checkbox>
```

## Props

<PropTable component={docs.exports.Checkbox} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Disabled)

```tsx example
<Checkbox isDisabled>Subscribe</Checkbox>
```

### Emphasized
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Emphasized-or-not?)

```tsx example
<Checkbox isEmphasized defaultSelected>Subscribe</Checkbox>
```

---

### Packages @Adobe React Spectrum Docs Checkbox CheckboxGroup (`packages/@adobe/react-spectrum/docs/checkbox/CheckboxGroup.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/checkbox';
import packageData from '@react-spectrum/checkbox/package.json';
import {HeaderInfo, PropTable, PageDescription, VersionBadge, ClassAPI} from '@react-spectrum/docs';

```jsx import
 import {Checkbox, CheckboxGroup} from '@react-spectrum/checkbox';
 import {Flex} from '@react-spectrum/layout';
 ```

---
category: Forms
keywords: [input, checkbox group, accessibility]
after_version: 3.1.0
---

# CheckboxGroup

<PageDescription>{docs.exports.CheckboxGroup.description}</PageDescription>

<HeaderInfo
 packageData={packageData}
 componentNames={['CheckboxGroup', 'Checkbox']}
 sourceData={[
 {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/checkbox/'}
 ]}
 since="3.0.0" />

## Example

```tsx example
<CheckboxGroup label="Favorite sports">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

## Content

CheckboxGroup accepts multiple [Checkbox](Checkbox.html) elements as children.
Each Checkbox represents an option that can be selected, labeled by its children.

## Value

CheckboxGroup supports selecting zero or more items. An initial, uncontrolled value can be provided to the CheckboxGroup using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop. Both of these props accept an array of selected items, which map to the
`value` prop on each item.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState(['soccer', 'baseball']);

  return (
    <Flex gap="size-300">
      <CheckboxGroup label="Favorite sports (uncontrolled)" defaultValue={['soccer', 'baseball']}>
        <Checkbox value="soccer">Soccer</Checkbox>
        <Checkbox value="baseball">Baseball</Checkbox>
        <Checkbox value="basketball">Basketball</Checkbox>
      </CheckboxGroup>

      <CheckboxGroup label="Favorite sports (controlled)" value={selected} onChange={setSelected}>
        <Checkbox value="soccer">Soccer</Checkbox>
        <Checkbox value="baseball">Baseball</Checkbox>
        <Checkbox value="basketball">Basketball</Checkbox>
      </CheckboxGroup>
    </Flex>
  );
}
```

### HTML forms

CheckboxGroup supports the `name` prop, paired with the Checkbox `value` prop, for integration with HTML forms.

```tsx example
<CheckboxGroup label="Condiments" name="condiments">
  <Checkbox value="mayo">Mayo</Checkbox>
  <Checkbox value="mustart">Mustard</Checkbox>
  <Checkbox value="ketchup">Ketchup</Checkbox>
</CheckboxGroup>
```

## Labeling
A visual label should be provided for the CheckboxGroup using the `label` prop. If the CheckboxGroup requires an option to be selected by the user,
the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-300" wrap>
  <CheckboxGroup label="Favorite sports">
    <Checkbox value="soccer">Soccer</Checkbox>
    <Checkbox value="baseball">Baseball</Checkbox>
    <Checkbox value="basketball">Basketball</Checkbox>
  </CheckboxGroup>
  <CheckboxGroup label="Favorite sports" isRequired necessityIndicator="icon">
    <Checkbox value="soccer">Soccer</Checkbox>
    <Checkbox value="baseball">Baseball</Checkbox>
    <Checkbox value="basketball">Basketball</Checkbox>
  </CheckboxGroup>
  <CheckboxGroup label="Favorite sports" isRequired necessityIndicator="label">
    <Checkbox value="soccer">Soccer</Checkbox>
    <Checkbox value="baseball">Baseball</Checkbox>
    <Checkbox value="basketball">Basketball</Checkbox>
  </CheckboxGroup>
  <CheckboxGroup label="Favorite sports" necessityIndicator="label">
    <Checkbox value="soccer">Soccer</Checkbox>
    <Checkbox value="baseball">Baseball</Checkbox>
    <Checkbox value="basketball">Basketball</Checkbox>
  </CheckboxGroup>
</Flex>
```

### Accessibility

If a visible label isn't specified for a CheckboxGroup, an `aria-label` must be provided for accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

Checkbox elements within a group should always have a visible label.

### Internationalization

To internationalize a CheckboxGroup, a localized string should be passed to the `label` prop and as the child content of the Checkbox elements.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the Checkbox is automatically placed on the right side of the text. When the necessityIndicator prop is set to "label", a localized string will be provided for "(required)" or "(optional)" automatically.

## Events

CheckboxGroup accepts an `onChange` prop, which is triggered when a user adds or removes an item from the selection.
The example below uses `onChange` to log how the user is interacting with the component.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState([]);

  return (
    <>
      <CheckboxGroup label="Favorite sports" value={selected} onChange={setSelected}>
        <Checkbox value="soccer">Soccer</Checkbox>
        <Checkbox value="baseball">Baseball</Checkbox>
        <Checkbox value="basketball">Basketball</Checkbox>
      </CheckboxGroup>
      <div>You have selected: {selected.join(', ')}</div>
    </>
  );
}
```

## Validation

CheckboxGroup supports the `isRequired` prop to ensure the user selects at least one item, as well as custom client and server-side validation. Individual checkboxes also support validation, and errors from all checkboxes are aggregated at the group level. CheckboxGroup can also be integrated with other form libraries. See the [Forms](../forms) guide to learn more.

### Group validation

The `isRequired` prop at the `CheckboxGroup` level requires that at least one item is selected. When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native">
  {/*- begin highlight -*/}
  <CheckboxGroup label="Sandwich condiments" name="condiments" isRequired>
  {/*- end highlight -*/}
    <Checkbox value="lettuce">Lettuce</Checkbox>
    <Checkbox value="tomato">Tomato</Checkbox>
    <Checkbox value="onion">Onion</Checkbox>
    <Checkbox value="sprouts">Sprouts</Checkbox>
  </CheckboxGroup>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `CheckboxGroup` displays default validation messages provided by the browser. See [Customizing error messages](../forms#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

### Individual Checkbox validation

To require that specific checkboxes are checked, set the `isRequired` prop at the `Checkbox` level instead of the `CheckboxGroup`. The following example shows how to require that all items are selected.

```tsx example
<Form validationBehavior="native">
  <CheckboxGroup label="Agree to the following" isRequired>
    {/*- begin highlight -*/}
    <Checkbox value="terms" isRequired>Terms and conditions</Checkbox>
    <Checkbox value="privacy" isRequired>Privacy policy</Checkbox>
    <Checkbox value="cookies" isRequired>Cookie policy</Checkbox>
    {/*- end highlight -*/}
  </CheckboxGroup>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

## Props

<PropTable component={docs.exports.CheckboxGroup} links={docs.links} />

## Visual options

### Orientation

CheckboxGroups are vertically oriented by default.
The `orientation` prop can be used to change the orientation to horizontal.

```tsx example
<CheckboxGroup label="Favorite sports" orientation="horizontal">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Label position and alignment

By default, the label is positioned above the CheckboxGroup.
The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can
be used to align the label as "start" or "end".
For left-to-right (LTR) languages, "start" refers to the left most edge of the CheckboxGroup
and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<CheckboxGroup label="Favorite sports" labelPosition="side" labelAlign="end">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/checkbox-group/#Help-text-(description-and-error-message))

Both a description and an error message can be supplied to a CheckboxGroup. The description is always visible unless the `isInvalid` is true and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
  let [checked, setChecked] = React.useState(['dogs', 'dragons']);
  let isValid = checked.length === 2 && checked.includes('dogs') && checked.includes('dragons');

  return (
    <CheckboxGroup
      label="Pets"
      onChange={setChecked}
      value={checked}
      isInvalid={!isValid}
      description="Select your pets."
      errorMessage={
        checked.includes('cats')
          ? 'No cats allowed.'
          : 'Select only dogs and dragons.'
      }>
      <Checkbox value="dogs">Dogs</Checkbox>
      <Checkbox value="cats">Cats</Checkbox>
      <Checkbox value="dragons">Dragons</Checkbox>
    </CheckboxGroup>
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a CheckboxGroup.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<CheckboxGroup
  label="Favorite genres"
  contextualHelp={
    <ContextualHelp>
      <Heading>What does this do?</Heading>
      <Content>Your musical taste is used to train our machine learning recommendation algorithm.</Content>
    </ContextualHelp>
  }>
  <Checkbox value="rock">Rock</Checkbox>
  <Checkbox value="pop">Pop</Checkbox>
  <Checkbox value="classical">Classical</Checkbox>
</CheckboxGroup>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Disabled)

```tsx example
<CheckboxGroup label="Favorite sports" isDisabled>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

```tsx example
<CheckboxGroup label="Favorite sports">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball" isDisabled>Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Read only
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Read-only)

The `isReadOnly` prop makes the selection immutable. Unlike `isDisabled`, the CheckboxGroup remains focusable.
See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<CheckboxGroup label="Favorite sports" defaultValue={['baseball']} isReadOnly>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Emphasized
[View guidelines](https://spectrum.adobe.com/page/checkbox/#Emphasis)

```tsx example
<CheckboxGroup label="Favorite sports" defaultValue={['soccer', 'baseball']} isEmphasized>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

---

### Packages @Adobe React Spectrum Docs Color ColorArea (`packages/@adobe/react-spectrum/docs/color/ColorArea.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import colorTypes from 'docs:@react-stately/color';
import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorArea, ColorSlider, ColorWheel} from '@react-spectrum/color';
import {Flex, Grid} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';
import {View} from '@react-spectrum/view';
```

---
category: Color
keywords: [color area]
---

# ColorArea

<PageDescription>{docs.exports.ColorArea.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorArea']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/color-area/'}
  ]}
  since="3.35.0" />

## Example

```tsx example
<ColorArea defaultValue="#7f0000" />
```

## Value

A ColorArea requires either an uncontrolled default value or a controlled value, provided using the `defaultValue` or `value` props respectively.
The value provided to either of these props should be a color string or <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object.
`xChannel` and `yChannel` props may also be provided to specify which color channels the color area should display, and the direction of each channel in the color gradient.
This must be one of the channels included in the color value, for example, for RGB colors, the "red", "green", and "blue" channels are available.
For a full list of supported channels, see the [Props](#props) table below.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from a HSL string
so that `value`'s type remains consistent.

```tsx example
import {ColorArea} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';
import {parseColor} from '@react-stately/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('hsl(0, 100%, 50%)'));
  return (
    <Flex gap="size-300" wrap>
      <div>
        <Label id="hsl-uncontrolled-id">x: Saturation, y: Lightness (uncontrolled)</Label>
        <ColorArea
          aria-labelledby="hsl-uncontrolled-id"
          defaultValue={value}
          xChannel="saturation"
          yChannel="lightness" />
      </div>
      <div>
        <Label id="hsl-controlled-id">x: Saturation, y: Lightness (controlled)</Label>
        <ColorArea
          aria-labelledby="hsl-controlled-id"
          value={value}
          onChange={setValue}
          xChannel="saturation"
          yChannel="lightness" />
      </div>
    </Flex>
  );
}
```

### HTML forms

ColorArea supports the `xName` and `yName` props for integration with HTML forms. The values will be submitted as numbers between the minimum and maximum value for the corresponding channel in the X and Y direction.

```tsx example
<ColorArea xName="red" yName="green" />
```

## Labeling

By default, ColorArea uses an `aria-label` for the localized string "Color Picker",
which labels the visually hidden `<input>` elements for the two color channels, or on mobile devices,
the group containing them. If you wish to override this with a more specific label, an `aria-label` or
`aria-labelledby` prop may be passed to further identify the element to assistive technologies.
For example, for a ColorArea that adjusts a background color you might pass the `aria-label` prop,
"Background color", which ColorArea will return as the `aria-label` prop "Background color, Color picker". If you provide your own
`aria-label` or `aria-labelledby`, be sure to localize the string or labeling element appropriately.

Note that like [ColorWheel](ColorWheel.html), ColorArea does not include an integrated visible label or a `label` prop.
Use `aria-labelledby` to label the ColorArea using the IDREF assigned to a visible label.

```tsx example
import {ColorArea} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';

<Flex gap="size-300" wrap alignItems="end">
  <ColorArea
    aria-label="Background color"
    defaultValue="hsl(0, 100%, 50%)"
    xChannel="saturation"
    yChannel="lightness" />
  <div>
    <Label
      id="hsl-aria-labelledby-id">Background color</Label>
    <ColorArea
      aria-labelledby="hsl-aria-labelledby-id"
      defaultValue="hsl(0, 100%, 50%)"
      xChannel="saturation"
      yChannel="lightness" />
  </div>
</Flex>
```

### Accessibility

#### Role description

In order to communicate to a screen reader user that the ColorArea adjusts in two dimensions,
ColorArea provides an `aria-roledescription`, using the localized string "2D Slider", on each of the
visually hidden `<input>` elements.

#### Value formatting

The `aria-valuetext` of each `<input>` element within the ColorArea is formatted according to the user's locale automatically.
It will include the localized color channel name and current value for each channel, with the channel name
and value that the `<input>` element controls coming before the channel name and value for the adjacent
`<input>` element. For example, for an RGB ColorArea where the `xChannel` is "blue", the `yChannel`
is "green", when the current selected color is yellow (`rgb(255, 255, 0)`), the `<input>` representing the
blue channel will have `aria-valuetext` to announce as "Blue: 0, Green: 255", and the `<input>`
representing the green channel will have `aria-valuetext` to announce as "Green: 255, Blue: 0".

### Internationalization

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ColorArea is automatically flipped. As mentioned previously,
ColorArea automatically uses the current locale to format the `aria-valuetext` for each of the `<input>` element with the channel name and current value.

## Events

ColorArea supports two events: `onChange` and `onChangeEnd`. `onChange` is triggered whenever the ColorArea's handle is dragged, and `onChangeEnd`
is triggered when the user stops dragging the handle. Both events receive a <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object
as a parameter.

The example below uses `onChange` and `onChangeEnd` to update two separate elements with the ColorArea's value.

```tsx example
import {ColorArea} from '@react-spectrum/color';
import {parseColor} from '@react-stately/color';

function Example() {
  let [currentValue, setCurrentValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));
  let [finalValue, setFinalValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));

  return (
    <div>
      <ColorArea
        value={currentValue}
        onChange={setCurrentValue}
        onChangeEnd={setFinalValue} />
      <pre>Current value: {currentValue.toString('hsl')}</pre>
      <pre>Final value: {finalValue.toString('hsl')}</pre>
    </div>
  );
}
```

## Creating a color picker

To build a fully functional color picker, combine a ColorArea, which adjusts two channels of a color value stored in state, with a separate control, like a [ColorSlider](ColorSlider.html) or [ColorWheel](ColorWheel.html), for
adjusting the value of the third channel within the color space for the color value stored in state.
The current color space for a color can be returned using the `color.getColorSpace` method.
An array of channel names for a color can be returned using the `color.getColorChannels` method.
To get a localized channel name to use as a label, you can use the `color.getChannelName` method.


### RGBA

This example shows how you could build an RGB color picker using a color area and color sliders bound to the same
color value in state. The <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} />
function is used to parse the initial color from a hex value, stored in state. The `value` and `onChange` props
of both the ColorArea and ColorSlider are used to make the components controlled, so that they both update when the
color is modified.

```tsx example
import {ColorArea, ColorSlider} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';
import {parseColor} from '@react-stately/color';

function Example() {
  let [color, setColor] = React.useState(parseColor('#ff00ff'));
  let [redChannel, greenChannel, blueChannel] = color.getColorChannels();
  return (
    <fieldset style={{border: 0}}>
      <legend>{color.getColorSpace().toUpperCase()}A Example</legend>
      <Flex direction="column">
        <ColorArea xChannel={redChannel} yChannel={greenChannel} value={color} onChange={setColor} />
        <ColorSlider channel={blueChannel} value={color} onChange={setColor} />
        <ColorSlider channel="alpha" value={color} onChange={setColor} />
        <p>Current value: {color.toString('css')}</p>
      </Flex>
    </fieldset>
  );
}
```

### HSLA

This example shows how to build a similar color picker to the one above, using HSLA colors instead,
and a ColorWheel instead of a ColorSlider for the Hue channel.

```tsx example
import {ColorArea, ColorSlider, ColorWheel} from '@react-spectrum/color';
import {Flex, Grid} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';
import {parseColor} from '@react-stately/color';
import {View} from '@react-spectrum/view';

function Example() {
  let [color, setColor] = React.useState(parseColor('hsla(0, 100%, 50%, 0.5)'));
  let [, saturationChannel, lightnessChannel] = color.getColorChannels();
  return (
    <fieldset style={{border: 0}}>
      <legend>HSLA Example</legend>
      <Flex
        direction="column">
        <View
          position="relative"
          width="size-2400">
          <Grid
            position="absolute"
            justifyContent="center"
            alignContent="center"
            width="100%"
            height="100%">
            <ColorArea
              xChannel={saturationChannel}
              yChannel={lightnessChannel}
              value={color}
              onChange={setColor}
              size="size-1200" />
          </Grid>
          <ColorWheel
            value={color}
            onChange={setColor}
            size="size-2400" />
        </View>
        <ColorSlider channel="alpha" value={color} onChange={setColor} />
        <p>Current value: {color.toString('hsla')}</p>
      </Flex>
    </fieldset>
  );
}
```

### HSBA

This example shows how to build an HSBA color picker.

```tsx example
import {ColorArea, ColorSlider, ColorWheel} from '@react-spectrum/color';
import {Flex, Grid} from '@react-spectrum/layout';
import {Label} from '@react-spectrum/label';
import {parseColor} from '@react-stately/color';
import {View} from '@react-spectrum/view';

function Example() {
  let [color, setColor] = React.useState(parseColor('hsba(0, 100%, 50%, 0.5)'));
  let [, saturationChannel, brightnessChannel] = color.getColorChannels();
  return (
    <fieldset style={{border: 0}}>
      <legend>HSBA Example</legend>
      <Flex
        direction="column">
        <View
          position="relative"
          width="size-2400">
          <Grid
            position="absolute"
            justifyContent="center"
            alignContent="center"
            width="100%"
            height="100%">
            <ColorArea
              xChannel={saturationChannel}
              yChannel={brightnessChannel}
              value={color}
              onChange={setColor}
              size="size-1200" />
          </Grid>
          <ColorWheel
            value={color}
            onChange={setColor}
            size="size-2400" />
        </View>
        <ColorSlider channel="alpha" value={color} onChange={setColor} />
        <p>Current value: {color.toString('hsba')}</p>
      </Flex>
    </fieldset>
  );
}
```

## Props

<PropTable component={docs.exports.ColorArea} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/color-area/#Disabled)

```tsx example
import {ColorArea} from '@react-spectrum/color';

<ColorArea defaultValue="#7f0000" isDisabled />
```

### Custom Size
[View guidelines](https://spectrum.adobe.com/page/color-area/#Width)

```tsx example
import {ColorArea} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';

<Flex direction="column" gap="size-300">
  <ColorArea defaultValue="#7f0000" size="size-3600" maxWidth="100%" />
</Flex>
```

## Testing

The ColorArea features a draggable handle that the user can interact with to change its color value.
Please see the following section in the testing docs for more information on how to simulate this action in your
test suite.

[Simulating move event](./testing.html#simulating-move-event)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/color/test/ColorArea.test.tsx) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Color ColorField (`packages/@adobe/react-spectrum/docs/color/ColorField.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

```jsx import
import {ColorField} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
```

---
category: Color
keywords: [color field, input]
---

# ColorField

<PageDescription>{docs.exports.ColorField.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorField']}
  sourceData={[]}
  since="3.35.0" />

## Example

```tsx example
<ColorField label="Primary Color" />
```

## Value

A ColorField's `value` is empty by default, but an initial, uncontrolled, value can be provided using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop.  The value provided to either of these props should be a color string or <TypeLink links={statelyDocs.links} type={statelyDocs.exports.Color} /> object.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color
from a hex value, stored in state.

```tsx example
import {parseColor} from '@react-stately/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('#e73623'));

  return (
    <Flex gap="size-150" wrap>
      <ColorField
        label="Primary Color (Uncontrolled)"
        defaultValue="#e21" />

      <ColorField
        label="Primary Color (Controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### HTML forms

ColorField supports the `name` prop for integration with HTML forms. The value will be submitted to the server as a hex color string. When a `channel` prop is provided, the value will be submitted as a number instead.

```tsx example
<ColorField label="Color" name="color" />
```

## Color channel

By default, ColorField allows the user to edit the color as a hex value. When the `colorSpace` and `channel` props are provided, ColorField displays the value for that channel formatted as a number instead. Rendering multiple ColorFields together can allow a user to edit a color.

```tsx example
function Example() {
  let [color, setColor] = React.useState(parseColor('#7f007f'));
  return (
    <>
      <div style={{display: 'flex', gap: 8}}>
        <ColorField label="Hue" value={color} onChange={setColor} colorSpace="hsl" channel="hue" />
        <ColorField label="Saturation" value={color} onChange={setColor} colorSpace="hsl" channel="saturation" />
        <ColorField label="Lightness" value={color} onChange={setColor} colorSpace="hsl" channel="lightness" />
      </div>
      <p>Current color value: {color?.toString('hex')}</p>
    </>
  );
}
```

## Labeling

A visual label should be provided for the ColorField using the `label` prop. If the ColorField is required, the `isRequired` and
`necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <ColorField label="Primary Color" />
  <ColorField label="Primary Color" isRequired />
  <ColorField label="Primary Color" isRequired necessityIndicator="label" />
  <ColorField label="Primary Color" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the ColorField for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a ColorField, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Validation

ColorField supports the `isRequired` prop to ensure the user enters a value, as well as custom validation functions, realtime validation, and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the color field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <ColorField label="Color" name="color" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `ColorField` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Props

<PropTable component={docs.exports.ColorField} links={docs.links} />

## Visual options

### Quiet

```tsx example
<ColorField label="Primary Color" isQuiet />
```

### Disabled

```tsx example
<ColorField label="Primary Color" isDisabled defaultValue="#e73623" />
```

### Read only

The `isReadOnly` boolean prop makes the ColorField's text content immutable. Unlike `isDisabled`, the ColorField remains focusable
and the contents can still be copied. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<ColorField label="Primary Color" isReadOnly defaultValue="#e73623" />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the ColorField. The `labelPosition` prop can be used to position the label to the side.
The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the
left most edge of the ColorField and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<ColorField label="Primary Color" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/)

Both a description and an error message can be supplied to a ColorField. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <ColorField label="Color" defaultValue="#abc" validationState="valid" description="Enter your favorite color." />
  <ColorField label="Color" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a ColorField.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<ColorField
  label="Accent Color"
  defaultValue="#e73623"
  contextualHelp={
    <ContextualHelp>
      <Heading>What is an accent color?</Heading>
      <Content>An accent color is the primary foreground color for your theme, used across all components.</Content>
    </ContextualHelp>
  } />
```

### Custom width

[View guidelines](https://spectrum.adobe.com/page/text-field/#Width)

```tsx example
<ColorField label="Primary Color" width="size-3600" maxWidth="100%" />
```

---

### Packages @Adobe React Spectrum Docs Color ColorPicker (`packages/@adobe/react-spectrum/docs/color/ColorPicker.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import colorTypes from 'docs:@react-stately/color';
import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorPicker, ColorEditor} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
```

---
category: Color
keywords: [color picker]
---

# ColorPicker

<PageDescription>{docs.exports.ColorPicker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorPicker', 'ColorEditor']}
  since="3.35.0" />

## Example

```tsx example
<ColorPicker label="Fill" defaultValue="#5100FF">
  <ColorEditor />
</ColorPicker>
```

## Value

A ColorArea requires either an uncontrolled default value or a controlled value, provided using the `defaultValue` or `value` props respectively. The value provided to either of these props should be a color string or <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from a HSL string so that `value`'s type remains consistent.

```tsx example
import {ColorPicker} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
import {parseColor} from '@react-spectrum/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('hsl(25, 100%, 50%)'));
  return (
    <Flex gap="size-300" wrap>
      <ColorPicker
        label="Color Picker (uncontrolled)"
        /*- begin highlight -*/
        defaultValue="hsl(25, 100%, 50%)">
        {/*- end highlight -*/}
        <ColorEditor />
      </ColorPicker>
      <ColorPicker
        label="Color Picker (controlled)"
        /*- begin highlight -*/
        value={value}
        onChange={setValue}>
        {/*- end highlight -*/}
        <ColorEditor />
      </ColorPicker>
    </Flex>
  );
}
```

## Labeling

A visual label should be provided for the ColorPicker using the `label` prop.

```tsx example
<ColorPicker label="Stroke color" defaultValue="#345">
  <ColorEditor />
</ColorPicker>
```

### Accessibility

If a visible label isn't specified, an `aria-label` should be provided to the ColorPicker for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

```tsx example
<ColorPicker aria-label="Fill color" defaultValue="#184">
  <ColorEditor />
</ColorPicker>
```

In addition to the visible or accessibility label, a ColorPicker also announces a description of the current color value (e.g. "dark vibrant blue") as a part of the label.

### Internationalization

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ColorPicker is automatically flipped.

## Events

ColorPicker accepts an `onChange` prop which is triggered whenever the value is edited by the user. It receives a <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object as a parameter.

The example below uses `onChange` to update a separate element with the color value as a string.

```tsx example
import {parseColor} from '@react-spectrum/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));

  return (
    <div>
      <ColorPicker
        label="Color"
        value={value}
        onChange={setValue}>
        <ColorEditor />
      </ColorPicker>
      <p>Selected color: {value.toString('hsl')}</p>
    </div>
  );
}
```

## Custom color editor

`ColorEditor` provides a default color picker layout including a color area for saturation and brightness, and color sliders for hue and alpha. It also includes ColorFields to view and enter an exact color value by number.

ColorPicker can be customized by providing any combination of color components as children, including [ColorArea](ColorArea.html), [ColorField](ColorField.html), [ColorSlider](ColorSlider.html), [ColorSwatchPicker](ColorSwatchPicker.html), and [ColorWheel](ColorWheel.html).

```tsx example
import {ColorWheel, ColorArea} from '@react-spectrum/color';

<ColorPicker label="Fill" defaultValue="#08f">
  <ColorWheel />
  <ColorArea
    colorSpace="hsb"
    xChannel="saturation"
    yChannel="brightness"
    size="size-400"
    position="absolute"
    top="calc(50% - size-400)"
    left="calc(50% - size-400)" />
</ColorPicker>
```

## Props

### ColorPicker

<PropTable component={docs.exports.ColorPicker} links={docs.links} />

### ColorEditor

<PropTable component={docs.exports.ColorEditor} links={docs.links} />

## Visual options

### Hide alpha channel

By default, `ColorEditor` includes a ColorSlider and ColorField for editing the alpha channel. This can be hidden with the `hideAlphaChannel` prop.

```tsx example
<ColorPicker label="Color" defaultValue="#f80">
  <ColorEditor hideAlphaChannel />
</ColorPicker>
```

### Swatches

A `ColorEditor` can be combined with additional color components such as a [ColorSwatchPicker](ColorSwatchPicker.html) to choose from a list of pre-defined colors.

```tsx example
import {ColorSwatchPicker, ColorSwatch} from '@react-spectrum/color';

<ColorPicker label="Color" defaultValue="#A00">
  <Flex direction="column" gap="size-300">
    <ColorEditor />
    <ColorSwatchPicker>
      <ColorSwatch color="#A00" />
      <ColorSwatch color="#f80" />
      <ColorSwatch color="#080" />
      <ColorSwatch color="#08f" />
      <ColorSwatch color="#088" />
      <ColorSwatch color="#008" />
    </ColorSwatchPicker>
  </Flex>
</ColorPicker>
```

### Channel sliders

This example uses [ColorSlider](ColorSlider.html) to allow a user to adjust each channel of a color value, with a [Picker](Picker.html) to switch between color spaces.

```tsx example
import type {ColorSpace} from '@react-spectrum/color';
import {ColorSlider, getColorChannels} from '@react-spectrum/color';
import {Picker, Item} from '@react-spectrum/picker';

function Example() {
  let [space, setSpace] = React.useState<ColorSpace>('rgb');

  return (
    <ColorPicker label="Color" defaultValue="#184">
      <Flex direction="column" gap="size-100">
        <Picker aria-label="Color space" isQuiet selectedKey={space} onSelectionChange={s => setSpace(s as ColorSpace)}>
          <Item key="rgb">RGB</Item>
          <Item key="hsl">HSL</Item>
          <Item key="hsb">HSB</Item>
        </Picker>
        {getColorChannels(space).map(channel => (
          <ColorSlider key={channel} colorSpace={space} channel={channel} />
        ))}
        <ColorSlider channel="alpha" />
      </Flex>
    </ColorPicker>
  );
}
```

### Rounding

The rounding of the color swatch can be controlled with the `rounding` prop.

```tsx example
<Flex direction="column" gap="size-100">
  <ColorPicker label="None" rounding="none" defaultValue="#A00">
    <ColorEditor />
  </ColorPicker>
  <ColorPicker label="Default" rounding="default" defaultValue="#080">
    <ColorEditor />
  </ColorPicker>
  <ColorPicker label="Full" rounding="full" defaultValue="#00F">
    <ColorEditor />
  </ColorPicker>
</Flex>
```

### Size

The size of the color swatch can be controlled with the `size` prop. The default size is "S".

```tsx example
<Flex direction="column" gap="size-100">
  <ColorPicker label="Extra small" size="XS" defaultValue="#A00">
    <ColorEditor />
  </ColorPicker>
  <ColorPicker label="Small" size="S" defaultValue="#080">
    <ColorEditor />
  </ColorPicker>
  <ColorPicker label="Medium" size="M" defaultValue="#FB0">
    <ColorEditor />
  </ColorPicker>
  <ColorPicker label="Large" size="L" defaultValue="#00F">
    <ColorEditor />
  </ColorPicker>
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Color ColorSlider (`packages/@adobe/react-spectrum/docs/color/ColorSlider.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import colorTypes from 'docs:@react-stately/color';
import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorSlider} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
```

---
category: Color
keywords: [color slider]
---

# ColorSlider

<PageDescription>{docs.exports.ColorSlider.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorSlider']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/color-slider/'}
  ]}
  since="3.35.0" />

## Example

```tsx example
<ColorSlider defaultValue="#7f0000" channel="red" />
```

## Value

A ColorSlider requires either an uncontrolled default value or a controlled value, provided using the `defaultValue` or `value` props respectively.
The value provided to either of these props should be a color string or <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object. The `channel` prop must also be provided to specify which color channel the slider should display. This must be one of the channels included in the color value, for example, for RGB colors, the "red", "green", and "blue" channels are available. For a full list of supported channels, see the [Props](#props) table below.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from a HSL string
so that `value`'s type remains consistent.

```tsx example
import {parseColor} from '@react-stately/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('hsl(0, 100%, 50%)'));
  return (
    <Flex gap="size-300" wrap>
      <ColorSlider
        label="Hue (uncontrolled)"
        defaultValue="hsl(0, 100%, 50%)"
        channel="hue" />
      <ColorSlider
        label="Hue (controlled)"
        value={value}
        onChange={setValue}
        channel="hue" />
    </Flex>
  );
}
```

### HTML forms

ColorSlider supports the `name` prop for integration with HTML forms. The value will be submitted as a number between the minimum and maximum value for the displayed channel.

```tsx example
<ColorSlider
  defaultValue="#7f0000"
  channel="red"
  name="red" />
```

## Labeling

The ColorSlider's channel name and value are shown above the ColorSlider by default. The label and value label can be hidden by providing
`label={null}` and `showValueLabel={false}` to the ColorSlider, respectively. In addition, a custom label can be provided via the `label` prop.

```tsx example
<Flex gap="size-300" wrap alignItems="end">
  <ColorSlider channel="saturation" defaultValue="hsl(0, 100%, 50%)" label={null} />
  <ColorSlider channel="lightness" defaultValue="hsl(0, 100%, 50%)" showValueLabel={false} />
</Flex>
```

### Accessibility

If the ColorSlider's label is hidden, a localized string for the channel name is used as the `aria-label` by default. The value of the ColorSlider
is also automatically localized and provided to the input as `aria-valuetext` regardless of the value label's visibility. If you provide your own `aria-label`
or `aria-labelledby`, be sure to localize the string or labeling element appropriately.

### Internationalization

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ColorSlider is automatically flipped. As mentioned previously,
ColorSlider automatically uses the current locale to format the channel and value label.

## Events

ColorSlider supports two events: `onChange` and `onChangeEnd`. `onChange` is triggered whenever the ColorSlider's handle is dragged, and `onChangeEnd`
is triggered when the user stops dragging the handle. Both events receive a <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object
as a parameter.

The example below uses `onChange` and `onChangeEnd` to update two separate elements with the ColorSlider's value.

```tsx example
function Example() {
  let [currentValue, setCurrentValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));
  let [finalValue, setFinalValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));

  return (
    <div>
      <ColorSlider
        value={currentValue}
        channel="hue"
        onChange={setCurrentValue}
        onChangeEnd={setFinalValue} />
      <pre>Current value: {currentValue.toString('hsl')}</pre>
      <pre>Final value: {finalValue.toString('hsl')}</pre>
    </div>
  );
}
```

## Creating a color picker

### RGBA

This example shows how you could build an RGBA color picker using four color sliders bound to the same
color value in state. The <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} />
function is used to parse the initial color from a hex value, stored in state. The `value` and `onChange` props
of ColorSlider are used to make the sliders controlled, so that they all update when the color is modified.

```tsx example
function Example() {
  let [color, setColor] = React.useState(parseColor('#ff00ff'));

  return (
    <Flex direction="column">
      <ColorSlider channel="red" value={color} onChange={setColor} />
      <ColorSlider channel="green" value={color} onChange={setColor} />
      <ColorSlider channel="blue" value={color} onChange={setColor} />
      <ColorSlider channel="alpha" value={color} onChange={setColor} />
    </Flex>
  );
}
```

### HSLA

This example shows how to build a similar color picker to the one above, using HSLA colors instead.

```tsx example
function Example() {
  let [color, setColor] = React.useState(parseColor('hsla(0, 100%, 50%, 0.5)'));

  return (
    <Flex direction="column">
      <ColorSlider channel="hue" value={color} onChange={setColor} />
      <ColorSlider channel="saturation" value={color} onChange={setColor} />
      <ColorSlider channel="lightness" value={color} onChange={setColor} />
      <ColorSlider channel="alpha" value={color} onChange={setColor} />
    </Flex>
  );
}
```

### HSBA

This example shows how to build an HSBA color picker.

```tsx example
function Example() {
  let [color, setColor] = React.useState(parseColor('hsba(0, 100%, 50%, 0.5)'));
  return (
    <>
      <ColorSlider channel="hue" value={color} onChange={setColor} />
      <ColorSlider channel="saturation" value={color} onChange={setColor} />
      <ColorSlider channel="brightness" value={color} onChange={setColor} />
      <ColorSlider channel="alpha" value={color} onChange={setColor} />
    </>
  );
}
```

## Props

<PropTable component={docs.exports.ColorSlider} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/color-slider/#Disabled)

```tsx example
<ColorSlider defaultValue="#7f0000"  channel="red" isDisabled />
```

### Vertical
[View guidelines](https://spectrum.adobe.com/page/color-slider/#Orientation)

```tsx example
<ColorSlider defaultValue="#7f0000" channel="red" orientation="vertical" />
```

### Custom Size
[View guidelines](https://spectrum.adobe.com/page/color-slider/#Length)

```tsx example
<Flex direction="column" gap="size-300">
  <ColorSlider defaultValue="#7f0000" channel="red" orientation="vertical" height="size-3600" />
  <ColorSlider defaultValue="#7f0000" channel="red" width="size-3600" maxWidth="100%" />
</Flex>
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a ColorSlider.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<ColorSlider
  label="Accent Color"
  channel="hue"
  defaultValue="hsl(120, 100%, 50%)"
  contextualHelp={
    <ContextualHelp>
      <Heading>What is an accent color?</Heading>
      <Content>An accent color is the primary foreground color for your theme, used across all components.</Content>
    </ContextualHelp>
  } />
```

## Testing

The ColorSlider features a draggable handle that the user can interact with to change its color value.
Please see the following section in the testing docs for more information on how to simulate this action in your
test suite.

[Simulating move event](./testing.html#simulating-move-event)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/color/test/ColorArea.test.tsx) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Color ColorSwatch (`packages/@adobe/react-spectrum/docs/color/ColorSwatch.mdx`)

{/* Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import colorTypes from 'docs:@react-stately/color';
import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorSwatch} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
```

---
category: Color
keywords: [color swatch]
---

# ColorSwatch

<PageDescription>{docs.exports.ColorSwatch.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorSwatch']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/swatch/'}
  ]}
  since="3.35.0" />

## Example

```tsx example
<ColorSwatch color="#f00" />
```

## Value

ColorSwatch accepts a value via the `color` prop. The value should be a color string or <TypeLink links={statelyDocs.links} type={statelyDocs.exports.Color} /> object.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from an HSL string. This is passed to the `value` prop of a [ColorSlider](ColorSlider.html), and the `color` prop of a `ColorSwatch` to show a preview of the selected color.

```tsx example
import {parseColor, ColorSlider} from '@react-spectrum/color';

function Example() {
  let [color, setColor] = React.useState(parseColor('hsl(0, 100%, 50%)'));
  return (
    <Flex direction="column" gap="size-100">
      <ColorSlider value={color} onChange={setColor} channel="hue" />
      <ColorSwatch color={color} />
    </Flex>
  );
}
```

Fully transparent colors are displayed with a red slash through the swatch, while partially transparent colors are shown with a checkerboard background.

```tsx example
import {parseColor, ColorSlider} from '@react-spectrum/color';

function Example() {
  let [color, setColor] = React.useState(parseColor('hsla(0, 100%, 50%, 0)'));
  return (
    <Flex direction="column" gap="size-100">
      <ColorSlider value={color} onChange={setColor} channel="alpha" />
      <ColorSwatch color={color} />
    </Flex>
  );
}
```

## Labeling

By default, ColorSwatch includes a localized color description for screen reader users (e.g. "dark vibrant blue") as an `aria-label`. If you have a more specific color name (e.g. Pantone colors), the automatically generated color description can be overridden via the `colorName` prop. An additional label describing the context of the color swatch (e.g. "Background color") can also be provided via the `aria-label` or `aria-labelledby` props.

In the example below, the full accessible name of the color swatch will be "Fire truck red, Background color".

```tsx example
<ColorSwatch color="#f00" aria-label="Background color" colorName="Fire truck red" />
```

## Props

<PropTable component={docs.exports.ColorSwatch} links={docs.links} />

## Visual options

### Size

[View guidelines](https://spectrum.adobe.com/page/swatch/#Size)

```tsx example
<Flex gap="size-100">
  <ColorSwatch color="#ff0" size="XS" />
  <ColorSwatch color="#ff0" size="S" />
  <ColorSwatch color="#ff0" size="M" />
  <ColorSwatch color="#ff0" size="L" />
</Flex>
```

### Rounding

[View guidelines](https://spectrum.adobe.com/page/swatch/#Corner-rounding)

```tsx example
<Flex gap="size-100">
  <ColorSwatch color="#0ff" rounding="none" />
  <ColorSwatch color="#0ff" rounding="default" />
  <ColorSwatch color="#0ff" rounding="full" />
</Flex>
```

### Custom width

[View guidelines](https://spectrum.adobe.com/page/swatch/#Shape)

```tsx example
<ColorSwatch color="#00f" width="size-1000" />
```

---

### Packages @Adobe React Spectrum Docs Color ColorSwatchPicker (`packages/@adobe/react-spectrum/docs/color/ColorSwatchPicker.mdx`)

{/* Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import colorTypes from 'docs:@react-stately/color';
import docs from 'docs:@react-spectrum/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorSwatchPicker, ColorSwatch} from '@react-spectrum/color';
```

---
category: Color
keywords: [color swatch]
---

# ColorSwatchPicker

<PageDescription>{docs.exports.ColorSwatchPicker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorSwatchPicker']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/swatch-group/'}
  ]}
  since="3.35.0" />

## Example

```tsx example
<ColorSwatchPicker>
  <ColorSwatch color="#A00" />
  <ColorSwatch color="#f80" />
  <ColorSwatch color="#080" />
  <ColorSwatch color="#08f" />
  <ColorSwatch color="#088" />
  <ColorSwatch color="#008" />
</ColorSwatchPicker>
```

## Value

ColorSwatchPicker accepts either an uncontrolled default value or a controlled value, provided using the `defaultValue` or `value` props respectively. The value provided to either of these props should be a color string or <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object. The value is matched against the color of each ColorSwatch, including equivalent colors in different color spaces.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from a HSL string so that `value`'s type remains consistent.

```tsx example
import {parseColor} from '@react-spectrum/color';

function Example() {
  let [color, setColor] = React.useState(parseColor('hsl(0, 100%, 33.33%)'));

  return (
    <ColorSwatchPicker value={color} onChange={setColor}>
      <ColorSwatch color="#A00" />
      <ColorSwatch color="#f80" />
      <ColorSwatch color="#080" />
    </ColorSwatchPicker>
  );
}
```

**Note**: ColorSwatches rendered inside a ColorSwatchPicker must have unique colors, even between different color spaces. For example, the values `#f00`, `hsl(0, 100%, 50%)`, and `hsb(0, 100%, 100%)` are all equivalent and considered duplicates. This is required so that selection behavior works properly.

## Labeling

By default, `ColorSwatchPicker` has an `aria-label` with the localized string "Color swatches". This can be overridden with a more specific accessibility label using the `aria-label` or `aria-labelledby` props. All labels should be localized.

```tsx example
<ColorSwatchPicker aria-label="Fill color">
  <ColorSwatch color="#A00" />
  <ColorSwatch color="#f80" />
  <ColorSwatch color="#080" />
</ColorSwatchPicker>
```

## Events

ColorSwatchPicker accepts an `onChange` prop which is triggered whenever the value is edited by the user. It receives a <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object as a parameter.

The example below uses `onChange` to update a separate element with the color value as a string.

```tsx example
import {parseColor} from '@react-spectrum/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('#A00'));

  return (
    <div>
      <ColorSwatchPicker value={value} onChange={setValue}>
        <ColorSwatch color="#A00" />
        <ColorSwatch color="#f80" />
        <ColorSwatch color="#080" />
        <ColorSwatch color="#08f" />
        <ColorSwatch color="#088" />
        <ColorSwatch color="#008" />
      </ColorSwatchPicker>
      <p>Selected color: {value.toString('rgb')}</p>
    </div>
  );
}
```

## Props

<PropTable component={docs.exports.ColorSwatchPicker} links={docs.links} />

## Visual options

### Size

[View guidelines](https://spectrum.adobe.com/page/swatch-group/#Size)

```tsx example
<ColorSwatchPicker size="XS">
  <ColorSwatch color="#A00" />
  <ColorSwatch color="#f80" />
  <ColorSwatch color="#080" />
  <ColorSwatch color="#08f" />
</ColorSwatchPicker>
```

### Density

[View guidelines](https://spectrum.adobe.com/page/swatch-group/#Density)

```tsx example
<ColorSwatchPicker density="compact">
  <ColorSwatch color="#A00" />
  <ColorSwatch color="#f80" />
  <ColorSwatch color="#080" />
  <ColorSwatch color="#08f" />
</ColorSwatchPicker>
```

### Rounding

[View guidelines](https://spectrum.adobe.com/page/swatch-group/#Corner-rounding-in-swatch-groups)

Only use rounded corners if the ColorSwatchPicker is displayed on a single row.

```tsx example
<ColorSwatchPicker rounding="full">
  <ColorSwatch color="#A00" />
  <ColorSwatch color="#f80" />
  <ColorSwatch color="#080" />
  <ColorSwatch color="#08f" />
</ColorSwatchPicker>
```

---

### Packages @Adobe React Spectrum Docs Color ColorWheel (`packages/@adobe/react-spectrum/docs/color/ColorWheel.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import docs from 'docs:@react-spectrum/color';
import colorTypes from 'docs:@react-stately/color';
import {HeaderInfo, PropTable, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Layout} from '@react-spectrum/docs';
import packageData from '@react-spectrum/color/package.json';
import statelyDocs from 'docs:@react-stately/color';

export default Layout;

```jsx import
import {ColorWheel} from '@react-spectrum/color';
import {Flex} from '@react-spectrum/layout';
```

---
category: Color
keywords: [color wheel, slider]
---

# ColorWheel

<PageDescription>{docs.exports.ColorWheel.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ColorWheel']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/color-wheel/'}
  ]}
  since="3.35.0" />

## Example

```tsx example
<ColorWheel defaultValue="hsl(30, 100%, 50%)" />
```

## Value

A ColorWheel's `value` specifies the position of the ColorWheel's thumb on the track, and accepts a string or <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object.
It is initialized as `hsl(0, 100%, 50%)` by default, but an alternative initial uncontrolled value can be provided using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop. Note that only HSB(A) values are supported as valid values.

In the example below, the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.parseColor} /> function is used to parse the initial color from a HSL string
so that `value`'s type remains consistent.

```tsx example
import {parseColor} from '@react-stately/color';

function Example() {
  let [value, setValue] = React.useState(parseColor('hsl(30, 100%, 50%)'));
  return (
    <Flex gap="size-300" wrap>
      <Flex direction="column" alignItems="center">
        <label id="label-1">Hue (uncontrolled)</label>
        <ColorWheel
          defaultValue="hsl(30, 100%, 50%)"
          aria-labelledby="label-1" />
      </Flex>
      <Flex direction="column" alignItems="center">
        <label id="label-2">Hue (controlled)</label>
        <ColorWheel
          value={value}
          onChange={setValue}
          aria-labelledby="label-1" />
      </Flex>
    </Flex>
  );
}
```

### HTML forms

ColorWheel supports the `name` prop for integration with HTML forms. The value will be submitted as a number between 0 and 360 degrees.

```tsx example
<ColorWheel name="hue" />
```

## Labeling

By default, a localized string for the "hue" channel name is used as the `aria-label` for the ColorWheel. When a custom `aria-label` or `aria-labelledby`
is provided, it should be localized accordingly.

## Events

ColorWheel supports two events: `onChange` and `onChangeEnd`. `onChange` is triggered whenever the ColorWheel's handle is dragged, and `onChangeEnd`
is triggered when the user stops dragging the handle. Both events receive a <TypeLink links={colorTypes.links} type={colorTypes.exports.Color} /> object
as a parameter.

The example below uses `onChange` and `onChangeEnd` to update two separate elements with the ColorWheel's value.

```tsx example
function Example() {
  let [currentValue, setCurrentValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));
  let [finalValue, setFinalValue] = React.useState(parseColor('hsl(50, 100%, 50%)'));

  return (
    <div>
      <ColorWheel
        value={currentValue}
        onChange={setCurrentValue}
        onChangeEnd={setFinalValue}
      />
      <pre>Current value: {currentValue.toString('hsl')}</pre>
      <pre>Final value: {finalValue.toString('hsl')}</pre>
    </div>
  );
}
```

## Props

<PropTable component={docs.exports.ColorWheel} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/color-wheel/#Disabled)

```tsx example
<ColorWheel isDisabled />
```

### Size
[View guidelines](https://spectrum.adobe.com/page/color-wheel/#Size)

```tsx example
<ColorWheel size="size-1600" />
```

## Testing

The ColorWheel features a draggable handle that the user can interact with to change its color value.
Please see the following section in the testing docs for more information on how to simulate this action in your
test suite.

[Simulating move event](./testing.html#simulating-move-event)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/color/test/ColorWheel.test.tsx) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Combobox ComboBox (`packages/@adobe/react-spectrum/docs/combobox/ComboBox.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/combobox';
import comboboxUtils from 'docs:@react-aria/test-utils';
import packageData from '@react-spectrum/combobox/package.json';
import {HeaderInfo, PropTable, PageDescription, ClassAPI, VersionBadge} from '@react-spectrum/docs';

```jsx import
import Add from '@spectrum-icons/workflow/Add';
import Alert from '@spectrum-icons/workflow/Alert';
import Bell from '@spectrum-icons/workflow/Bell';
import {ComboBox, Item, Section} from '@react-spectrum/combobox';
import Draw from '@spectrum-icons/workflow/Draw';
import {Flex} from '@react-spectrum/layout';
import {Text} from '@react-spectrum/text';
import {useFilter} from '@react-aria/i18n';
import {Avatar} from "@react-spectrum/avatar";
```

---
category: Pickers
keywords: [collections, dropdown]
---

# ComboBox

<PageDescription>{docs.exports.ComboBox.description}</PageDescription>

<HeaderInfo
 packageData={packageData}
 componentNames={['ComboBox', 'Item', 'Section']}
 sourceData={[
 {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/combo-box/'}
 ]}
 since="3.12.0" />

## Example
```tsx example
<ComboBox label="Favorite Animal">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

## Content
ComboBox follows the [Collection Components](collections.html) API, accepting both static and dynamic collections.
Similar to [Picker](Picker.html), ComboBox accepts `<Item>` elements as children, each with a `key` prop. Basic usage of ComboBox, seen in the example above, shows multiple options populated with a string.
Static collections, as in this example, can be used when the full list of options is known ahead of time.

Dynamic collections, as shown below, can be used when the options come from an external data source such as an API call, or update over time.
Providing the data in this way allows ComboBox to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of options is passed to the ComboBox using the `defaultItems` prop. Each item accepts a key prop, which is passed to the `onSelectionChange` handler to identify the selected item.
Alternatively, if the item objects contain an `id` property, as shown in the example below, then this is used automatically and a `key` prop is not required. See the [Events](#events) section for more detail on selection.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aerospace'},
    {id: 2, name: 'Mechanical'},
    {id: 3, name: 'Civil'},
    {id: 4, name: 'Biomedical'},
    {id: 5, name: 'Nuclear'},
    {id: 6, name: 'Industrial'},
    {id: 7, name: 'Chemical'},
    {id: 8, name: 'Agricultural'},
    {id: 9, name: 'Electrical'}
  ];
  let [majorId, setMajorId] = React.useState(null);

  return (
    <>
      <p>Topic id: {majorId}</p>
      <ComboBox
        label="Pick an engineering major"
        defaultItems={options}
        onSelectionChange={setMajorId}>
        {item => <Item>{item.name}</Item>}
      </ComboBox>
    </>
  );
}
```

Alternatively, passing your list of options to ComboBox's `items` prop will cause the list of items to be controlled, useful for when you want to provide your own
filtering logic. See the [Custom Filtering](#custom-filtering) section for more detail.

### Trays
On mobile, ComboBox automatically displays in a tray instead of a popover to improve usability. The tray contains a search field that mobile users
can use to filter the options available via text.

### Internationalization
To internationalize a ComboBox, a localized string should be passed to the `children` of each `Item`.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ComboBox is automatically flipped.

## Value
A ComboBox's `value` is empty by default, but an initial, uncontrolled, value can be provided using the `defaultInputValue` prop.
Alternatively, a controlled value can be provided using the `inputValue` prop. Note that the input value of the ComboBox does not affect
the ComboBox's selected option. See [Events](#events) for more details on input change events.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Adobe Photoshop'},
    {id: 2, name: 'Adobe XD'},
    {id: 3, name: 'Adobe InDesign'},
    {id: 4, name: 'Adobe AfterEffects'},
    {id: 5, name: 'Adobe Illustrator'},
    {id: 6, name: 'Adobe Lightroom'},
    {id: 7, name: 'Adobe Premiere Pro'},
    {id: 8, name: 'Adobe Fresco'},
    {id: 9, name: 'Adobe Dreamweaver'}
  ];
  let [value, setValue] = React.useState('Adobe XD');

  return (
    <Flex gap="size-150" wrap>
      <ComboBox
        label="Adobe product (Uncontrolled)"
        defaultItems={options}
        defaultInputValue="Adobe XD">
        {item => <Item>{item.name}</Item>}
      </ComboBox>

      <ComboBox
        label="Pick an Adobe product (Controlled)"
        defaultItems={options}
        inputValue={value}
        onInputChange={setValue}>
        {item => <Item>{item.name}</Item>}
      </ComboBox>
    </Flex>
  );
}
```

### Custom Value
By default on blur, a ComboBox will either reset its input value to match the selected option's text or clear its input value if an option has not been selected yet.
If you would like to allow the end user to provide a custom input value to the ComboBox, the `allowsCustomValue` prop can be used to override the above behavior.

```tsx example
function Example() {
  let options = [
    {name: 'Apple'},
    {name: 'Banana'},
    {name: 'Orange'},
    {name: 'Honeydew'},
    {name: 'Grapes'},
    {name: 'Watermelon'},
    {name: 'Cantaloupe'},
    {name: 'Pear'}
  ];

  return (
    <>
      <p>
        Please indicate what fruit you would like included with your delivery. If your desired choice does not appear in the list
        feel free to write your own selection.
      </p>
      <ComboBox
        label="Preferred fruit"
        defaultItems={options}
        allowsCustomValue>
        {item => <Item key={item.name}>{item.name}</Item>}
      </ComboBox>
    </>
  );
}
```

### HTML forms

ComboBox supports the `name` prop for integration with HTML forms. By default, the text in the input field will be submitted to the server. If the `formValue` prop is set to `"key"`, the `key` of the selected item will be submitted instead.

```tsx example
<Flex gap="size-200" wrap>
  <ComboBox
    label="Ice cream flavor"
    ///- begin highlight -///
    name="iceCream"
    allowsCustomValue
    ///- end highlight -///
  >
    <Item>Chocolate</Item>
    <Item>Mint</Item>
    <Item>Strawberry</Item>
    <Item>Vanilla</Item>
  </ComboBox>
  <ComboBox
    label="Favorite Animal"
    ///- begin highlight -///
    name="favoriteAnimalId"
    formValue="key"
    ///- end highlight -///
  >
    <Item key="panda">Panda</Item>
    <Item key="cat">Cat</Item>
    <Item key="dog">Dog</Item>
  </ComboBox>
</Flex>
```

## Labeling
ComboBox can be labeled using the `label` prop. If the ComboBox is a required field, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<ComboBox label="Favorite Animal" isRequired necessityIndicator="icon">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```
```tsx example
<ComboBox label="Favorite Animal" isRequired necessityIndicator="label">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```
```tsx example
<ComboBox label="Favorite Animal" necessityIndicator="label">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Accessibility
If a visible label isn't specified, an `aria-label` must be provided to the ComboBox for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization
In order to internationalize a ComboBox, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Selection
Setting a selected option can be done by using the `defaultSelectedKey` or `selectedKey` prop. The selected key corresponds to the `key` of an item. See [Events](#events) for more details on selection events.
Additionally, see the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
import type {Key} from '@adobe/react-spectrum';

function Example() {
  let options = [
    {id: 1, name: 'Adobe Photoshop'},
    {id: 2, name: 'Adobe XD'},
    {id: 3, name: 'Adobe InDesign'},
    {id: 4, name: 'Adobe AfterEffects'},
    {id: 5, name: 'Adobe Illustrator'},
    {id: 6, name: 'Adobe Lightroom'},
    {id: 7, name: 'Adobe Premiere Pro'},
    {id: 8, name: 'Adobe Fresco'},
    {id: 9, name: 'Adobe Dreamweaver'}
  ];
  let [productId, setProductId] = React.useState<Key>(9);

  return (
    <Flex gap="size-150" wrap>
      <ComboBox
        label="Pick an Adobe product (uncontrolled)"
        defaultItems={options}
        defaultSelectedKey={9}>
        {item => <Item>{item.name}</Item>}
      </ComboBox>

      <ComboBox
        label="Pick an Adobe product (controlled)"
        defaultItems={options}
        selectedKey={productId}
        onSelectionChange={selected => setProductId(selected)}>
        {item => <Item>{item.name}</Item>}
      </ComboBox>
    </Flex>
  );
}
```

## Links

By default, interacting with an item in a ComboBox selects it and updates the input value. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Interacting with link items navigates to the provided URL and does not update the selection or input value.

```tsx example
<ComboBox label="Tech company websites">
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</ComboBox>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
ComboBox supports sections in order to group options. Sections can be used by wrapping groups of items in a `Section` element. Each `Section` takes a `title` and `key` prop.

### Static items
```tsx example
<ComboBox label="Preferred fruit or vegetable">
  <Section title="Fruit">
    <Item key="Apple">Apple</Item>
    <Item key="Banana">Banana</Item>
    <Item key="Orange">Orange</Item>
    <Item key="Honeydew">Honeydew</Item>
    <Item key="Grapes">Grapes</Item>
    <Item key="Watermelon">Watermelon</Item>
    <Item key="Cantaloupe">Cantaloupe</Item>
    <Item key="Pear">Pear</Item>
  </Section>
  <Section title="Vegetable">
    <Item key="Cabbage">Cabbage</Item>
    <Item key="Broccoli">Broccoli</Item>
    <Item key="Carrots">Carrots</Item>
    <Item key="Lettuce">Lettuce</Item>
    <Item key="Spinach">Spinach</Item>
    <Item key="Bok Choy">Bok Choy</Item>
    <Item key="Cauliflower">Cauliflower</Item>
    <Item key="Potatoes">Potatoes</Item>
  </Section>
</ComboBox>
```

### Dynamic items
Sections used with dynamic items are populated from a hierarchical data structure. Please note that `Section` takes an array of data using the `items` prop only.

```tsx example
function Example() {
  let options = [
    {name: 'Fruit', children: [
      {name: 'Apple'},
      {name: 'Banana'},
      {name: 'Orange'},
      {name: 'Honeydew'},
      {name: 'Grapes'},
      {name: 'Watermelon'},
      {name: 'Cantaloupe'},
      {name: 'Pear'}
    ]},
    {name: 'Vegetable', children: [
      {name: 'Cabbage'},
      {name: 'Broccoli'},
      {name: 'Carrots'},
      {name: 'Lettuce'},
      {name: 'Spinach'},
      {name: 'Bok Choy'},
      {name: 'Cauliflower'},
      {name: 'Potatoes'}
    ]}
  ];

  return (
    <ComboBox label="Preferred fruit or vegetable" defaultItems={options}>
      {item => (
        <Section key={item.name} items={item.children} title={item.name}>
          {item => <Item key={item.name}>{item.name}</Item>}
        </Section>
      )}
    </ComboBox>
  );
}
```

## Events
ComboBox supports selection via mouse, keyboard, and touch. You can handle all of these via the `onSelectionChange`
prop. ComboBox will pass the selected `key` to the `onSelectionChange` handler.
Additionally, ComboBox accepts an `onInputChange` prop which is triggered whenever the value is edited by the user, whether through typing or option
selection.

The example below uses `onSelectionChange` and `onInputChange` to update the selection and input value stored in React state.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aerospace'},
    {id: 2, name: 'Mechanical'},
    {id: 3, name: 'Civil'},
    {id: 4, name: 'Biomedical'},
    {id: 5, name: 'Nuclear'},
    {id: 6, name: 'Industrial'},
    {id: 7, name: 'Chemical'},
    {id: 8, name: 'Agricultural'},
    {id: 9, name: 'Electrical'}
  ];

  let [value, setValue] = React.useState('');
  let [majorId, setMajorId] = React.useState('');

  let onSelectionChange = (id) => {
    setMajorId(id);
  };

  let onInputChange = (value) => {
    setValue(value)
  };

  return (
    <>
      <p>Current selected major id: {majorId}</p>
      <p>Current input text: {value}</p>
      <ComboBox
        label="Pick a engineering major"
        defaultItems={options}
        selectedKey={majorId}
        onSelectionChange={onSelectionChange}
        onInputChange={onInputChange}>
        {item => <Item>{item.name}</Item>}
      </ComboBox>
    </>
  );
}
```

### Fully controlled ComboBox

When a ComboBox has multiple controlled properties (e.g.`inputValue`, `selectedKey`, `items`), it is important to note that an update to one of these properties will
not automatically update the others. Each interaction done in the ComboBox will only trigger its associated event handler. For example, typing in the field will only
trigger `onInputChange` whereas selecting an item from the ComboBox menu will only trigger `onSelectionChange` so it is your responsibility to update the other
controlled properties accordingly. Note that you should provide an `onSelectionChange` handler for a ComboBox with controlled input value and open state. This way, you can properly
control the menu's open state when the user selects an option or blurs from the field.

The below example demonstrates how you would construct the same example above in a completely controlled fashion.

```tsx example
import {useTreeData} from '@react-stately/data';

function Example() {
  let options = [
    {id: 1, name: 'Aerospace'},
    {id: 2, name: 'Mechanical'},
    {id: 3, name: 'Civil'},
    {id: 4, name: 'Biomedical'},
    {id: 5, name: 'Nuclear'},
    {id: 6, name: 'Industrial'},
    {id: 7, name: 'Chemical'},
    {id: 8, name: 'Agricultural'},
    {id: 9, name: 'Electrical'}
  ];

  let [fieldState, setFieldState] = React.useState({
    selectedKey: '',
    inputValue: ''
  });

  let list = useTreeData({
    initialItems: options
  });

  let onSelectionChange = (key) => {
    setFieldState({
      inputValue: list.getItem(key)?.value.name ?? '',
      selectedKey: key
    });
  };

  let onInputChange = (value) => {
    setFieldState(prevState => ({
      inputValue: value,
      selectedKey: value === '' ? null : prevState.selectedKey
    }));
  };

  return (
     <>
      <p>Current selected major id: {fieldState.selectedKey}</p>
      <p>Current input text: {fieldState.inputValue}</p>
       <ComboBox
        label="Pick a engineering major"
        defaultItems={list.items}
        selectedKey={fieldState.selectedKey}
        inputValue={fieldState.inputValue}
        onSelectionChange={onSelectionChange}
        onInputChange={onInputChange}>
        {item => <Item>{item.value.name}</Item>}
      </ComboBox>
     </>
  );
}
```

## Complex items
Items within ComboBox also allow for additional content used to better communicate options. Icons, avatars, and descriptions can be added to the `children` of `Item` as shown in the example below.
If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
See Icon's [labeling](workflow-icons.html#labeling) section and Avatar's [accessibility](Avatar.html#accessibility) section for more information on how to label these elements.

```tsx example
<ComboBox label="Select action">
  <Item textValue="Add to queue">
    <Add />
    <Text>Add to queue</Text>
    <Text slot="description">Add to current watch queue.</Text>
  </Item>
  <Item textValue="Add review">
    <Draw />
    <Text>Add review</Text>
    <Text slot="description">Post a review for the episode.</Text>
  </Item>
    <Item textValue="Subscribe to series">
    <Bell />
    <Text>Subscribe to series</Text>
    <Text slot="description">Add series to your subscription list and be notified when a new episode airs.</Text>
  </Item>
  <Item textValue="Report">
    <Alert />
    <Text>Report</Text>
    <Text slot="description">Report an issue/violation.</Text>
  </Item>
</ComboBox>
```

### With avatars

```tsx example
<ComboBox label="Select a user">
  <Item textValue="User 1">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 1</Text>
  </Item>
  <Item textValue="User 2">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 2</Text>
  </Item>
  <Item textValue="User 3">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 3</Text>
  </Item>
  <Item textValue="User 4">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 4</Text>
  </Item>
</ComboBox>
```

## Asynchronous loading

ComboBox supports loading data asynchronously, and will display a progress circle reflecting the current load state,
set by the `loadingState` prop. It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data. See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Character {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Character>({
    async load({signal, cursor, filterText}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      // If no cursor is available, then we're loading the first page,
      // filtering the results returned via a query string that
      // mirrors the ComboBox input text.
      // Otherwise, the cursor is the next URL to load,
      // as returned from the previous page.
      let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=${filterText}`, {signal});
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <ComboBox
      label="Star Wars Character Lookup"
      items={list.items}
      inputValue={list.filterText}
      onInputChange={list.setFilterText}
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}>
      {item => <Item key={item.name}>{item.name}</Item>}
    </ComboBox>
  );
}
```

When both `inputValue` and `selectedKey` are controlled, and the `selectedKey` is set to an initial value before the `items` load, you must update the `inputValue` when the `items` load.
This can be done by returning `filterText` from the `useAsyncList` load function.

The example below demonstrates how you could update the input value for your selected key once your list of items has been fetched.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Validation

ComboBox supports the `isRequired` prop to ensure the user enters a value, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the combo box or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <ComboBox label="Favorite animal" name="animal" isRequired>
  {/*- end highlight -*/}
    <Item>Aardvark</Item>
    <Item>Cat</Item>
    <Item>Dog</Item>
    <Item>Kangaroo</Item>
    <Item>Panda</Item>
    <Item>Snake</Item>
  </ComboBox>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `ComboBox` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Custom Filtering
By default, ComboBox uses a string "contains" filtering strategy when deciding what items to display in the dropdown menu. This filtering strategy can be overwritten
by filtering the list of items yourself and passing the filtered list to the ComboBox via the `items` prop.

The example below uses a string "startsWith" filter function obtained from the `useFilter` hook to display items that start with the ComboBox's current input
value only. By using the `menuTrigger` returned by `onOpenChange`, it also handles displaying the entire option list regardless of the current filter value when the ComboBox menu is
opened via the trigger button or arrow keys. `menuTrigger` tells you if the menu was opened manually by the user ("manual"), by focusing the ComboBox ("focus"), or by
changes in the input field ("input"), allowing you to make updates to other controlled aspects of your ComboBox accordingly.

```tsx example
function Example() {
  let options = [
    {id: 1, email: 'fake@email.com'},
    {id: 2, email: 'anotherfake@email.com'},
    {id: 3, email: 'bob@email.com'},
    {id: 4, email: 'joe@email.com'},
    {id: 5, email: 'yourEmail@email.com'},
    {id: 6, email: 'valid@email.com'},
    {id: 7, email: 'spam@email.com'},
    {id: 8, email: 'newsletter@email.com'},
    {id: 9, email: 'subscribe@email.com'}
  ];

  let [showAll, setShowAll] = React.useState(false);
  let [filterValue, setFilterValue] = React.useState('');
  let {startsWith} = useFilter({sensitivity: 'base'});
  let filteredItems = React.useMemo(() => options.filter(item => startsWith(item.email, filterValue)), [options, filterValue]);

  return (
    <ComboBox
      onOpenChange={(isOpen, menuTrigger) => {
        // Show all items if menu is opened manually
        // i.e. by the arrow keys or trigger button
        if (menuTrigger === 'manual' && isOpen) {
          setShowAll(true);
        }
      }}
      width="size-3000"
      label="To:"
      items={showAll ? options : filteredItems}
      inputValue={filterValue}
      onInputChange={(value) => {
        setShowAll(false);
        setFilterValue(value);
      }}
      allowsCustomValue>
      {item => <Item>{item.email}</Item>}
    </ComboBox>
  );
}
```

## Trigger options
By default, the ComboBox's menu is opened when the user types into the input field ("input"). There are two other supported modes: one where the menu opens when the ComboBox is focused ("focus") and
the other where the menu only opens when the user clicks or taps on the ComboBox's field button ("manual"). These can be set by providing "focus" or "manual" to the `menuTrigger` prop.
Guidelines on when to use a specific mode can be found [here](https://spectrum.adobe.com/page/combo-box/#Menu-trigger). Note that the mobile ComboBox experience requires the end user to press the ComboBox button
to open the tray regardless of the `menuTrigger` setting.

```tsx example
<ComboBox label="Select action" menuTrigger="focus">
  <Item textValue="Add to queue">
    <Add />
    <Text>Add to queue</Text>
    <Text slot="description">Add to current watch queue.</Text>
  </Item>
  <Item textValue="Add review">
    <Draw />
    <Text>Add review</Text>
    <Text slot="description">Post a review for the episode.</Text>
  </Item>
    <Item textValue="Subscribe to series">
    <Bell />
    <Text>Subscribe to series</Text>
    <Text slot="description">Add series to your subscription list and be notified when a new episode airs.</Text>
  </Item>
  <Item textValue="Report">
    <Alert />
    <Text>Report</Text>
    <Text slot="description">Report an issue/violation.</Text>
  </Item>
</ComboBox>
```
```tsx example
<ComboBox label="Select action" menuTrigger="manual">
  <Item textValue="Add to queue">
    <Add />
    <Text>Add to queue</Text>
    <Text slot="description">Add to current watch queue.</Text>
  </Item>
  <Item textValue="Add review">
    <Draw />
    <Text>Add review</Text>
    <Text slot="description">Post a review for the episode.</Text>
  </Item>
    <Item textValue="Subscribe to series">
    <Bell />
    <Text>Subscribe to series</Text>
    <Text slot="description">Add series to your subscription list and be notified when a new episode airs.</Text>
  </Item>
  <Item textValue="Report">
    <Alert />
    <Text>Report</Text>
    <Text slot="description">Report an issue/violation.</Text>
  </Item>
</ComboBox>
```

## Props

<PropTable component={docs.exports.ComboBox} links={docs.links} />

## Visual options

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Label-position)

By default, the label is positioned above the ComboBox. The `labelPosition` prop can be used to position the label to the side.
The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the ComboBox and "end" refers to the right most edge.
For right-to-left (RTL) languages, this is flipped.

```tsx example
<ComboBox label="Favorite Animal" labelPosition="side" labelAlign="end">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Quiet
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Quiet)

```tsx example
<ComboBox label="Favorite Animal" isQuiet>
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Disabled)

```tsx example
<ComboBox label="Favorite Animal" isDisabled>
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Read only
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Read-only)

```tsx example
<ComboBox label="Favorite Animal" isReadOnly selectedKey="red panda">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Help-text-(description-and-error-message))

Both a description and an error message can be supplied to a ComboBox. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
    let [animalId, setAnimalId] = React.useState(null);
    let options = [
      {id: 1, name: 'Aardvark'},
      {id: 2, name: 'Cat'},
      {id: 3, name: 'Dog'},
      {id: 4, name: 'Kangaroo'},
      {id: 5, name: 'Koala'},
      {id: 6, name: 'Penguin'},
      {id: 7, name: 'Snake'},
      {id: 8, name: 'Turtle'},
      {id: 9, name: 'Wombat'}
    ];
  let isValid = React.useMemo(() => animalId !== 2 && animalId !== 7, [animalId]);

  return (
    <ComboBox
      validationState={!animalId ? undefined : isValid ? 'valid' : 'invalid'}
      label="Favorite animal"
      description="Pick your favorite animal, you will be judged."
      errorMessage={animalId === 2 ? 'The author of this example is a dog person.' : 'Oh no it\'s a snake! Choose anything else.'}
      items={options}
      selectedKey={animalId}
      onSelectionChange={selected => setAnimalId(selected)}>
      {item => <Item>{item.name}</Item>}
    </ComboBox>
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a ComboBox.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<ComboBox
  label="Engineering major"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Major changes</Heading>
      <Content>Once you have changed your major, you cannot change it back.</Content>
    </ContextualHelp>
  }>
  <Item>Aerospace</Item>
  <Item>Mechanical</Item>
  <Item>Civil</Item>
  <Item>Nuclear</Item>
  <Item>Industrial</Item>
  <Item>Chemical</Item>
  <Item>Agricultural</Item>
  <Item>Electrical</Item>
</ComboBox>
```

### Custom widths
[View guidelines](https://spectrum.adobe.com/page/combo-box/#Width)

```tsx example
<ComboBox label="Favorite Animal" width="size-6000" maxWidth="100%">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

### Menu direction
```tsx example
<ComboBox label="Favorite Animal" direction="top">
  <Item key="red panda">Red Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
  <Item key="aardvark">Aardvark</Item>
  <Item key="kangaroo">Kangaroo</Item>
  <Item key="snake">Snake</Item>
</ComboBox>
```

## Testing

The ComboBox features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your device configuration, this overlay may render as a tray or a dropdown and the trigger itself may render as a button or a input. Additionally,
the ComboBox features automatic virtualization and may need specific mocks in a test environment to enable said virtualization properly.
Please see the following sections in the testing docs for more information on how to handle these
behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/combobox/test/ComboBox.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common combobox interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the combobox tester and a sample of how you could use it in your test suite.

```ts
// Combobox.test.ts
import {render, within} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/ComboBox.html#testing

it('ComboBox can select an option via keyboard', async function () {
  // Render your test component/app and initialize the combobox tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <ComboBox data-testid="test-combobox">
        ...
      </ComboBox>
    </Provider>
  );
  let comboboxTester = testUtilUser.createTester('ComboBox', {root: getByTestId('test-combobox'), interactionType: 'keyboard'});

  await comboboxTester.open();
  expect(comboboxTester.getListbox()).toBeInTheDocument();

  let options = comboboxTester.getOptions();
  await comboboxTester.toggleOptionSelection({option: options[0]});
  expect(comboboxTester.getCombobox().value).toBe('One');
  expect(comboboxTester.getListbox()).not.toBeInTheDocument();
});
```

<ClassAPI links={comboboxUtils.links} class={comboboxUtils.exports.ComboBoxTester} />

---

### Packages @Adobe React Spectrum Docs Contextualhelp ContextualHelp (`packages/@adobe/react-spectrum/docs/contextualhelp/ContextualHelp.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/contextualhelp';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/contextualhelp/package.json';

```jsx import
import {ContextualHelp} from '@react-spectrum/contextualhelp';
import {Content, Footer} from '@react-spectrum/view';
import {Heading, Text} from '@react-spectrum/text';
import {Link} from '@react-spectrum/link';
import {Flex} from '@react-spectrum/layout';
```

---
category: Overlays
keywords: [popover, field, input]
---

# ContextualHelp

<PageDescription>{docs.exports.ContextualHelp.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ContextualHelp']}
  sourceData={[ {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/contextual-help/'} ]}
  since="3.16.0" />

## Example

```tsx example
<ContextualHelp variant="info">
  <Heading>Need help?</Heading>
  <Content><Text>If you're having issues accessing your account, contact our customer support team for help.</Text></Content>
</ContextualHelp>
```

## Content

Unlike [Dialog](Dialog.html), the layout in ContextualHelp is very deliberate. Every ContextualHelp component is triggered as a popover where the
trigger element is a quiet action button with either a help or info icon. Much like [Dialog](Dialog.html), however, ContextualHelp has sections that
can be populated by providing the following components to your ContextualHelp as children:
[Heading](Heading.html) (title), [Content](Content.html) (body), and [Footer](Footer.html) (link).
Each of these components are required in a Spectrum compliant ContextualHelp except for `Footer` since including a link is optional.

```tsx example
<ContextualHelp variant="help">
  <Heading>What is a segment?</Heading>
  <Content><Text>Segments identify who your visitors are, what devices and services they use, where they navigated from, and much more.</Text></Content>
  <Footer><Link>Learn more about segments</Link></Footer>
</ContextualHelp>
```

## Placement

ContextualHelp supports [Dialog placement](./DialogTrigger.html#dialog-placement) options for when the positioning of the popover needs to customized.

```tsx example
<ContextualHelp variant="info" placement="top start">
  <Heading>Placement</Heading>
  <Content><Text>The placement of this contextual help popover has been customized to use top start.</Text></Content>
</ContextualHelp>
```

## Events

ContextualHelp accepts an `onOpenChange` prop, triggered when the ContextualHelp's popover opens or closes.

The example below uses `onOpenChange` to update a separate element with the current open state of the Dialog.

```tsx example
function Example() {
  let [state, setState] = React.useState(false);

  return (
    <Flex alignItems="center" gap="size-100">
      <ContextualHelp variant="info" onOpenChange={(isOpen) => setState(isOpen)}>
        <Heading>Permission required</Heading>
        <Content><Text>Your admin must grant you permission before you can create a segment.</Text></Content>
      </ContextualHelp>
      <Text>Current open state: {state.toString()}</Text>
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.ContextualHelp} links={docs.links} />

## Visual options

### Info

Use the info icon for brief, specific, contextual guidance. This is best for supplemental or nice-to-know information,
in-line with a label or a component (if there is no label). The content for an info icon’s popover should be [instructive](https://spectrum.adobe.com/page/voice-and-tone/#Tone-spectrum) in tone.

```tsx example
<ContextualHelp variant="info">
  <Heading>Permission required</Heading>
  <Content><Text>Your admin must grant you permission before you can create a segment.</Text></Content>
</ContextualHelp>
```

### Help

Use the help icon for content that offers more detailed, in-depth guidance about a task, UI element, tool, or keyboard shortcuts.
This may include an image, video, or link and should be [helpful](https://spectrum.adobe.com/page/voice-and-tone/#Tone-spectrum) in tone.

```tsx example
<ContextualHelp variant="help">
  <Heading>What is a segment?</Heading>
  <Content><Text>Segments identify who your visitors are, what devices and services they use, where they navigated from, and much more.</Text></Content>
  <Footer><Link>Learn more about segments</Link></Footer>
</ContextualHelp>
```

## Testing

The ContextualHelpTrigger features an overlay that transitions in and out of the page as it is opened and closed.
Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/dialog/test/AlertDialog.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Datepicker DateField (`packages/@adobe/react-spectrum/docs/datepicker/DateField.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/datepicker';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/datepicker/package.json';

```jsx import
import {DateField} from '@react-spectrum/datepicker';
import {Flex} from '@react-spectrum/layout';
```

---
category: Date and Time
keywords: [input, form, field, date, time]
---

# DateField

<PageDescription>{docs.exports.DateField.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DateField']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<DateField label="Event date" />
```

## Value

A `DateField` displays a placeholder by default. An initial, uncontrolled value can be provided to the `DateField` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Date values are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. `DateField` supports values of the following types:

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDate} /> – a date without any time components. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDate} /> function. Use this type to represent dates where the time is not important, such as a birthday or an all day calendar event.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> – a date with a time, but not in any specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDateTime} /> function. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a `ZonedDateTime`.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> – a date with a time in a specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} />, <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} />, or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> functions. Use this type to represent an exact moment in time at a particular location on Earth.

```tsx example
import {parseDate} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState(parseDate('2020-02-03'));

  return (
    <Flex gap="size-150" wrap>
      <DateField
        label="Date (uncontrolled)"
        defaultValue={parseDate('2020-02-03')} />
      <DateField
        label="Date (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### Time zones

`DateField` is time zone aware when a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated.

In most cases, your data will come from and be sent to a server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. [@internationalized/date](react-aria:internationalized/date/) includes functions for parsing strings in multiple formats into <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> objects. Which format you use will depend on what information you need to store.

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} /> – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `"2021-11-07T00:45[America/Los_Angeles]"` or `"2021-11-07T00:45-07:00[America/Los_Angeles]"`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} /> – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `"2021-11-07T07:45:00Z"`), or stored with a particular offset (e.g. `"2021-11-07T07:45:00-07:00"`). A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for `parseAbsolute`, and accepts the same formats.

```tsx example
import {parseZonedDateTime} from '@internationalized/date';

<DateField
  label="Event date"
  defaultValue={parseZonedDateTime('2022-11-07T00:45[America/Los_Angeles]')} />
```

`DateField` displays times in the time zone included in the `ZonedDateTime` object. The above example is always displayed in Pacific Standard Time because the `America/Los_Angeles` time zone identifier is provided. [@internationalized/date](react-aria:internationalized/date/) includes functions for converting dates between time zones, or parsing a date directly into a specific time zone or the user's local time zone, as shown below.

```tsx example
import {parseAbsoluteToLocal} from '@internationalized/date';

<DateField
  label="Event date"
  defaultValue={parseAbsoluteToLocal('2021-11-07T07:45:00Z')}
/>
```

### Granularity

The `granularity` prop allows you to control the smallest unit that is displayed by a `DateField`. By default, `CalendarDate` values are displayed with `"day"` granularity (year, month, and day), and `CalendarDateTime` and `ZonedDateTime` values are displayed with `"minute"` granularity. More granular time values can be displayed by setting the `granularity` prop to `"second"`.

In addition, when a value with a time is provided but you wish to only display the date, you can set the granularity to `"day"`. This has no effect on the actual value (it still has a time component), only on what fields are displayed. In the following example, two DateFields are synchronized with the same value, but display different granularities.

```tsx example
function Example() {
  let [date, setDate] = React.useState(parseAbsoluteToLocal('2021-04-07T18:45:22Z'));

  return (
    <Flex gap="size-150" wrap>
      <DateField
        label="Date and time"
        granularity="second"
        value={date}
        onChange={setDate} />
      <DateField
        label="Date"
        granularity="day"
        value={date}
        onChange={setDate} />
    </Flex>
  );
}
```


If no `value` or `defaultValue` prop is passed, then the `granularity` prop also affects which type of value is emitted from the `onChange` event. Note that by default, time values will not have a time zone because none was supplied. You can override this by setting the `placeholderValue` prop explicitly. Values emitted from `onChange` will use the time zone of the placeholder value.

```tsx example
import {now} from '@internationalized/date';

<Flex gap="size-150" wrap>
  <DateField
    label="Event date"
    granularity="second" />
  <DateField
    label="Event date"
    placeholderValue={now('America/New_York')}
    granularity="second" />
</Flex>
```

### International calendars

`DateField` supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component.

Selected dates passed to `onChange` always use the same calendar system as the `value` or `defaultValue` prop. If no `value` or `defaultValue` is provided, then dates passed to `onChange` are always in the Gregorian calendar since this is the most commonly used. This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.

The below example displays a `DateField` in the Hindi language, using the Indian calendar. Dates emitted from `onChange` are in the Gregorian calendar.

```tsx example
import {Provider} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(null);
  return (
    <Provider locale="hi-IN-u-ca-indian">
      <DateField label="Date" value={date} onChange={setDate} />
      <p>Selected date: {date?.toString()}</p>
    </Provider>
  );
}
```

### HTML forms

DateField supports the `name` prop for integration with HTML forms. The value will be submitted to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string according to the granularity of the value. For example, if the date field allows selecting only a date then a string such as `"2023-02-03"` will be submitted, and if it allows selecting a time then a string such as `"2023-02-03T08:45:00"` will be submitted. See the [Value](#value) section above for more details about the supported value types.

```tsx example
<DateField label="Birth date" name="birthday" />
```

## Labeling

A visual label should be provided for the `DateField` using the `label` prop. If the `DateField` is required, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <DateField label="Birth date" />
  <DateField label="Birth date" isRequired necessityIndicator="icon" />
  <DateField label="Birth date" isRequired necessityIndicator="label" />
  <DateField label="Birth date" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the `DateField` for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `DateField`, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Events

`DateField` accepts an `onChange` prop which is triggered whenever the date is edited by the user. The example below uses `onChange` to update a separate element with a formatted version of the date in the user's locale and local time zone. This is done by converting the date to a native JavaScript `Date` object to pass to the formatter.

```tsx example
import {getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(parseDate('1985-07-03'));
  let formatter = useDateFormatter({dateStyle: 'full'});

  return (
    <>
      <DateField label="Birth date" value={date} onChange={setDate} />
      <p>Selected date: {date ? formatter.format(date.toDate(getLocalTimeZone())): '--'}</p>
    </>
  );
}
```

## Validation

DateField supports the `isRequired` prop to ensure the user enters a value, as well as minimum and maximum values, and custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the date field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <DateField label="Appointment date" name="date" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `DateField` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

### Minimum and maximum values

The `minValue` and `maxValue` props can also be used to ensure the value is within a specific range. This example only accepts dates after today.

```tsx example
import {today} from '@internationalized/date';

<Form validationBehavior="native" maxWidth="size-3000">
  <DateField
    label="Appointment date"
    /*- begin highlight -*/
    minValue={today(getLocalTimeZone())}
    /*- end highlight -*/
    defaultValue={parseDate('2022-02-03')} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

### Custom validation

The `validate` function can be used to perform custom validation logic. It receives the current field value, and should return a string or array of strings representing one or more error messages if the value is invalid.

This example validates that the selected date is a weekday and not a weekend according to the current locale.

```tsx example
import {isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let {locale} = useLocale();

  return (
    <Form validationBehavior="native" maxWidth="size-3000">
      <DateField
        label="Appointment date"
        /*- begin highlight -*/
        validate={date => date && isWeekend(date, locale) ? 'We are closed on weekends.' : null}
        /*- end highlight -*/
        defaultValue={parseDate('2023-10-28')} />
      <ButtonGroup>
        <Button type="submit" variant="primary">Submit</Button>
        <Button type="reset" variant="secondary">Reset</Button>
      </ButtonGroup>
    </Form>
  );
}
```

## Props

<PropTable component={docs.exports.DateField} links={docs.links} />

## Visual options

### Quiet

```tsx example
<DateField label="Birth date" isQuiet />
```

### Disabled

```tsx example
<DateField label="Birth date" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the DateField's value immutable. Unlike `isDisabled`, the DateField remains focusable.

```tsx example
<DateField label="Birth date" value={today(getLocalTimeZone())} isReadOnly />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the `DateField`. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the `DateField` and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<DateField label="Birth date" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a DateField. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <DateField label="Date" defaultValue={today(getLocalTimeZone())} validationState="valid" description="Select a meeting date." />
  <DateField label="Date" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

`DateField` also supports displaying the expected date format for the user's locale automatically using the `showFormatHelpText` prop.

```tsx example
<DateField label="Birth date" showFormatHelpText />
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a DateField.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<DateField
  label="Appointment date"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Appointment changes</Heading>
      <Content>Your appointment date cannot be changed once it is scheduled.</Content>
    </ContextualHelp>
  } />
```

### Placeholder value

When no value is set, a placeholder is shown. The format of the placeholder is influenced by the `granularity` and `placeholderValue` props. `placeholderValue` also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys. By default, the `placeholderValue` is the current date at midnight, but you can set it to a more appropriate value if needed.

```tsx example
import {CalendarDate} from '@internationalized/date';

<DateField label="Birth date" placeholderValue={new CalendarDate(1980, 1, 1)} />
```

### Hide time zone

When a `ZonedDateTime` object is provided as the value of a `DateField`, the time zone abbreviation is displayed by default. However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the `hideTimeZone` option.

```tsx example
<DateField
  label="Appointment time"
  defaultValue={parseZonedDateTime('2022-11-07T10:45[America/Los_Angeles]')}
  hideTimeZone />
```

### Hour cycle

By default, `DateField` displays times in either 12 or 24 hour hour format depending on the user's locale. However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. This example forces the `DateField` to use 24-hour time, regardless of the locale.

```tsx example
<DateField
  label="Appointment time"
  granularity="minute"
  hourCycle={24} />
```

---

### Packages @Adobe React Spectrum Docs Datepicker DatePicker (`packages/@adobe/react-spectrum/docs/datepicker/DatePicker.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/datepicker';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/datepicker/package.json';

```jsx import
import {DatePicker} from '@react-spectrum/datepicker';
import {Flex} from '@react-spectrum/layout';
```

---
category: Date and Time
keywords: [input, form, field, date, time]
---

# DatePicker

<PageDescription>{docs.exports.DatePicker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DatePicker']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<DatePicker label="Event date" />
```

## Value

A `DatePicker` displays a placeholder by default. An initial, uncontrolled value can be provided to the `DatePicker` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Date values are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. `DatePicker` supports values of the following types:

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDate} /> – a date without any time components. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDate} /> function. Use this type to represent dates where the time is not important, such as a birthday or an all day calendar event.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> – a date with a time, but not in any specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDateTime} /> function. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a `ZonedDateTime`.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> – a date with a time in a specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} />, <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} />, or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> functions. Use this type to represent an exact moment in time at a particular location on Earth.

```tsx example
import {parseDate} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState(parseDate('2020-02-03'));

  return (
    <Flex gap="size-150" wrap>
      <DatePicker
        label="Date (uncontrolled)"
        defaultValue={parseDate('2020-02-03')} />
      <DatePicker
        label="Date (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### Time zones

`DatePicker` is time zone aware when a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated.

In most cases, your data will come from and be sent to a server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. [@internationalized/date](react-aria:internationalized/date/) includes functions for parsing strings in multiple formats into <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> objects. Which format you use will depend on what information you need to store.

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} /> – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `"2021-11-07T00:45[America/Los_Angeles]"` or `"2021-11-07T00:45-07:00[America/Los_Angeles]"`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} /> – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `"2021-11-07T07:45:00Z"`), or stored with a particular offset (e.g. `"2021-11-07T07:45:00-07:00"`). A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for `parseAbsolute`, and accepts the same formats.

```tsx example
import {parseZonedDateTime} from '@internationalized/date';

<DatePicker
  label="Event date"
  defaultValue={parseZonedDateTime('2022-11-07T00:45[America/Los_Angeles]')} />
```

`DatePicker` displays times in the time zone included in the `ZonedDateTime` object. The above example is always displayed in Pacific Standard Time because the `America/Los_Angeles` time zone identifier is provided. [@internationalized/date](react-aria:internationalized/date/) includes functions for converting dates between time zones, or parsing a date directly into a specific time zone or the user's local time zone, as shown below.

```tsx example
import {parseAbsoluteToLocal} from '@internationalized/date';

<DatePicker
  label="Event date"
  defaultValue={parseAbsoluteToLocal('2021-11-07T07:45:00Z')}
/>
```

### Granularity

The `granularity` prop allows you to control the smallest unit that is displayed by a `DatePicker`. By default, `CalendarDate` values are displayed with `"day"` granularity (year, month, and day), and `CalendarDateTime` and `ZonedDateTime` values are displayed with `"minute"` granularity. More granular time values can be displayed by setting the `granularity` prop to `"second"`.

In addition, when a value with a time is provided but you wish to only display the date, you can set the granularity to `"day"`. This has no effect on the actual value (it still has a time component), only on what fields are displayed. In the following example, two DatePickers are synchronized with the same value, but display different granularities.

```tsx example
function Example() {
  let [date, setDate] = React.useState(parseAbsoluteToLocal('2021-04-07T18:45:22Z'));

  return (
    <Flex gap="size-150" wrap>
      <DatePicker
        label="Date and time"
        granularity="second"
        value={date}
        onChange={setDate} />
      <DatePicker
        label="Date"
        granularity="day"
        value={date}
        onChange={setDate} />
    </Flex>
  );
}
```

If no `value` or `defaultValue` prop is passed, then the `granularity` prop also affects which type of value is emitted from the `onChange` event. Note that by default, time values will not have a time zone because none was supplied. You can override this by setting the `placeholderValue` prop explicitly. Values emitted from `onChange` will use the time zone of the placeholder value.

```tsx example
import {now} from '@internationalized/date';

<Flex gap="size-150" wrap>
  <DatePicker
    label="Event date"
    granularity="second" />
  <DatePicker
    label="Event date"
    placeholderValue={now('America/New_York')}
    granularity="second" />
</Flex>
```

### International calendars

`DatePicker` supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component.

Selected dates passed to `onChange` always use the same calendar system as the `value` or `defaultValue` prop. If no `value` or `defaultValue` is provided, then dates passed to `onChange` are always in the Gregorian calendar since this is the most commonly used. This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.

The below example displays a `DatePicker` in the Hindi language, using the Indian calendar. Dates emitted from `onChange` are in the Gregorian calendar.

```tsx example
import {Provider} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(null);
  return (
    <Provider locale="hi-IN-u-ca-indian">
      <DatePicker label="Date" value={date} onChange={setDate} />
      <p>Selected date: {date?.toString()}</p>
    </Provider>
  );
}
```

### Custom calendar systems

`DatePicker` also supports custom calendar systems that implement custom business rules. An example would be a fiscal year calendar that follows a [4-5-4 format](https://nrf.com/resources/4-5-4-calendar), where month ranges don't follow the usual Gregorian calendar. This prop is used when displaying the calendar popover component.

The `createCalendar` prop accepts a function that returns an instance of the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.Calendar} /> interface. See the docs in [@internationalized/date](react-aria:internationalized/date/Calendar#custom-calendars) for an example implementation.

```tsx import
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar} from '@internationalized/date';
```

```
/* Detailed source-code truncated for AI context efficiency. */
```

### HTML forms

DatePicker supports the `name` prop for integration with HTML forms. The value will be submitted to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string according to the granularity of the value. For example, if the date picker allows selecting only a date then a string such as `"2023-02-03"` will be submitted, and if it allows selecting a time then a string such as `"2023-02-03T08:45:00"` will be submitted. See the [Value](#value) section above for more details about the supported value types.

```tsx example
<DatePicker label="Birth date" name="birthday" />
```

## Labeling

A visual label should be provided for the `DatePicker` using the `label` prop. If the `DatePicker` is required, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <DatePicker label="Birth date" />
  <DatePicker label="Birth date" isRequired necessityIndicator="icon" />
  <DatePicker label="Birth date" isRequired necessityIndicator="label" />
  <DatePicker label="Birth date" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the `DatePicker` for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `DatePicker`, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Events

`DatePicker` accepts an `onChange` prop which is triggered whenever the date is edited by the user. The example below uses `onChange` to update a separate element with a formatted version of the date in the user's locale and local time zone. This is done by converting the date to a native JavaScript `Date` object to pass to the formatter.

```tsx example
import {getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(parseDate('1985-07-03'));
  let formatter = useDateFormatter({dateStyle: 'full'});

  return (
    <>
      <DatePicker label="Birth date" value={date} onChange={setDate} />
      <p>Selected date: {date ? formatter.format(date.toDate(getLocalTimeZone())) : '--'}</p>
    </>
  );
}
```

## Validation

DatePicker supports the `isRequired` prop to ensure the user enters a value, as well as minimum and maximum values, and custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the date picker or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <DatePicker label="Appointment date" name="date" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `DatePicker` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

### Minimum and maximum values

The `minValue` and `maxValue` props can also be used to ensure the value is within a specific range. This example only accepts dates after today.

```tsx example
import {today} from '@internationalized/date';

<Form validationBehavior="native" maxWidth="size-3000">
  <DatePicker
    label="Appointment date"
    /*- begin highlight -*/
    minValue={today(getLocalTimeZone())}
    /*- end highlight -*/
    defaultValue={parseDate('2022-02-03')} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```


### Unavailable dates

`DatePicker` supports marking certain dates as _unavailable_.  These dates cannot be selected by the user and are displayed with a crossed out appearance in the calendar. In the date field, an invalid state is displayed if a user enters an unavailable date. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable.

This example includes multiple unavailable date ranges, e.g. dates when no appointments are available. In addition, all weekends are unavailable. The `minValue` prop is also used to prevent selecting dates before today.

```tsx example
import {today, isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let now = today(getLocalTimeZone());
  let disabledRanges = [
    [now, now.add({days: 5})],
    [now.add({days: 14}), now.add({days: 16})],
    [now.add({days: 23}), now.add({days: 24})],
  ];

  let {locale} = useLocale();
  return (
    <DatePicker
      label="Appointment date"
      minValue={today(getLocalTimeZone())}
      /*- begin highlight -*/
      isDateUnavailable={date => isWeekend(date, locale) || disabledRanges.some((interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0)}
      /*- end highlight -*/
      validationBehavior="native" />
  );
}
```

### Custom validation

The `validate` function can be used to perform custom validation logic. It receives the current date value, and should return a string or array of strings representing one or more error messages if the value is invalid.

This example validates that the selected date is a weekday and not a weekend according to the current locale.

```tsx example
import {isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let {locale} = useLocale();

  return (
    <Form validationBehavior="native" maxWidth="size-3000">
      <DatePicker
        label="Appointment date"
        /*- begin highlight -*/
        validate={date => date && isWeekend(date, locale) ? 'We are closed on weekends.' : null}
        /*- end highlight -*/
        defaultValue={parseDate('2023-10-28')} />
      <ButtonGroup>
        <Button type="submit" variant="primary">Submit</Button>
        <Button type="reset" variant="secondary">Reset</Button>
      </ButtonGroup>
    </Form>
  );
}
```

## Props

<PropTable component={docs.exports.DatePicker} links={docs.links} />

## Visual options

### Quiet

```tsx example
<DatePicker label="Birth date" isQuiet />
```

### Disabled

```tsx example
<DatePicker label="Birth date" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the DatePicker's value immutable. Unlike `isDisabled`, the DatePicker remains focusable.

```tsx example
<DatePicker label="Birth date" value={today(getLocalTimeZone())} isReadOnly />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the `DatePicker`. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the `DatePicker` and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<DatePicker label="Birth date" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a DatePicker. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <DatePicker label="Date" defaultValue={today(getLocalTimeZone())} validationState="valid" description="Select a meeting date." />
  <DatePicker label="Date" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

`DatePicker` also supports displaying the expected date format for the user's locale automatically using the `showFormatHelpText` prop.

```tsx example
<DatePicker label="Birth date" showFormatHelpText />
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a DatePicker.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<DatePicker
  label="Appointment date"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Appointment changes</Heading>
      <Content>Your appointment date cannot be changed once it is scheduled.</Content>
    </ContextualHelp>
  } />
```

### Placeholder value

When no value is set, a placeholder is shown. The format of the placeholder is influenced by the `granularity` and `placeholderValue` props. `placeholderValue` also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys, as well as the default month shown in the calendar popover. By default, the `placeholderValue` is the current date at midnight, but you can set it to a more appropriate value if needed.

```tsx example
import {CalendarDate} from '@internationalized/date';

<DatePicker label="Birth date" placeholderValue={new CalendarDate(1980, 1, 1)} />
```

### Maximum visible months

By default, the calendar popover displays a single month. The `maxVisibleMonths` prop allows displaying up to 3 months at a time, if screen space permits.

```tsx example
<DatePicker label="Appointment date" maxVisibleMonths={3} />
```

### Page behavior

By default, when pressing the next or previous buttons, pagination will advance by the `maxVisibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`.

```tsx example
<DatePicker label="Appointment date" maxVisibleMonths={3} pageBehavior="single" />
```

### Hide time zone

When a `ZonedDateTime` object is provided as the value of a `DatePicker`, the time zone abbreviation is displayed by default. However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the `hideTimeZone` option.

```tsx example
<DatePicker
  label="Appointment time"
  defaultValue={parseZonedDateTime('2022-11-07T10:45[America/Los_Angeles]')}
  hideTimeZone />
```

### Hour cycle

By default, `DatePicker` displays times in either 12 or 24 hour hour format depending on the user's locale. However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. This example forces the `DatePicker` to use 24-hour time, regardless of the locale.

```tsx example
<DatePicker
  label="Appointment time"
  granularity="minute"
  hourCycle={24} />
```

### Custom first day of week

By default, the first day of the week is automatically set based on the current locale. This can be changed by setting the `firstDayOfWeek` prop to `'sun'`, `'mon'`, `'tue'`, `'wed'`, `'thu'`, `'fri'`, or `'sat'`.

```tsx example
<DatePicker label="Appointment date" firstDayOfWeek="mon" />
```

## Testing

The DatePicker features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your configuration, this overlay may render as a tray or a popover. Please see the following sections in the
testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/datepicker/test/DateField.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Datepicker DateRangePicker (`packages/@adobe/react-spectrum/docs/datepicker/DateRangePicker.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/datepicker';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/datepicker/package.json';

```jsx import
import {DateRangePicker} from '@react-spectrum/datepicker';
import {Flex} from '@react-spectrum/layout';
```

---
category: Date and Time
keywords: [input, form, field, date, time]
---

# DateRangePicker

<PageDescription>{docs.exports.DateRangePicker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DateRangePicker']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<DateRangePicker label="Date range" />
```

## Value

A `DateRangePicker` displays a placeholder by default. An initial, uncontrolled value can be provided to the `DateRangePicker` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Date ranges are objects with `start` and `end` properties containing date values, which are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. `DateRangePicker` supports values of the following types:

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDate} /> – a date without any time components. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDate} /> function. Use this type to represent dates where the time is not important, such as a birthday or an all day calendar event.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> – a date with a time, but not in any specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseDateTime} /> function. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored as a `ZonedDateTime`.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> – a date with a time in a specific time zone. May be parsed from a string representation using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} />, <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} />, or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> functions. Use this type to represent an exact moment in time at a particular location on Earth.

```tsx example
import {parseDate} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState({
    start: parseDate('2020-02-03'),
    end: parseDate('2020-02-08')
  });

  return (
    <Flex gap="size-150" wrap>
      <DateRangePicker
        label="Date range (uncontrolled)"
        defaultValue={{
          start: parseDate('2020-02-03'),
          end: parseDate('2020-02-08')
        }} />
      <DateRangePicker
        label="Date range (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

### Time zones

`DateRangePicker` is time zone aware when <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> objects are provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated.

In most cases, your data will come from and be sent to a server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. [@internationalized/date](react-aria:internationalized/date/) includes functions for parsing strings in multiple formats into <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> objects. Which format you use will depend on what information you need to store.

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} /> – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `"2021-11-07T00:45[America/Los_Angeles]"` or `"2021-11-07T00:45-07:00[America/Los_Angeles]"`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} /> – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `"2021-11-07T07:45:00Z"`), or stored with a particular offset (e.g. `"2021-11-07T07:45:00-07:00"`). A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for `parseAbsolute`, and accepts the same formats.

```tsx example
import {parseZonedDateTime} from '@internationalized/date';

<DateRangePicker
  label="Date range"
  defaultValue={{
    start: parseZonedDateTime('2022-11-07T00:45[America/Los_Angeles]'),
    end: parseZonedDateTime('2022-11-08T11:15[America/Los_Angeles]')
  }} />
```

`DateRangePicker` displays times in the time zone included in the `ZonedDateTime` object. The above example is always displayed in Pacific Standard Time because the `America/Los_Angeles` time zone identifier is provided. [@internationalized/date](react-aria:internationalized/date/) includes functions for converting dates between time zones, or parsing a date directly into a specific time zone or the user's local time zone, as shown below.

```tsx example
import {parseAbsoluteToLocal} from '@internationalized/date';

<DateRangePicker
  label="Date range"
  defaultValue={{
    start: parseAbsoluteToLocal('2021-11-07T07:45:00Z'),
    end: parseAbsoluteToLocal('2021-11-08T14:25:00Z')
  }}
/>
```

### Granularity

The `granularity` prop allows you to control the smallest unit that is displayed by a `DateRangePicker`. By default, `CalendarDate` values are displayed with `"day"` granularity (year, month, and day), and `CalendarDateTime` and `ZonedDateTime` values are displayed with `"minute"` granularity. More granular time values can be displayed by setting the `granularity` prop to `"second"`.

In addition, when a value with a time is provided but you wish to only display the date, you can set the granularity to `"day"`. This has no effect on the actual value (it still has a time component), only on what fields are displayed. In the following example, two DateRangePickers are synchronized with the same value, but display different granularities.

```tsx example
function Example() {
  let [date, setDate] = React.useState({
    start: parseAbsoluteToLocal('2021-04-07T18:45:22Z'),
    end: parseAbsoluteToLocal('2021-04-08T20:00:00Z')
  });

  return (
    <Flex gap="size-150" wrap>
      <DateRangePicker
        label="Date and time range"
        granularity="second"
        value={date}
        onChange={setDate} />
      <DateRangePicker
        label="Date range"
        granularity="day"
        value={date}
        onChange={setDate} />
    </Flex>
  );
}
```


If no `value` or `defaultValue` prop is passed, then the `granularity` prop also affects which type of value is emitted from the `onChange` event. Note that by default, time values will not have a time zone because none was supplied. You can override this by setting the `placeholderValue` prop explicitly. Values emitted from `onChange` will use the time zone of the placeholder value.

```tsx example
import {now} from '@internationalized/date';

<Flex gap="size-150" wrap>
  <DateRangePicker
    label="Date range"
    granularity="second" />
  <DateRangePicker
    label="Date range"
    placeholderValue={now('America/New_York')}
    granularity="second" />
</Flex>
```

### International calendars

`DateRangePicker` supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more. Dates are automatically displayed in the appropriate calendar system for the user's locale. The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the `Provider` component.

Selected dates passed to `onChange` always use the same calendar system as the `value` or `defaultValue` prop. If no `value` or `defaultValue` is provided, then dates passed to `onChange` are always in the Gregorian calendar since this is the most commonly used. This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.

The below example displays a `DateRangePicker` in the Hindi language, using the Indian calendar. Dates emitted from `onChange` are in the Gregorian calendar.

```tsx example
import {Provider} from '@adobe/react-spectrum';

function Example() {
  let [range, setRange] = React.useState(null);
  return (
    <Provider locale="hi-IN-u-ca-indian">
      <DateRangePicker label="Date range" value={range} onChange={setRange} />
      <p>Start date: {range?.start.toString()}</p>
      <p>End date: {range?.end.toString()}</p>
    </Provider>
  );
}
```

### Custom calendar systems

`DateRangePicker` also supports custom calendar systems that implement custom business rules. An example would be a fiscal year calendar that follows a [4-5-4 format](https://nrf.com/resources/4-5-4-calendar), where month ranges don't follow the usual Gregorian calendar. This prop is used when displaying the range calendar popover component.

The `createCalendar` prop accepts a function that returns an instance of the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.Calendar} /> interface. See the docs in [@internationalized/date](react-aria:internationalized/date/Calendar#custom-calendars) for an example implementation.

```tsx import
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar} from '@internationalized/date';
```

```
/* Detailed source-code truncated for AI context efficiency. */
```

### HTML forms

DateRangePicker supports the `startName` and `endName` props for integration with HTML forms. The values will be submitted to the server as [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted strings according to the granularity of the value. For example, if the date range picker allows selecting only dates then strings such as `"2023-02-03"` will be submitted, and if it allows selecting times then strings such as `"2023-02-03T08:45:00"` will be submitted. See the [Value](#value) section above for more details about the supported value types.

```tsx example
<DateRangePicker label="Trip dates" startName="startDate" endName="endDate" />
```

## Labeling

A visual label should be provided for the `DateRangePicker` using the `label` prop. If the `DateRangePicker` is required, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <DateRangePicker label="Date range" />
  <DateRangePicker label="Date range" isRequired necessityIndicator="icon" />
  <DateRangePicker label="Date range" isRequired necessityIndicator="label" />
  <DateRangePicker label="Date range" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the `DateRangePicker` for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `DateRangePicker`, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Events

`DateRangePicker` accepts an `onChange` prop which is triggered whenever the start or end date is edited by the user. The example below uses `onChange` to update a separate element with a formatted version of the date range in the user's locale and local time zone. This is done by converting the dates to native JavaScript `Date` objects to pass to the formatter.

```tsx example
import {getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [range, setRange] = React.useState({
    start: parseDate('2020-07-03'),
    end: parseDate('2020-07-10')
  });
  let formatter = useDateFormatter({dateStyle: 'long'});

  return (
    <>
      <DateRangePicker label="Date range" value={range} onChange={setRange} />
      <p>Selected date: {range ? formatter.formatRange(range.start.toDate(getLocalTimeZone()), range.end.toDate(getLocalTimeZone())) : '--'}</p>
    </>
  );
}
```

## Validation

DateRangePicker supports the `isRequired` prop to ensure the user enters a value, as well as minimum and maximum values, and custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the date range picker or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <DateRangePicker label="Date range" startName="startDate" endName="endDate" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `DateRangePicker` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

### Minimum and maximum values

The `minValue` and `maxValue` props can also be used to ensure the value is within a specific range. `DateRangePicker` also validates that the end date is after the start date. This example only accepts dates after today.

```tsx example
import {today} from '@internationalized/date';

<Form validationBehavior="native" maxWidth="size-3000">
  <DateRangePicker
    label="Trip dates"
    /*- begin highlight -*/
    minValue={today(getLocalTimeZone())}
    /*- end highlight -*/
    defaultValue={{
      start: parseDate('2022-02-03'),
      end: parseDate('2022-05-03')
    }} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

### Custom validation

The `validate` function can be used to perform custom validation logic. It receives the current date range, and should return a string or array of strings representing one or more error messages if the value is invalid.

This example validates that the selected date range is a maximum of 1 week in duration.

```tsx example
<Form validationBehavior="native" maxWidth="size-3000">
  <DateRangePicker
    label="Trip dates"
    /*- begin highlight -*/
    validate={range => range?.end.compare(range.start) > 7 ? 'Maximum stay duration is 1 week.' : null}
    /*- end highlight -*/
    defaultValue={{
      start: today(getLocalTimeZone()),
      end: today(getLocalTimeZone()).add({ weeks: 1, days: 3 })
    }} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

### Unavailable dates

`DateRangePicker` supports marking certain dates as _unavailable_. These dates cannot be selected by the user and are displayed with a crossed out appearance in the calendar. The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable.

Note that by default, users may not select non-contiguous ranges, i.e. ranges that contain unavailable dates within them. Once a start date is selected in the calendar, enabled dates will be restricted to subsequent dates until an unavailable date is hit. While this is handled automatically in the calendar, additional validation logic must be provided to ensure an invalid state is displayed in the date field. This can be achieved using the `validationState` prop. See [below](#non-contiguous-ranges) for an example of how to allow non-contiguous ranges.

This example includes multiple unavailable date ranges, e.g. dates when a rental house is not available. The `minValue` prop is also used to prevent selecting dates before today. The `validationState` prop is used to mark selected date ranges with unavailable dates in the middle as invalid.

```tsx example
import {today} from '@internationalized/date';

function Example() {
  let now = today(getLocalTimeZone());
  let disabledRanges = [
    [now, now.add({days: 5})],
    [now.add({days: 14}), now.add({days: 16})],
    [now.add({days: 23}), now.add({days: 24})],
  ];

  return (
    <DateRangePicker
      label="Trip dates"
      minValue={today(getLocalTimeZone())}
      /*- begin highlight -*/
      isDateUnavailable={date => disabledRanges.some((interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0)}
      validate={value => disabledRanges.some(interval => value && value.end.compare(interval[0]) >= 0 && value.start.compare(interval[1]) <= 0) ? 'Selected date range may not include unavailable dates.' : null}
      /*- end highlight -*/
      validationBehavior="native" />
  );
}
```

### Non-contiguous ranges

The `allowsNonContiguousRanges` prop enables a range to be selected even if there are unavailable dates in the middle. The value emitted in the `onChange` event will still be a single range with a `start` and `end` property, but unavailable dates will not be displayed as selected. It is up to applications to split the full selected range into multiple as needed for business logic.

This example prevents selecting weekends, but allows selecting ranges that span multiple weeks.

```tsx example
import {isWeekend} from '@internationalized/date';
import {useLocale} from '@adobe/react-spectrum';

function Example() {
  let {locale} = useLocale();

  return <DateRangePicker label="Time off request" isDateUnavailable={date => isWeekend(date, locale)} allowsNonContiguousRanges />
}
```

## Props

<PropTable component={docs.exports.DateRangePicker} links={docs.links} />

## Visual options

### Quiet

```tsx example
<DateRangePicker label="Date range" isQuiet />
```

### Disabled

```tsx example
<DateRangePicker label="Date range" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the DateRangePicker's value immutable. Unlike `isDisabled`, the DateRangePicker remains focusable.

```tsx example
<DateRangePicker label="Date range" value={{start: today(getLocalTimeZone()), end: today(getLocalTimeZone()).add({weeks: 1})}} isReadOnly />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the `DateRangePicker`. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the `DateRangePicker` and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<DateRangePicker label="Date range" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a `DateRangePicker`. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <DateRangePicker label="Date range" defaultValue={{start: today(getLocalTimeZone()), end: today(getLocalTimeZone()).add({weeks: 1})}} validationState="valid" description="Select your trip dates." />
  <DateRangePicker label="Date range" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

`DateRangePicker` also supports displaying the expected date format for the user's locale automatically using the `showFormatHelpText` prop.

```tsx example
<DateRangePicker label="Date range" showFormatHelpText />
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a DateRangePicker.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<DateRangePicker
  label="Trip dates"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Date changes</Heading>
      <Content>Your trip dates cannot be changed once scheduled.</Content>
    </ContextualHelp>
  } />
```

### Placeholder value

When no value is set, a placeholder is shown. The format of the placeholder is influenced by the `granularity` and `placeholderValue` props. `placeholderValue` also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys, as well as the default month shown in the calendar popover. By default, the `placeholderValue` is the current date at midnight, but you can set it to a more appropriate value if needed.

```tsx example
import {CalendarDate} from '@internationalized/date';

<DateRangePicker label="Date range" placeholderValue={new CalendarDate(1980, 1, 1)} />
```

### Maximum visible months

By default, the calendar popover displays a single month. The `maxVisibleMonths` prop allows displaying up to 3 months at a time, if screen space permits.

```tsx example
<DateRangePicker label="Date range" maxVisibleMonths={3} />
```

### Page behavior

By default, when pressing the next or previous buttons, pagination will advance by the `maxVisibleMonths` value. This behavior can be changed to page by single months instead, by setting `pageBehavior` to `single`.

```tsx example
<DateRangePicker label="Date range" maxVisibleMonths={3} pageBehavior="single" />
```

### Hide time zone

When `ZonedDateTime` objects are provided as the value of a `DateRangePicker`, the time zone abbreviation is displayed by default. However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the `hideTimeZone` option.

```tsx example
<DateRangePicker
  label="Date range"
  defaultValue={{
    start: parseZonedDateTime('2022-11-07T10:45[America/Los_Angeles]'),
    end: parseZonedDateTime('2022-11-08T19:45[America/Los_Angeles]')
  }}
  hideTimeZone />
```

### Hour cycle

By default, `DateRangePicker` displays times in either 12 or 24 hour hour format depending on the user's locale. However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. This example forces the `DateRangePicker` to use 24-hour time, regardless of the locale.

```tsx example
<DateRangePicker
  label="Date range"
  granularity="minute"
  hourCycle={24} />
```

### Custom first day of week

By default, the first day of the week is automatically set based on the current locale. This can be changed by setting the `firstDayOfWeek` prop to `'sun'`, `'mon'`, `'tue'`, `'wed'`, `'thu'`, `'fri'`, or `'sat'`.

```tsx example
<DateRangePicker label="Date range" firstDayOfWeek="mon" />
```

## Testing

The DateRangePicker features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your configuration, this overlay may render as a tray or a popover. Please see the following sections in the
testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/datepicker/docs/DateRangePicker.mdx) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Datepicker TimeField (`packages/@adobe/react-spectrum/docs/datepicker/TimeField.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/datepicker';
import i18nDocs from 'docs:@internationalized/date';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/datepicker/package.json';

```jsx import
import {TimeField} from '@react-spectrum/datepicker';
import {Flex} from '@react-spectrum/layout';
```

---
category: Date and Time
keywords: [input, form, field, time]
---

# TimeField

<PageDescription>{docs.exports.TimeField.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['TimeField']}
  sourceData={[]}
  since="3.19.0" />

## Example

```tsx example
<TimeField label="Event time" />
```

## Value

A `TimeField` displays a placeholder by default. An initial, uncontrolled value can be provided to the `TimeField` using the `defaultValue` prop. Alternatively, a controlled value can be provided using the `value` prop.

Time values are provided using objects in the [@internationalized/date](react-aria:internationalized/date/) package. This library handles correct international date and time manipulation across calendars, time zones, and other localization concerns.

`TimeField` only supports selecting times, but values with date components are also accepted. By default, `TimeField` will emit <TypeLink links={i18nDocs.links} type={i18nDocs.exports.Time} /> objects in the `onChange` event, but if a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.CalendarDateTime} /> or <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is passed as the `value` or `defaultValue`, values of that type will be emitted, changing only the time and preserving the date components.

```tsx example
import {Time} from '@internationalized/date';

function Example() {
  let [value, setValue] = React.useState(new Time(11, 45));

  return (
    <Flex gap="size-150" wrap>
      <TimeField
        label="Time (uncontrolled)"
        defaultValue={new Time(11, 45)} />
      <TimeField
        label="Time (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

`Time` values may also be parsed from strings using the <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseTime} /> function. This accepts [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Times) formatted time strings such as `"04:45:23.123"`. The `toString` method of a `Time` object can also be used to convert a time object to a string.

### Time zones

`TimeField` is time zone aware when a <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> object is provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated.

In most cases, your data will come from and be sent to a server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string. [@internationalized/date](react-aria:internationalized/date/) includes functions for parsing strings in multiple formats into <TypeLink links={i18nDocs.links} type={i18nDocs.exports.ZonedDateTime} /> objects. Which format you use will depend on what information you need to store.

* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseZonedDateTime} /> – This function parses a date with an explicit time zone and optional UTC offset attached (e.g. `"2021-11-07T00:45[America/Los_Angeles]"` or `"2021-11-07T00:45-07:00[America/Los_Angeles]"`). This format preserves the maximum amount of information. If the exact local time and time zone that a user selected is important, use this format. Storing the time zone and offset that was selected rather than converting to UTC ensures that the local time is correct regardless of daylight saving rule changes (e.g. if a locale abolishes DST). Examples where this applies include calendar events, reminders, and other times that occur in a particular location.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsolute} /> – This function parses an absolute date and time that occurs at the same instant at all locations on Earth. It can be represented in UTC (e.g. `"2021-11-07T07:45:00Z"`), or stored with a particular offset (e.g. `"2021-11-07T07:45:00-07:00"`). A time zone identifier, e.g. `America/Los_Angeles`, must be passed, and the result will be converted into that time zone. Absolute times are the best way to represent events that occurred in the past, or future events where an exact time is needed, regardless of time zone.
* <TypeLink links={i18nDocs.links} type={i18nDocs.exports.parseAbsoluteToLocal} /> – This function parses an absolute date and time into the current user's local time zone. It is a shortcut for `parseAbsolute`, and accepts the same formats.

```tsx example
import {parseZonedDateTime} from '@internationalized/date';

<TimeField
  label="Event time"
  defaultValue={parseZonedDateTime('2022-11-07T00:45[America/Los_Angeles]')} />
```

`TimeField` displays times in the time zone included in the `ZonedDateTime` object. The above example is always displayed in Pacific Standard Time because the `America/Los_Angeles` time zone identifier is provided. [@internationalized/date](react-aria:internationalized/date/) includes functions for converting dates between time zones, or parsing a date directly into a specific time zone or the user's local time zone, as shown below.

```tsx example
import {parseAbsoluteToLocal} from '@internationalized/date';

<TimeField
  label="Event time"
  defaultValue={parseAbsoluteToLocal('2021-11-07T07:45:00Z')}
/>
```

### Granularity

The `granularity` prop allows you to control the smallest unit that is displayed by a `TimeField`. By default, times are displayed with `"minute"` granularity. More granular time values can be displayed by setting the `granularity` prop to `"second"`.

```tsx example
<TimeField
  label="Event time"
  granularity="second"
  defaultValue={parseAbsoluteToLocal('2021-04-07T18:45:22Z')} />
```

### HTML forms

TimeField supports the `name` prop for integration with HTML forms. The value will be submitted to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted string, e.g. `"08:45:00"`.

```tsx example
<TimeField label="Meeting time" name="meetingTime" />
```

## Labeling

A visual label should be provided for the `TimeField` using the `label` prop. If the `TimeField` is required, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <TimeField label="Event time" />
  <TimeField label="Event time" isRequired necessityIndicator="icon" />
  <TimeField label="Event time" isRequired necessityIndicator="label" />
  <TimeField label="Event time" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the `TimeField` for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a `TimeField`, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Events

`TimeField` accepts an `onChange` prop which is triggered whenever the time is edited by the user. The example below uses `onChange` to update a separate element with a formatted version of the date in the user's locale and local time zone. This is done by converting the date to a native JavaScript `Date` object to pass to the formatter. The `TimeField` allows editing the time components while keeping the date fixed.

```tsx example
import {useDateFormatter} from '@adobe/react-spectrum';

function Example() {
  let [date, setDate] = React.useState(parseAbsoluteToLocal('2021-04-07T18:45:22Z'));
  let formatter = useDateFormatter({dateStyle: 'long', timeStyle: 'long'});

  return (
    <>
      <TimeField label="Time" value={date} onChange={setDate} />
      <p>Selected date and time: {(date?.toDate && formatter.format(date.toDate())) || (date && date.toString()) || '--'}</p>
    </>
  );
}
```

## Validation

TimeField supports the `isRequired` prop to ensure the user enters a value, as well as minimum and maximum values, and custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the time field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <TimeField label="Meeting time" name="time" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `TimeField` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

### Minimum and maximum values

The `minValue` and `maxValue` props can also be used to ensure the value is within a specific range. This example only accepts times between 9 AM and 5 PM.

```tsx example
<Form validationBehavior="native" maxWidth="size-3000">
  <TimeField
    label="Meeting time"
    /*- begin highlight -*/
    minValue={new Time(9)}
    maxValue={new Time(17)}
    /*- end highlight -*/
    defaultValue={new Time(8)} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

### Custom validation

The `validate` function can be used to perform custom validation logic. It receives the current field value, and should return a string or array of strings representing one or more error messages if the value is invalid.

This example validates that the selected time is on a 15 minute increment.

```tsx example
<Form validationBehavior="native" maxWidth="size-3000">
  <TimeField
    label="Meeting time"
    /*- begin highlight -*/
    validate={time => time?.minute % 15 !== 0 ? 'Meetings start every 15 minutes.' : null}
    /*- end highlight -*/
    defaultValue={new Time(9, 25)} />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

## Props

<PropTable component={docs.exports.TimeField} links={docs.links} />

## Visual options

### Quiet

```tsx example
<TimeField label="Event time" isQuiet />
```

### Disabled

```tsx example
<TimeField label="Event time" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the TimeField's value immutable. Unlike `isDisabled`, the TimeField remains focusable.

```tsx example
<TimeField label="Event time" value={new Time(11)} isReadOnly />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the `TimeField`. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the `TimeField` and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<TimeField label="Event time" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a TimeField. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <TimeField label="Time" defaultValue={new Time(9)} validationState="valid" description="Select a meeting time." />
  <TimeField label="Time" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a TimeField.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<TimeField
  label="Appointment time"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Appointment changes</Heading>
      <Content>Your appointment time cannot be changed once it is scheduled.</Content>
    </ContextualHelp>
  } />
```

### Placeholder value

When no value is set, a placeholder is shown. The format of the placeholder is influenced by the `granularity` and `placeholderValue` props. `placeholderValue` also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys. By default, the `placeholderValue` is midnight, but you can set it to a more appropriate value if needed.

```tsx example
<TimeField label="Appointment time" placeholderValue={new Time(9)} />
```

### Hide time zone

When a `ZonedDateTime` object is provided as the value of a `TimeField`, the time zone abbreviation is displayed by default. However, if this is displayed elsewhere or implicit based on the usecase, it can be hidden using the `hideTimeZone` option.

```tsx example
<TimeField
  label="Appointment time"
  defaultValue={parseZonedDateTime('2022-11-07T10:45[America/Los_Angeles]')}
  hideTimeZone />
```

### Hour cycle

By default, `TimeField` displays times in either 12 or 24 hour hour format depending on the user's locale. However, this can be overridden using the `hourCycle` prop if needed for a specific usecase. This example forces the `TimeField` to use 24-hour time, regardless of the locale.

```tsx example
<TimeField
  label="Appointment time"
  hourCycle={24} />
```

---

### Packages @Adobe React Spectrum Docs Dialog AlertDialog (`packages/@adobe/react-spectrum/docs/dialog/AlertDialog.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/dialog';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/dialog/package.json';

```jsx import
import {ActionButton} from '@react-spectrum/button';
import {AlertDialog, DialogTrigger} from '@react-spectrum/dialog';
```

---
category: Overlays
keywords: [alert dialog]
---

# AlertDialog

<PageDescription>{docs.exports.AlertDialog.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['AlertDialog', 'DialogTrigger']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/alert-dialog/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<DialogTrigger>
  <ActionButton>Save</ActionButton>
  <AlertDialog
    title="Low Disk Space"
    variant="warning"
    primaryActionLabel="Confirm">
    You are running low on disk space.
    Delete unnecessary files to free up space.
  </AlertDialog>
</DialogTrigger>
```

## Content

Unlike [Dialog](Dialog.html), the layout in AlertDialog is very deliberate. The body of an AlertDialog can be provided by passing
children to the component. The AlertDialog also supports having up to three buttons in its footer: a primary button,
a secondary button, and a cancel button. Each button can be rendered by providing a string to the `primaryActionLabel`, `secondaryActionLabel`,
and `cancelLabel` respectively. Be sure to localize any strings provided to the AlertDialog and to the button labels as well.
AlertDialogs do not support a Fullscreen mode.

AlertDialogs should always have a visible title, specified by passing a string as the `title` prop. This string should be localized
so that it is properly internationalized.

```tsx example
<DialogTrigger>
  <ActionButton>Exit</ActionButton>
  <AlertDialog
    variant="information"
    title="Register profile"
    primaryActionLabel="Register"
    secondaryActionLabel="Remind me later"
    cancelLabel="Cancel">
    You have not saved your profile information
    for this account. Would you like to register now?
  </AlertDialog>
</DialogTrigger>
```

### Accessibility

If any of the buttons in the AlertDialog's footer should be focused when it opens, specify which one via the `autoFocusButton` prop.

```tsx example
<DialogTrigger>
  <ActionButton>Save</ActionButton>
  <AlertDialog
    variant="confirmation"
    title="Save file"
    primaryActionLabel="Save"
    cancelLabel="Cancel"
    autoFocusButton="primary">
    A file with the same name already exists. Overwrite?
  </AlertDialog>
</DialogTrigger>
```

## Events

AlertDialog accepts an `onPrimaryAction`, `onSecondaryAction` and `onCancel` prop, triggered when the AlertDialog's confirm or cancel buttons are pressed respectively.

The example below uses `onPrimaryAction`, `onSecondaryAction` and `onCancel` to tell the user which button was pressed to close the AlertDialog.

```tsx example
function Example() {
  let onPrimaryAction = () => alert('Primary button pressed.');
  let onSecondaryAction = () => alert('Secondary button pressed.');
  let alertCancel = () => alert('Cancel button pressed.');

  return (
    <DialogTrigger>
      <ActionButton>
        Publish
      </ActionButton>
      <AlertDialog
        variant="confirmation"
        title="Confirm Publish"
        primaryActionLabel="Publish"
        secondaryActionLabel="Save as draft"
        cancelLabel="Cancel"
        onCancel={alertCancel}
        onPrimaryAction={onPrimaryAction}
        onSecondaryAction={onSecondaryAction}>
        Are you sure you want to publish this document?
      </AlertDialog>
    </DialogTrigger>
  );
}
```

## Props

<PropTable component={docs.exports.AlertDialog} links={docs.links} />

## Visual options

### Variant
[View guidelines](https://spectrum.adobe.com/page/alert-dialog/#Options)

**Confirmation**
```tsx example
<DialogTrigger>
  <ActionButton>Exit</ActionButton>
  <AlertDialog
    variant="confirmation"
    title="Exit instance?"
    primaryActionLabel="Confirm"
    cancelLabel="Cancel">
    Exit dungeon instance and return to main hub?
  </AlertDialog>
</DialogTrigger>
```
**Information**
```tsx example
<DialogTrigger>
  <ActionButton>New file</ActionButton>
  <AlertDialog
    variant="information"
    title="Connect your account"
    primaryActionLabel="Continue"
    cancelLabel="Cancel">
    Please connect an existing account to sync any new files.
  </AlertDialog>
</DialogTrigger>
```
**Destructive**
```tsx example
<DialogTrigger>
  <ActionButton>Delete</ActionButton>
  <AlertDialog
    variant="destructive"
    title="Delete file"
    primaryActionLabel="Delete"
    cancelLabel="Cancel">
    This will permanently delete the selected file. Continue?
  </AlertDialog>
</DialogTrigger>
```
**Error**
```tsx example
<DialogTrigger>
  <ActionButton>Login</ActionButton>
  <AlertDialog
    variant="error"
    title="Unable to connect"
    primaryActionLabel="Retry"
    cancelLabel="Cancel">
    Something went wrong while connecting to the server.
    Please try again in a couple minutes.
  </AlertDialog>
</DialogTrigger>
```
**Warning**
```tsx example
<DialogTrigger>
  <ActionButton>Enter</ActionButton>
  <AlertDialog
    variant="warning"
    title="Raid instance"
    primaryActionLabel="Confirm"
    cancelLabel="Cancel">
    The following encounter meant for parties of 4 or more. Enter anyways?
  </AlertDialog>
</DialogTrigger>
```

### Primary action disabled

Disables the primary button.

```tsx example
<DialogTrigger>
  <ActionButton>Upgrade</ActionButton>
  <AlertDialog
    isPrimaryActionDisabled
    variant="confirmation"
    title="Upgrade subscription"
    primaryActionLabel="Upgrade"
    cancelLabel="Cancel">
    Upgrade subscription for an additional $14.99 a month?
  </AlertDialog>
</DialogTrigger>
```

### Secondary action disabled

Disables the secondary button.

```tsx example
<DialogTrigger>
  <ActionButton>Upgrade</ActionButton>
  <AlertDialog
    isSecondaryActionDisabled
    variant="confirmation"
    title="Upgrade subscription"
    primaryActionLabel="Upgrade"
    secondaryActionLabel="Apply Coupon"
    cancelLabel="Cancel">
    Upgrade subscription for an additional $14.99 a month?
  </AlertDialog>
</DialogTrigger>
```

## Testing

The AlertDialog features an overlay that transitions in and out of the page as it is opened and closed.
Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/contextualhelp/test/ContextualHelp.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

To identify a particular instance of the cancel, secondary, or confirm button, you can use the following data-testid's respectively:
- `"rsp-AlertDialog-cancelButton"`
- `"rsp-AlertDialog-secondaryButton"`
- `"rsp-AlertDialog-confirmButton"`

---

### Packages @Adobe React Spectrum Docs Dialog Dialog (`packages/@adobe/react-spectrum/docs/dialog/Dialog.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import DialogAnatomy from './images/DialogAnatomy.svg';
import docs from 'docs:@react-spectrum/dialog';
import {Image, HeaderInfo, PropTable, PageDescription, VersionBadge, ClassAPI} from '@react-spectrum/docs';
import packageData from '@react-spectrum/dialog/package.json';
import styles from '@react-spectrum/docs/src/docs.css';

```jsx import
import Book from '@spectrum-icons/workflow/Book';
import {Footer} from '@react-spectrum/view';
import {Checkbox} from '@react-spectrum/checkbox';
import {Flex} from '@react-spectrum/layout';
import {Form} from '@react-spectrum/form';
import {Link} from '@react-spectrum/link';
import {Image} from '@react-spectrum/image';
import {TextField} from '@react-spectrum/textfield';
```

---
category: Overlays
keywords: [modal, tray, popover]
---

# Dialog

<PageDescription>{docs.exports.Dialog.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Dialog', 'DialogTrigger']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/alert-dialog/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
import {ActionButton, Button} from '@react-spectrum/button';
import {ButtonGroup} from '@react-spectrum/buttongroup';
import {Content, Header} from '@react-spectrum/view';
import {Dialog, DialogTrigger} from '@react-spectrum/dialog';
import {Divider} from '@react-spectrum/divider';
import {Heading, Text} from '@react-spectrum/text';

<DialogTrigger>
  <ActionButton>Check connectivity</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Internet Speed Test</Heading>
      <Header>Connection status: Connected</Header>
      <Divider />
      <Content>
        <Text>
          Start speed test?
        </Text>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close}>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

## Content

A standard Dialog has the following anatomy:

<div className={styles.exampleImage}>
  <DialogAnatomy />
</div>

These sections can be populated by providing the following components to your Dialog as children:
[Header](Header.html), [Heading](Heading.html) (title), [Divider](Divider.html), [Content](Content.html) (body),
[ButtonGroup](ButtonGroup.html), and [Footer](Footer.html). Each of these components are
required in a Spectrum compliant Dialog except for `Header`, `Footer`, and `Divider` so be sure to design your Dialog accordingly.

### Examples
A typical Dialog with a title, contents, and action buttons can be created like so:

```tsx example
<DialogTrigger>
  <ActionButton>Publish</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Publish 3 pages</Heading>
      <Divider />
      <Content>Confirm publish?</Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

A dismissable Dialog forgoes its ButtonGroup in favor of rendering a close button at the top right of the Dialog.

```tsx example
<DialogTrigger isDismissable>
  <ActionButton>Status</ActionButton>
  <Dialog>
    <Heading>Status</Heading>
    <Divider />
    <Content>Printer Status: Connected</Content>
  </Dialog>
</DialogTrigger>
```

It is important to note that the `Heading`, `Header`, `Content`, and `Footer` content elements accept any renderable
node, not just strings. This allows you to create Dialogs for more complex workflows, such as including a form
for the user to fill out or adding confirmation checkboxes.

```tsx example
<DialogTrigger>
  <ActionButton>Register</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>
        <Flex alignItems="center" gap="size-100">
          <Book size="S" />
          <Text>
            Register for newsletter
          </Text>
        </Flex>
      </Heading>
      <Header>
        <Link>
          <a href="//example.com" target="_blank">What is this?</a>
        </Link>
      </Header>
      <Divider />
      <Content>
        <Form>
          <TextField label="First Name" autoFocus />
          <TextField label="Last Name" />
          <TextField label="Street Address" />
          <TextField label="City" />
        </Form>
      </Content>
      <Footer>
        <Checkbox>
          I want to receive updates for exclusive offers in my area.
        </Checkbox>
      </Footer>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close}>Register</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

The example below illustrates how a Dialog with a hero image could be rendered via the `hero` slot:

```tsx example
<DialogTrigger>
  <ActionButton>Upload</ActionButton>
  {(close) => (
    <Dialog>
      <Image slot="hero" alt="" src="https://i.imgur.com/Z7AzH2c.png" objectFit="cover" />
      <Heading>Upload file</Heading>
      <Divider />
      <Content>Are you sure you want to upload this file?</Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

### Accessibility

Keep in mind when creating your Dialog that the tab order within the Dialog follows the order of the children provided.
You are also responsible for determining what component, if any, should be automatically focused when the Dialog opens.

## Labeling

### Accessibility

The title of a Dialog is typically provided via its heading. By default, the Dialog sets its
`aria-labelledby` to match the heading `id`, but this can be overridden by providing an `aria-labelledby` prop
to the Dialog directly. If a visible label isn't specified, an `aria-label` must be provided instead.

## Events

For Dialogs, user defined callbacks should be chained with the DialogTrigger's `close` function in the `onPress` handler
of the Dialog's action buttons. The following example alerts if the Dialog's save or cancel button is clicked.

```tsx example
function Example() {
  let alertSave = (close) => {
    close();
    alert('Profile saved!');
  }

  let alertCancel = (close) => {
    close();
    alert('Profile not saved!');
  }

  return (
    <DialogTrigger>
      <ActionButton>Set Profile</ActionButton>
      {(close) => (
        <Dialog>
          <Heading>Profile</Heading>
          <Divider />
          <ButtonGroup>
            <Button variant="secondary" onPress={() => alertCancel(close)}>Cancel</Button>
            <Button autoFocus variant="accent" onPress={() => alertSave(close)}>Save</Button>
          </ButtonGroup>
          <Content>
            <Form>
              <TextField label="Name" />
              <Checkbox>Make private</Checkbox>
            </Form>
          </Content>
        </Dialog>
      )}
    </DialogTrigger>
  );
}
```

Additionally, DialogTrigger accepts an `onOpenChange` prop which is triggered whenever the Dialog is opened or closed.
For more information, see the [DialogTrigger docs](./DialogTrigger.html#events).

### Dismissable dialogs

Dismissable Dialogs support an optional `onDismiss` prop which is triggered whenever the Dialog's close button is clicked.
Similar to non-dismissable dialogs, you must chain the DialogTrigger's `close` function with whatever callback you provide as
`onDismiss`. If this event callback is not needed, the dismissiable dialog will behave as normal without passing this callback through.

```tsx example
function Example() {
  let alertDismiss = (close) => {
    close();
    alert('Dialog dismissed.');
  }
  return (
    <DialogTrigger isDismissable>
      <ActionButton>Info</ActionButton>
      {(close) => (
        <Dialog onDismiss={() => alertDismiss(close)}>
          <Heading>Version Info</Heading>
          <Divider />
          <Content>
            <Text>
              Version 1.0.0, Copyright 2020
            </Text>
          </Content>
        </Dialog>
        )}
    </DialogTrigger>
  );
}
```

**Note:** The `onDismiss` callback is optional. If you don't need to add a `onDismiss` handler to your dismissable Dialog, you may omit
the wrapping `close` function surrounding the Dialog. An example of this can be found in the Examples section [above](#examples).

## Props

<PropTable component={docs.exports.Dialog} links={docs.links} />

## Visual options

### Dialog types
Dialogs can be rendered as modals, popovers, or trays. Note that popovers are displayed as modals by default on mobile.
See the [DialogTrigger docs](./DialogTrigger.html#dialog-types) for more information.

```tsx example
<DialogTrigger isDismissable type="modal">
  <ActionButton>Trigger Modal</ActionButton>
  <Dialog>
    <Heading>Modal</Heading>
    <Divider />
    <Content>
      <Text>
        This is a modal.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```
```tsx example
<DialogTrigger type="popover">
  <ActionButton>Trigger Popover</ActionButton>
  <Dialog>
    <Heading>Popover</Heading>
    <Divider />
    <Content>
      <Text>
        This is a popover.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```
```tsx example
<DialogTrigger type="tray">
  <ActionButton>Trigger Tray</ActionButton>
  <Dialog>
    <Heading>Tray</Heading>
    <Divider />
    <Content>
      <Text>
        This is a tray.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Size
Only `modal` type Dialogs support a user defined size prop. Note that the `fullscreen` and `fullscreenTakeover` sizes
require the [DialogTrigger `type`](./DialogTrigger.html#dialog-types) prop to be set to `fullscreen` or `fullscreenTakeover`
respectively for container sizing considerations. Modal sizes on mobile devices are also unaffected by this prop due to screen constraints.

```tsx example
<DialogTrigger>
  <ActionButton>Small</ActionButton>
  {(close) => (
    <Dialog size="S">
      <Heading>Profile</Heading>
      <Divider />
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button autoFocus variant="accent" onPress={close}>Save</Button>
      </ButtonGroup>
      <Content>
        <Form>
          <TextField label="Name" />
          <Checkbox>Make private</Checkbox>
        </Form>
      </Content>
    </Dialog>
  )}
</DialogTrigger>
```
```tsx example
<DialogTrigger>
  <ActionButton>Medium</ActionButton>
  {(close) => (
    <Dialog size="M">
      <Heading>Profile</Heading>
      <Divider />
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button autoFocus variant="accent" onPress={close}>Save</Button>
      </ButtonGroup>
      <Content>
        <Form>
          <TextField label="Name" />
          <Checkbox>Make private</Checkbox>
        </Form>
      </Content>
    </Dialog>
  )}
</DialogTrigger>
```
```tsx example
<DialogTrigger>
  <ActionButton>Large</ActionButton>
  {(close) => (
    <Dialog size="L">
      <Heading>Profile</Heading>
      <Divider />
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button autoFocus variant="accent" onPress={close}>Save</Button>
      </ButtonGroup>
      <Content>
        <Form>
          <TextField label="Name" />
          <Checkbox>Make private</Checkbox>
        </Form>
      </Content>
    </Dialog>
  )}
</DialogTrigger>
```

---

### Packages @Adobe React Spectrum Docs Dialog DialogContainer (`packages/@adobe/react-spectrum/docs/dialog/DialogContainer.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/dialog';
import {HeaderInfo, PropTable, FunctionAPI, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-spectrum/dialog/package.json';

```jsx import
import {Content} from '@react-spectrum/view';
import {Form} from '@react-spectrum/form';
import {Heading, Text} from '@react-spectrum/text';
import {TextField} from '@react-spectrum/textfield';
import {Divider} from '@react-spectrum/divider';
import {DialogContainer, Dialog, AlertDialog} from '@react-spectrum/dialog';
import {ActionButton, Button} from '@react-spectrum/button';
import {ButtonGroup} from '@react-spectrum/buttongroup';
import {MenuTrigger, Menu, Item} from '@react-spectrum/menu';
import More from '@spectrum-icons/workflow/More';
import Delete from '@spectrum-icons/workflow/Delete';
import Edit from '@spectrum-icons/workflow/Edit';
```

---
category: Overlays
keywords: [dialog container, dialog, modal]
---

# DialogContainer

<PageDescription>{docs.exports.DialogContainer.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DialogContainer', 'Dialog']}
  since="3.4.0" />

## Example

```tsx example
function Example(props) {
  let [isOpen, setOpen] = React.useState(false);

  return (
    <>
      <ActionButton onPress={() => setOpen(true)}>
        <Delete />
        <Text>Delete</Text>
      </ActionButton>
      <DialogContainer onDismiss={() => setOpen(false)} {...props}>
        {isOpen &&
          <AlertDialog
            title="Delete"
            variant="destructive"
            primaryActionLabel="Delete">
            Are you sure you want to delete this item?
          </AlertDialog>
        }
      </DialogContainer>
    </>
  );
}
```

## Dialog triggered by a menu item

DialogContainer is useful over a [DialogTrigger](DialogTrigger.html) when your have a trigger that can unmount while the dialog is
open. For example, placing a DialogTrigger around a menu item would not work because the menu closes when pressing an item, thereby
unmounting the DialogTrigger. When the trigger unmounts, so does the Dialog. In these cases, it is useful to place the dialog *outside*
the tree that unmounts, so that the dialog is not also removed.

The following example shows a [MenuTrigger](MenuTrigger.html) containing a [Menu](Menu.html) with two actions: "edit" and "delete".
Each menu item opens a different dialog. This is implemented by using a DialogContainer that displays the edit dialog,
delete dialog, or no dialog depending on the current value stored in local state. Pressing a menu item triggers the menu's
`onAction` prop, which sets the state to the type of dialog to display, based on the menu item's `key`. This causes the associated
dialog to be rendered within the DialogContainer.

This example also demonstrates the use of the `useDialogContainer` hook, which allows the dialog to dismiss itself when a user
presses one of the buttons inside it. This triggers the DialogContainer's `onDismiss` event, which resets the state storing the
open dialog back to `null`. In addition, the user can close the dialog using the <Keyboard>Escape</Keyboard> key (unless the
`isKeyboardDismissDisabled` prop is set), or by clicking outside (if the `isDismissable` prop is set).

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Props

<PropTable component={docs.exports.DialogContainer} links={docs.links} />

## useDialogContainer

The `useDialogContainer` hook can be used to allow a custom dialog component to access the `type` of container
the dialog is rendered in (e.g. `modal`, `popover`, `fullscreen`, etc.), and also to dismiss the dialog
programmatically. It works with both `DialogContainer` and [DialogTrigger](DialogTrigger.html).

<FunctionAPI function={docs.exports.useDialogContainer} links={docs.links} />

## Visual options

### Full screen

The `type` prop allows setting the type of modal to display. Set it to `"fullscreen"` to display a full screen dialog, which
only reveals a small portion of the page behind the underlay. Use this variant for more complex workflows that do not fit in
the available modal dialog [sizes](Dialog.html#size).

```tsx example
function Example(props) {
  let [isOpen, setOpen] = React.useState(false);

  return (
    <>
      <ActionButton onPress={() => setOpen(true)}>
        <Edit />
        <Text>Edit</Text>
      </ActionButton>
      <DialogContainer type="fullscreen" onDismiss={() => setOpen(false)} {...props}>
        {isOpen &&
          <EditDialog />
        }
      </DialogContainer>
    </>
  );
}
```

### Full screen takeover

Fullscreen takeover dialogs are similar to the fullscreen variant except that the dialog covers the entire screen.

```tsx example
function Example(props) {
  let [isOpen, setOpen] = React.useState(false);

  return (
    <>
      <ActionButton onPress={() => setOpen(true)}>
        <Edit />
        <Text>Edit</Text>
      </ActionButton>
      <DialogContainer type="fullscreenTakeover" onDismiss={() => setOpen(false)} {...props}>
        {isOpen &&
          <EditDialog />
        }
      </DialogContainer>
    </>
  );
}
```

```tsx import
// Duplicated from above so we can access in other examples...
function EditDialog() {
  let dialog = useDialogContainer();

  return (
    <Dialog>
      <Heading>Edit</Heading>
      <Divider />
      <Content>
        <Form width="100%">
          <TextField autoFocus label="First Name" defaultValue="John" />
          <TextField label="Last Name" defaultValue="Smith" />
        </Form>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={dialog.dismiss}>Cancel</Button>
        <Button variant="accent" onPress={dialog.dismiss}>Save</Button>
      </ButtonGroup>
    </Dialog>
  );
}
```

## Testing

The DialogContainer features an overlay that transitions in and out of the page as it is opened and closed.
Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/dialog/test/DialogContainer.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Dialog DialogTrigger (`packages/@adobe/react-spectrum/docs/dialog/DialogTrigger.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/dialog';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-spectrum/dialog/package.json';

```jsx import
import {ActionButton, Button} from '@react-spectrum/button';
import {ButtonGroup} from '@react-spectrum/buttongroup';
import {Checkbox} from '@react-spectrum/checkbox';
import {Content} from '@react-spectrum/view';
import {Dialog, DialogTrigger} from '@react-spectrum/dialog';
import {Divider} from '@react-spectrum/divider';
import {Form} from '@react-spectrum/form';
import {Heading, Text} from '@react-spectrum/text';
import {TextField} from '@react-spectrum/textfield';
import {Flex} from '@react-spectrum/layout';
```

---
category: Overlays
keywords: [dialog trigger, dialog, modal, tray, popover]
---

# DialogTrigger

<PageDescription>{docs.exports.DialogTrigger.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DialogTrigger', 'Dialog']}
  since="3.0.0" />

## Example

```tsx example
<DialogTrigger type="popover">
  <ActionButton>Disk Status</ActionButton>
  <Dialog>
    <Heading>C://</Heading>
    <Divider />
    <Content>
      <Text>
        50% disk space remaining.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

## Content

The DialogTrigger accepts exactly two children: the element which triggers opening
of the Dialog and the Dialog itself. The trigger must be the first child
passed into the DialogTrigger and should be an element that supports press events.

If your Dialog has buttons within it that should close the Dialog when pressed,
you must wrap the Dialog in a function in order to propagate the DialogTrigger's
`close` function to the Dialog's children. Dialogs that do not contain such interactive
elements can simply provide the Dialog component as is to the DialogTrigger as its second child.

The example below demonstrates how to pass the DialogTrigger's `close` function to the Dialog's buttons.

```tsx example
<DialogTrigger>
  <ActionButton>Checkout</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Confirm checkout?</Heading>
      <Divider />
      <Content>
        <Text>
          You have 5 items in your cart. Proceed to checkout?
        </Text>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

## Dialog types

By providing a `type` prop, you can specify the type of Dialog that is rendered
by your DialogTrigger. Note that pressing the <Keyboard>Esc</Keyboard> key will close the Dialog regardless
of its `type`.

### Modal

Modal Dialogs create an underlay that blocks access to the underlying user interface
until the Dialog is closed. Sizing options can be found on the [Dialog page](./Dialog.html#size).
Focus is trapped inside the Modal as per the [accessibility guidelines](https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/)
laid out by W3C.

```tsx example
<DialogTrigger type="modal">
  <ActionButton>Unlink</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Unlinking email</Heading>
      <Divider />
      <Content>
        <Text>
          This will unlink your email from your profile "TestUser". Are you sure?
        </Text>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

### Popover

If a Dialog without an underlay is needed, consider
using a Popover Dialog. See [Dialog placement](#dialog-placement) for how you can
customize the positioning. Note that popovers are automatically rendered as modals on
mobile by default. See the [mobile type](#mobile-type) option for more information.

```tsx example
<DialogTrigger type="popover">
  <ActionButton>Info</ActionButton>
  <Dialog>
    <Heading>Version Info</Heading>
    <Divider />
    <Content>
      <Text>
        Version 1.0.0, Copyright 2020
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Tray

Tray Dialogs are typically used to portray information on mobile devices or smaller screens.

```tsx example
<DialogTrigger type="tray">
  <ActionButton>Check Messages</ActionButton>
  <Dialog>
    <Heading>New Messages</Heading>
    <Divider />
    <Content>
      <Text>
        You have 5 new messages.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Fullscreen

Fullscreen Dialogs are a fullscreen variant of the Modal Dialog, only revealing a small
portion of the page behind the underlay. Use this variant for more complex workflows that
do not fit in the available Modal Dialog sizes. This variant does not support
`isDismissible`.

```tsx example
<DialogTrigger type="fullscreen">
  <ActionButton>See Details</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Package details</Heading>
      <Divider />
      <Content>
        <Text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin sit amet tristique risus. In sit amet suscipit lorem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In condimentum imperdiet metus non condimentum. Duis eu velit et quam accumsan tempus at id velit. Duis elementum elementum purus, id tempus mauris posuere a. Nunc vestibulum sapien pellentesque lectus commodo ornare.
        </Text>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Buy</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

### Fullscreen takeover

Fullscreen takeover Dialogs are similar to the fullscreen variant except that the
Dialog covers the entire screen.

```tsx example
<DialogTrigger type="fullscreenTakeover">
  <ActionButton>Register</ActionButton>
  {(close) => (
    <Dialog>
      <Heading>Register a new account</Heading>
      <Divider />
      <Content>
        <Form>
          <TextField label="Name" />
          <TextField label="Email address" />
          <Checkbox>Make profile private</Checkbox>
        </Form>
      </Content>
      <ButtonGroup>
        <Button variant="secondary" onPress={close}>Cancel</Button>
        <Button variant="accent" onPress={close} autoFocus>Confirm</Button>
      </ButtonGroup>
    </Dialog>
  )}
</DialogTrigger>
```

### Dismissable

If your Modal Dialog doesn't require the user to make a confirmation, you can set `isDismissable`
on the DialogTrigger. This adds a close button that the user can press to dismiss the Dialog.

```tsx example
<DialogTrigger isDismissable type="modal">
  <ActionButton>User Status</ActionButton>
  <Dialog>
    <Heading>Status: Bob</Heading>
    <Divider />
    <Content>
      <Text>
        Last Login: December 12, 1989
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Mobile type

The `mobileType` prop allows you to specify what kind of Dialog should be displayed when viewed on
mobile devices or smaller viewports. Note that on mobile, Popovers are not supported and will
display as modals by default.

The example below renders as a Popover on desktop but switches to a Tray on mobile.

```tsx example
<DialogTrigger type="popover" mobileType="tray">
  <ActionButton>Info</ActionButton>
  <Dialog>
    <Heading>Version Info</Heading>
    <Divider />
    <Content>
      <Text>
        Version 1.0.0, Copyright 2020
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

## Dialog placement

Popover Dialogs support a variety of placement options since they do not take over the user interface
like Modal or Tray Dialogs.

### Dialog anchor

By default, popovers anchor themselves to their associated trigger. This can be overridden by providing
a separate ref to the `targetRef` prop.

```tsx example
function Example() {
  let ref = React.useRef(null)

  return (
    <Flex gap="size-1000">
      <DialogTrigger type="popover" targetRef={ref}>
        <ActionButton>Trigger</ActionButton>
        <Dialog>
          <Heading>The Heading</Heading>
          <Divider />
          <Content>
            <Text>
              This is a popover anchored to the span.
            </Text>
          </Content>
        </Dialog>
      </DialogTrigger>
      <span
        ref={ref}
        style={{width: '100px'}}>
        Popover appears over here
      </span>
    </Flex>
  );
}
```

### Placement

The popover's placement with respect to its anchor element can be adjusted using the `placement`
prop. See the props table [below](#props) for a full list of available placement combinations.

```tsx example
<DialogTrigger type="popover" placement="right top">
  <ActionButton>Trigger</ActionButton>
  <Dialog>
    <Heading>The Heading</Heading>
    <Divider />
    <Content>
      <Text>
        This is a popover placed to the right of its
        trigger and offset so the arrow is at the top of the dialog.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Offset and cross offset

The Popover Dialog's offset with respect to its anchor element can be adjusted using the `offset` and
`crossOffset` props. The `offset` prop controls the spacing applied along the main axis between the element and its
anchor element whereas the `crossOffset` prop handles the spacing applied along the cross axis.

Below is a popover offset by an additional 50px above the trigger.
```tsx example
<DialogTrigger type="popover" placement="top" offset={50}>
  <ActionButton>Trigger</ActionButton>
  <Dialog>
    <Heading>Offset</Heading>
    <Divider />
    <Content>
      <Text>
        Offset by an additional 50px.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```
Below is a popover cross offset by an additional 100px to the right of the trigger.
```tsx example
<DialogTrigger type="popover" placement="top" crossOffset={100}>
  <ActionButton>Trigger</ActionButton>
  <Dialog>
    <Heading>Cross offset</Heading>
    <Divider />
    <Content>
      <Text>
        Offset by an additional 100px.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

### Flipping

By default, DialogTrigger attempts to flip popovers on the main axis in situations where the original placement
would cause it to render out of view. This can be overridden by setting `shouldFlip={false}`.
To see the difference between the two options, scroll this page so that the example below is near the bottom of the window.

```tsx example
<Flex gap="size-100" wrap>
  <DialogTrigger type="popover" placement="bottom">
    <ActionButton>Default DialogTrigger</ActionButton>
    <Dialog>
      <Heading>The Heading</Heading>
      <Divider />
      <Content>
        <Text>
          This is a popover that will flip if it can't fully render below the button.
        </Text>
      </Content>
    </Dialog>
  </DialogTrigger>

  <DialogTrigger type="popover" placement="bottom" shouldFlip={false}>
    <ActionButton>DialogTrigger with shouldFlip=false</ActionButton>
    <Dialog>
      <Heading>The Heading</Heading>
      <Divider />
      <Content>
        <Text>
          This is a popover that won't flip if it can't fully render below the button.
        </Text>
      </Content>
    </Dialog>
  </DialogTrigger>
</Flex>
```

### Container padding

You can control the minimum padding required between the Popover Dialog and the
surrounding container via the `containerPadding` prop. This affects the positioning
breakpoints that determine when the Dialog will attempt to flip.

The example below will flip the Dialog from above the trigger button to below the trigger
button if the Dialog cannot render fully while maintaining 50px of padding between itself and
the top of the browser.

```tsx example
<DialogTrigger type="popover" placement="top" containerPadding={50}>
  <ActionButton>Trigger</ActionButton>
  <Dialog>
    <Heading>The Heading</Heading>
    <Divider />
    <Content>
      <Text>
        This is a popover.
      </Text>
    </Content>
  </Dialog>
</DialogTrigger>
```

## Events

DialogTrigger accepts an `onOpenChange` handler which is triggered whenever the Dialog is opened or closed.

The example below uses `onOpenChange` to update a separate element with the current open state of the
Dialog.

```tsx example
function Example() {
  let [state, setState] = React.useState(false);

  return (
    <Flex alignItems="center" gap="size-100">
      <DialogTrigger type="popover" placement="top" onOpenChange={(isOpen) => setState(isOpen)}>
        <ActionButton>Whispers</ActionButton>
        <Dialog>
          <Heading>Whispers and DMs</Heading>
          <Divider />
          <Content>
            <Text>
              You have 0 new messages.
            </Text>
          </Content>
        </Dialog>
      </DialogTrigger>
      <Text>Current open state: {state.toString()}</Text>
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.DialogTrigger} links={docs.links} />

## Testing

The DialogTrigger features an overlay that transitions in and out of the page as it is opened and closed.
Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/dialog/test/DialogTrigger.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Divider Divider (`packages/@adobe/react-spectrum/docs/divider/Divider.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/divider';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/divider/package.json';

```jsx import
import {Divider} from '@react-spectrum/divider';
import {Flex} from '@react-spectrum/layout';
import {Text} from '@react-spectrum/text';
```

---
category: Content
---

# Divider

<PageDescription>{docs.exports.Divider.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Divider']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/divider/'}
  ]}
  since="3.0.0" />

## Example

### Horizontal
[View guidelines](https://spectrum.adobe.com/page/divider/#Orientation)

```tsx example
<Flex direction="column" gap="size-125">
  <Text>Content above</Text>
  <Divider />
  <Text>Content below</Text>
</Flex>
```

### Vertical

```tsx example
<Flex gap="size-125">
  <Text>Content left</Text>
  <Divider orientation="vertical" />
  <Text>Content right</Text>
</Flex>
```

### Size
[View guidelines](https://spectrum.adobe.com/page/divider/#Size)

```tsx example
<Flex direction="column" gap="size-125">
  <Text>Content above large Divider</Text>
  <Divider size="L" />
  <Text>Content above medium Divider</Text>
  <Divider size="M" />
  <Text>Content above small Divider</Text>
  <Divider size="S" />
</Flex>
```
## Props

<PropTable component={docs.exports.Divider} links={docs.links} />

---

### Packages @Adobe React Spectrum Docs Dnd Dnd (`packages/@adobe/react-spectrum/docs/dnd/dnd.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import docs from 'docs:@react-spectrum/dnd';
import dndDocs from 'docs:@react-types/shared/src/dnd.d.ts';
import {FunctionAPI, PageDescription, TypeContext, InterfaceType} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import DragPreview from '/packages/dev/s2-docs/pages/react-aria/DndDragPreview.svg';
import BetweenDropPosition from '/packages/dev/s2-docs/pages/react-aria/DndBetweenDropPosition.svg';
import OnDropPosition from '/packages/dev/s2-docs/pages/react-aria/DndOnDropPosition.svg';
import RootDropPosition from '/packages/dev/s2-docs/pages/react-aria/DndRootDropPosition.svg';
import DragAffordance from '/packages/dev/s2-docs/pages/react-aria/DndDragAffordance.svg';
import Anatomy from '/packages/dev/s2-docs/pages/react-aria/DndAnatomy.svg';

---
category: Concepts
keywords: [drag and drop, dnd]
order: 6
---

# Drag and Drop

This page describes how to enable drag and drop functionality for the various React Spectrum components that support it.

## Introduction

Drag and drop is a common UI interaction that allows users to transfer data between two locations by directly moving a visual representation on screen.
It is a flexible, efficient, and intuitive way for users to perform a variety of tasks, and is widely supported across both desktop and mobile operating systems.
In addition to the standard mouse and touch interactions, React Spectrum also implements keyboard and screen reader accessible alternatives for drag and drop to enable all users to perform these tasks.

## Drag and Drop Concepts

Before we dive into how to enable drag and drop in React Spectrum, let's touch briefly on the terminology and concepts of drag and drop. In a drag and drop operation, there is
a **drag source** and a **drop target**. The drag source is the starting location of your dragged data and the drop target is its intended destination. The dragged data
is made up of one or more **drag items**, each of which contains information specific to their original item within the drag source.

<Anatomy role="img" aria-label="Drag and drop anatomy diagram, showing drag source, drag preview, and drop target." />

A drag item contains several pieces of information: the **type** of the data, the item's **kind**, and the actual data itself. The type of a drag item can be one of the
[common mime types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) or a custom type specific to your application. Multiple types can be attached to a
single drag item so that the item's data can be provided in different formats for interoperability with various drop targets. For example, an image could be represented by an
`image/jpeg` type and thus be recognized as a JPEG by a file upload drop target but also have a `plain/text` type that allows the image's file name to be communicated to a
text input drop target. In addition, there are two kinds of items: string items include inline data in the form of a Unicode string, and file items include a reference to a file from
the user's computer.

There are several **drop operations** that can be performed in a drag and drop operation: `"move"`, `"copy"`, `"link"`, and `"cancel"`. A `"move"` operation indicates that the dragged data will be
moved from its source location to the target location. A `"copy"` operation indicates that the dragged data will be copied to the target destination. A `"link"` operation indicates that
there will be a relationship established between the source and target locations. Finally, a `"cancel"` operation indicates that the drag and drop operation will be canceled, resulting in
no changes made to the source or target. The drag source can specify what drop operations are allowed for its data, allowing the drop target to decide what operation to perform, using the restrictions
set by the drag source as a guideline.

<figure style={{display: 'flex', flexDirection: 'column', alignItems: 'center', margin: '20px 0'}}>
  <div style={{display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 50, marginBottom: 4, background: 'var(--anatomy-gray-100)', padding: 32, width: 'calc(100% - 64px)', borderRadius: 4}}>
    <RootDropPosition role="img" aria-label="Root drop position" />
    <OnDropPosition role="img" aria-label="On drop position" />
    <BetweenDropPosition role="img" aria-label="Between drop position" />
  </div>
  <figcaption style={{fontStyle: 'italic'}}>The "root", "on", and "between" drop positions.</figcaption>
</figure>

Collection components, such as ListView and TableView, support multiple **drop positions**. The component may support a `"root"` drop position, allowing items to be dropped on the collection as a whole.
It may also support `"on"` drop positions, such as when dropping into a folder in a list. If the collection allows reordering of its items, it could support `"between"` drop positions, allowing the
user to insert or move items between other items. Any number of these drop positions can be allowed at the same time and the component can use the types of the dragged items to selectively allow or disallow certain positions.

### Interaction modes

There are several interaction modes that need to be considered for drag and drop. When using a mouse, you can click an item and drag by holding the mouse button down and moving the pointer. A drop can
be performed by releasing the mouse button or canceled by the <Keyboard>Esc</Keyboard> key. A similar interaction can be performed via touch, with a drag initiated via a long press and a drop performed by
removing your finger from the screen. In both cases, selecting and dragging an item is often accompanied by a **drag preview**. The drag preview is a smaller version of the dragged item that follows the cursor
or touch point. When multiple items are dragged at once, the drag preview displays a stack of items instead, accompanied by a badge reflecting the total number of dragged items. Drop targets are visually highlighted
when dragged over, and the desired drop operation can be controlled via modifier key presses or drop activations via hovering over the drop target for a period of time.

<figure style={{display: 'flex', flexDirection: 'column', alignItems: 'center', margin: '20px 0'}}>
  <DragPreview role="img" aria-labelledby="drag-preview-caption" />
  <figcaption id="drag-preview-caption" style={{fontStyle: 'italic'}}>A custom drag preview representing multiple drag items.</figcaption>
</figure>

For keyboards, copy and paste shortcuts have traditionally been the alternative method to drag and drop. This comes with many limitations as it is often hard to know where pasting is allowed and difficult to control the
exact positioning of the pasted items. Touch screen readers are even more limited in their ability to perform these operations since they often lack access to a keyboard and thus cannot copy paste in the same manner.

React Spectrum attempts to resolve the above limitations by providing interactive drag affordances that bring a user into drag and drop mode when triggered via keyboard or screen reader virtual click. To perform a drag and drop operation via a keyboard,
first select the items to be dragged by focusing the row and pressing <Keyboard>Space</Keyboard>. You can then start the drag operation by moving focus to the drag handle on any of the selected rows via the arrow keys and hitting <Keyboard>Enter</Keyboard>
or <Keyboard>Space</Keyboard>. Once a drag operation is started, you will be automatically brought to the first valid drop target. <Keyboard>Tab</Keyboard> can then be used to cycle through other valid drop targets. For collection components like the ListView above,
<Keyboard>Tab</Keyboard> will move you on or off the overall component itself whereas <Keyboard>ArrowUp</Keyboard> and <Keyboard>ArrowDown</Keyboard> will cycle through the valid drop targets within the component itself. Hitting <Keyboard>Enter</Keyboard>
will then confirm the drop operation on the focused drop target. To cancel a drag operation, you can hit <Keyboard>Esc</Keyboard> at any time.

<figure style={{display: 'flex', flexDirection: 'column', alignItems: 'center', margin: '20px 0'}}>
  <DragAffordance role="img" aria-labelledby="drag-affordance-caption" />
  <figcaption id="drag-affordance-caption" style={{fontStyle: 'italic'}}>A focusable drag affordance to initiate keyboard and screen reader drag and drop.</figcaption>
</figure>

For screen readers, please follow the custom instructions announced when focusing the row's drag handle to begin a drag operation. For screen readers on mobile devices, swiping left and right will
move you between valid drop targets and double tapping will confirm a drop operation. Go ahead and try out drag and drop in the example below!

## Examples

```tsx snippet
import {Flex} from '@react-spectrum/layout';

<Flex gap="size-300">
  <DraggableList />
  <DroppableList />
</Flex>
```

### Creating the draggable list

For the first ListView in the example above, we want to make the rows draggable and have the dragged rows removed from the list upon a successful drop. To accomplish this,
we first want to set up the initial list of items for our draggable ListView via [useListData](react-aria:useListData.html) so that we have access to some helper methods
to modify the list of items on the fly. Note that this is completely optional and is not required to enable drag and drop in React Spectrum. You may substitute `useListData` with
[useAsyncList](react-aria:useAsyncList.html) or with any other state management solution.

```tsx
let list = useListData({
  initialItems: [
    {id: 'a', type: 'file', name: 'Adobe Photoshop'},
    {id: 'b', type: 'file', name: 'Adobe XD'},
    {id: 'c', type: 'file', name: 'Adobe Dreamweaver'},
    {id: 'd', type: 'file', name: 'Adobe InDesign'},
    {id: 'e', type: 'file', name: 'Adobe Connect'}
  ]
});
```

Next, we need to specify the data associated with each dragged item by returning an array from the `getItems` function. As described above in the [concepts section](#drag-and-drop-concepts), each item includes a mapping of drag types to serialized data.
In this case, we look up the information for each dragged item and serialize it, mapping it to a custom item type. This information will be processed and provided to the drop target's drop handlers on drop.

```tsx
let getItems = (keys) => [...keys].map(key => {
  let item = list.getItem(key);
  return {
    'adobe-app': JSON.stringify(item)
  };
})
```

We also create an `onDragEnd` event handler for `useDragAndDrop` that handles removing the dragged items from the draggable list upon a successful drop operation. Note how we use
the `.remove` method provided by `useListData` to remove the dropped items from our list.

```tsx
let onDragEnd = (e) => {
  if (e.dropOperation === 'move') {
    list.remove(...e.keys);
  }
}
```

Finally, we provide our `getItems` and `onDragEnd` functions as options to `useDragAndDrop`, providing us with a set of `dragAndDropHooks` that we can pass to our ListView directly.
Below is what our draggable ListView would look like after combining everything together. For more info on `getItems` and `onDragEnd`, see the [props section](#props) below and the
[React Aria docs](react-aria:useDraggableCollection.html#drag-data).

```tsx example export=true render=false
import {Item, ListView, useListData} from '@adobe/react-spectrum';
import {useDragAndDrop} from '@react-spectrum/dnd';

function DraggableList() {
  let list = useListData({
    initialItems: [
      {id: 'a', type: 'file', name: 'Adobe Photoshop'},
      {id: 'b', type: 'file', name: 'Adobe XD'},
      {id: 'c', type: 'file', name: 'Adobe Dreamweaver'},
      {id: 'd', type: 'file', name: 'Adobe InDesign'},
      {id: 'e', type: 'file', name: 'Adobe Connect'}
    ]
  });

  let {dragAndDropHooks} = useDragAndDrop({
    getItems: (keys) => [...keys].map(key => {
      let item = list.getItem(key);
      return {
        'adobe-app': JSON.stringify(item)
      };
    }),
    onDragEnd: (e) => {
      if (e.dropOperation === 'move') {
        list.remove(...e.keys);
      }
    }
  });

  return (
    <ListView
      aria-label="Draggable list view example"
      width="size-3600"
      height="size-3600"
      selectionMode="multiple"
      items={list.items}
      dragAndDropHooks={dragAndDropHooks}>
      {item => (
        <Item textValue={item.name}>
          {item.name}
        </Item>
      )}
    </ListView>
  );
}
```

### Creating the droppable list

We want to make the second ListView droppable, accepting drops between items and onto folders but not at the root of the list. Similar to the draggable ListView, we'll start by initializing the default item list
via [useListData](react-aria:useListData.html). As a reminder, `useListData` is completely optional here and can be replaced by [useAsyncList](react-aria:useAsyncList.html) or any other state management solution.

```tsx
let list = useListData({
  initialItems: [
    {id: 'f', type: 'file', name: 'Adobe AfterEffects'},
    {id: 'g', type: 'file', name: 'Adobe Illustrator'},
    {id: 'h', type: 'file', name: 'Adobe Lightroom'},
    {id: 'i', type: 'file', name: 'Adobe Premiere Pro'},
    {id: 'j', type: 'file', name: 'Adobe Fresco'},
    {id: 'k', type: 'folder', name: 'Apps', childNodes: []}
  ]
});
```

Since we only want to accept items from the first ListView, we set up an array containing our custom type that will be provided to `useDragAndDrop`'s `acceptedDragTypes` option.

```tsx
let acceptedDragTypes = ['adobe-app'];
```

Next, we add support for insertion drops by providing an `onInsert` handler. This handler uses the relative drop position to insert the dropped items before or after the target item.
Note how we can access each drop item's information by using the expected drag type and `getText`.

```tsx
let onInsert = async (e) => {
  let {
    items,
    target
  } = e;

  let processedItems = await Promise.all(
    items.map(async item => JSON.parse(await item.getText('adobe-app')))
  );

  if (target.dropPosition === 'before') {
    list.insertBefore(target.key, ...processedItems);
  } else if (target.dropPosition === 'after') {
    list.insertAfter(target.key, ...processedItems);
  }
}
```

Similarly, item drops are enabled by providing an `onItemDrop` handler. The folder's contents are updated by using `list.update` to add the dropped items to
the folder's `childNodes`. To ensure that we can only drop on the folder in the droppable list, we create a `shouldAcceptItemDrop` function that only returns `true`
if the drop target has `childNodes`.

```tsx
let onItemDrop = async (e) => {
  let {
    items,
    target
  } = e;
  let processedItems = await Promise.all(
    items.map(async item => JSON.parse(await item.getText('adobe-app')))
  );
  let targetItem = list.getItem(target.key);
  list.update(target.key, {...targetItem, childNodes: [...targetItem.childNodes, ...processedItems]});
}

let shouldAcceptItemDrop = (target) => !!list.getItem(target.key).childNodes;
```

Below is what our droppable ListView would look like after combining everything together. By not supplying an `onRootDrop` handler to `useDragAndDrop`, we automatically
exclude the root of the droppable list from the drop targets reachable via any of the drag and drop interaction modes. For more information on the options used above,
please see the [API section](#high-level-drop-handlers-and-options) below.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Low-level API

The above example makes use of several high-level events and options supported by `useDragAndDrop` to define the droppable ListView's behavior. However, you may have complex operations
that would be difficult or impossible to implement using the high-level options alone. For situations like this, you can use `getDropOperation` and `onDrop` instead, granting you
complete control over what drop operations should be returned and how any drop on your collection should be handled. For a more general explanation of these low-level options and how they work,
see the [API section](#low-level-drop-handlers-and-options) below and the `useDroppableCollection` [React Aria docs](react-aria:useDroppableCollection.html#low-level-api).

The ListView below allows external directories to be dropped at its root level or between existing items. Files of a specific type can be dropped on certain pre-existing directories only.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## API

As seen in the [examples](#examples) above, enabling drag and drop for a supported React Spectrum component differs slightly from the typical event handler prop pattern that you may be familiar with.
Instead of providing each event handler directly to the component, you must first import `useDragAndDrop` from the `@react-spectrum/dnd` package and provide this hook with your desired options.
`useDragAndDrop` then provides you with a set of hooks that you can pass to the component via its `dragAndDropHooks` prop, thus enabling drag and drop operations for the component. This approach allows the drag and drop
implementation to be included only when used, keeping bundle sizes small when unused by an application.

Whether the component supports drag operations, drop operations, or both all depends on the options you provide to the `useDragAndDrop`. If you omit the `getItems` option, the component will not be draggable. Alternatively, if
you don't provide an `onDrop` handler or any of the high-level drop handlers (`onInsert`/`onItemDrop`/`onReorder`/`onRootDrop`) to `useDragAndDrop` then the component will not be droppable.

### High-level drop handlers and options
<TypeContext.Provider value={dndDocs.links}>
  <InterfaceType properties={dndDocs.exports.DroppableCollectionUtilityOptions.properties} />
</TypeContext.Provider>

As demonstrated in this [example](#creating-the-droppable-list), `useDragAndDrop` accepts a set of high-level drop handlers and options. Providing any of these high-level drop handlers will enable the corresponding
drop behavior in your component (e.g. if you provide `onReorder`, internal insertion drop operations are enabled, provided the component is draggable as well). `acceptedDragTypes` allows
you to control what types of drag items your droppable component should accept and `shouldAcceptItemDrop` gives you a greater degree of control over whether an item in your component is a valid drop target. Providing
these two options will also automatically filter out any invalid drag items from the list of items provided to the drop handlers.

### Low-level drop handlers and options
<TypeContext.Provider value={dndDocs.links}>
  <InterfaceType properties={dndDocs.exports.DroppableCollectionBaseProps.properties} />
</TypeContext.Provider>

These lower level drop handlers and options can be used to supplement or replace the high-level options mentioned above. `getDropOperation` allows you to specify what drop operations is returned based on the
dragged items' drag types, the drop target information, and drop operations allowed by the drag source. It can be used in tandem with the higher level `acceptedDragTypes` and `shouldAcceptItemDrop` (when onItemDrop is provided) options. Those
two options serve as a pre-filter, preemptively canceling any attempted drop operation that doesn't pass their requirements.

`onDrop` can be used to handle all accepted drops, overriding any provided high-level drop handlers. On the other hand, `onDropEnter` and `onDropExit` can be freely used with any of the high-level drop handlers and options.

### Props

The full list of options for `useDragAndDrop` is available below.

<FunctionAPI function={docs.exports.useDragAndDrop} links={docs.links} />
<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.exports.DragAndDropOptions.properties} />
</TypeContext.Provider>

Of the various drag-specific options above, `getAllowedDropOperations` may be of particular interest. When the dragged items are dropped on a drop target created using the React Aria drag and drop hooks,
the allowed drop operations you return in `getAllowedDropOperations` are provided to the drop target's `getDropOperation`, giving the drop target extra information to use when deciding what drop operation to execute. This in turn provides
the `onDragEnd` and `onDrop` handlers with the executed drop operation, allowing you to decide what to do with the dragged items in your original component and in the dropped component.

For instance, you may have a draggable collection of items that allows `"move"` and `"copy"` operations but you need a way to know whether or not you should be removing the dragged items
from the list after a drop operation. A drop target that only allows `"copy"` operations, such as a file upload drop zone, would be able to return `"copy"` from its `getDropOperation` and communicate that
to your draggable collection's `onDragEnd` handler, letting the draggable collection know that it shouldn't remove the dragged items from its list. Alternatively, a drop target that allows `"move"` operations, like in the
[example](#examples) above, would return `move` from its `getDropOperation` and thus inform your draggable collection to remove the dragged items from its list.


## Supported components

The following list shows which components currently support drag and drop. Common drag and drop implementations are included in each component's documentation so definitely take a look!
-  [ListView](ListView.html#drag-and-drop)
-  [TableView](TableView.html#drag-and-drop)

---

### Packages @Adobe React Spectrum Docs Dropzone DropZone (`packages/@adobe/react-spectrum/docs/dropzone/DropZone.mdx`)

{/* Copyright 2023 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/dropzone';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/dropzone/package.json';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import styles from '@react-spectrum/docs/src/docs.css';

```jsx import
import {DropZone} from '@react-spectrum/dropzone';
import {Heading} from '@react-spectrum/text';
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import {Button} from '@react-spectrum/button';
```

---
category: Drag and drop
---

# DropZone

<PageDescription>{docs.exports.DropZone.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['DropZone']}
  since="3.35.0"
/>

## Example

```tsx example
import Upload from '@spectrum-icons/illustrations/Upload';

function Example() {
  let [isFilled, setIsFilled] = React.useState(false);

  return (
    <>
      <Draggable />
      <DropZone
        maxWidth="size-3000"
        isFilled={isFilled}
        onDrop={() => setIsFilled(true)}>
        <IllustratedMessage>
          <Upload />
          <Heading>
            {isFilled ? 'You dropped something!' : 'Drag and drop your file'}
          </Heading>
        </IllustratedMessage>
      </DropZone>
    </>
  )
}
```
The `Draggable` component used above is defined below. See [useDrag](react-aria:useDrag) for more details and documentation.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```tsx example render=false export=true
import {useDrag} from '@react-aria/dnd';

function Draggable() {
  let {dragProps, isDragging} = useDrag({
    getItems() {
      return [{
        'text/plain': 'hello world',
        'my-app-custom-type': JSON.stringify({message: 'hello world'})
      }];
    }
  });

  return (
    <div {...dragProps} role="button" tabIndex={0} className={`draggable ${isDragging ? 'dragging' : ''}`}>
      Drag me
    </div>
  );
}
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>

```css
.draggable {
  display: inline-block;
  vertical-align: top;
  border: 1px solid gray;
  padding: 10px;
  margin-right: 20px;
  margin-bottom: 20px;
  border-radius: 4px;
  height: fit-content;
}

.draggable.dragging {
  opacity: 0.5;
}
```
</details>
</details>


## Content

A DropZone accepts an [IllustratedMessage](IllustratedMessage.html) as a child which is comprised of three areas:  an illustration, a title, and a body. Each of these sections can be populated by providing the following components to the IllustratedMessage as children: a SVG, a [Heading](Heading.html) (title), and a [Content](Content.html) (body). A [FileTrigger](react-aria:FileTrigger) is commonly paired with a DropZone to allow a user to choose files from their device.

```tsx example
import {FileTrigger} from '@adobe/react-spectrum';

function Example() {
  let [isFilled, setIsFilled] = React.useState(false);

  return (
    <>
      <Draggable />
      <DropZone
        maxWidth="size-3000"
        isFilled={isFilled}
        onDrop={() => setIsFilled(true)}>
        <IllustratedMessage>
          <Upload />
          <Heading>
            {isFilled ? 'You dropped something!' : 'Drag and drop here'}
          </Heading>
          <Content>
            <FileTrigger
              onSelect={()=> setIsFilled(true)}>
              <Button variant="primary">Browse</Button>
            </FileTrigger>
          </Content>
        </IllustratedMessage>
      </DropZone>
    </>
  )
}
```

### Accessibility

A visual label should be provided to `DropZone` using a `Text` element with a `label` slot. If it is not provided, then an `aria-label` or `aria-labelledby` prop must be passed to identify the visually hidden button to assistive technology.

### Internationalization

In order to internationalize a DropZone, a localized string should be passed to the `Text` element with a `label` slot or to the `aria-label` prop, in addition to the `replaceMessage` prop.

## Events

`DropZone` supports drop operations via mouse, keyboard, and touch. You can handle all of these via the `onDrop` prop. In addition, the `onDropEnter`, `onDropMove`, and `onDropExit` events are fired as the user enter and exists the dropzone during a drag operation.

The following example uses an `onDrop` handler to update the filled status stored in React state.

```tsx example
import File from '@spectrum-icons/illustrations/File';
import {Flex} from '@react-spectrum/layout';

function Example() {
  let [filledSrc, setFilledSrc] = React.useState(null);

  return (
    <>
      <Draggable />
      <DropZone
        maxWidth="size-3000"
        isFilled={!!filledSrc}
        onDrop={async (e) => {
          e.items.find(async (item) => {
            if (item.kind === 'file') {
              setFilledSrc(item.name);

            } else if (item.kind === 'text' && item.types.has('text/plain')) {
              setFilledSrc(await item.getText('text/plain'));
            }
          });
        }}>
        {filledSrc
          ? (
            <Flex direction="column" alignItems="center" justifyContent="center" gap="size-100">
              <File />
              {filledSrc}
            </Flex>
          )
          : (
            <IllustratedMessage>
              <Upload />
              <Heading>
                Drag and drop here
              </Heading>
            </IllustratedMessage>
          )}
      </DropZone>
    </>
  );
}
```


## Props

<PropTable component={docs.exports.DropZone} links={docs.links} />

## Visual options

### Filled state

The user is responsible for both managing the filled state of a DropZone and handling the associated styling. To set the DropZone to a filled state, the user must pass the `isFilled` prop.

The example below demonstrates one way of styling the filled state.

```tsx example
function Example() {
  let [filledSrc, setFilledSrc] = React.useState(null);

  return (
    <>
      <DraggableImage />
      <DropZone
        isFilled={!!filledSrc}
        maxWidth="size-3000"
        height="size-2400"
        getDropOperation={(types) =>  (types.has('image/png') || types.has('image/jpeg')) ? 'copy' : 'cancel'}
        onDrop={async (e) => {
          e.items.find(async (item) => {
            if (item.kind === 'file') {
              if (item.type === 'image/jpeg' || item.type === 'image/png') {
                setFilledSrc(URL.createObjectURL(await item.getFile()));
              }
            } else if (item.kind === 'text') {
              setFilledSrc(await item.getText('image/jpeg'));
            }
          });
        }}>
        {filledSrc
          ? <img className="images" alt="" src={filledSrc} />
          : (
            <IllustratedMessage>
              <Upload />
              <Heading>
                Drag and drop photos
              </Heading>
            </IllustratedMessage>
          )}
      </DropZone>
    </>
  );
}
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>

```css
.images {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--spectrum-alias-border-radius-small);
}
```
</details>

The `DraggableImage` component used above is defined below. See [useDrag](react-aria:useDrag) for more details and documentation.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```tsx example render=false export=true
function DraggableImage() {
  let {dragProps, isDragging} = useDrag({
    getItems() {
      return [
        {
          'image/jpeg': 'https://i.imgur.com/Z7AzH2c.jpg'
        }
      ];
    }
  });

  return (
    <div
      {...dragProps}
      role="button"
      tabIndex={0}
      className={`draggable ${isDragging ? 'dragging' : ''}`} >
      <img
        width="150px"
        height="100px"
        alt="Traditional Roof"
        src="https://i.imgur.com/Z7AzH2c.jpg"/>
    </div>
  );
}
```
</details>

### Replace message

When a DropZone is in a filled state and has an object dragged over it, a message will appear in front of the DropZone. By default, this message will say "Drop file to replace". However, users can choose to customize this message through the `replaceMessage` prop. This message should describe the interaction that will occur when the object is dropped. It should also be internationalized if needed.


```tsx example
function Example() {
  let [isFilled, setIsFilled] = React.useState(false);

  return (
    <>
      <Draggable />
      <DropZone
        isFilled={isFilled}
        maxWidth="size-3000"
        replaceMessage="This is a custom message"
        onDrop={() => setIsFilled(true)}>
        <IllustratedMessage>
          <Upload />
          <Heading>
            {isFilled ? 'You dropped something!' : 'Drag and drop here'}
          </Heading>
        </IllustratedMessage>
      </DropZone>
    </>
  );
}
```

### Visual feedback

A DropZone displays visual feedback to the user when a drag hovers over the drop target by passing the `getDropOperation` function. If a drop target only supports data of specific types (e.g. images, videos, text, etc.), then it should implement the `getDropOperation` prop and return `'cancel'` for types that aren't supported. This will prevent visual feedback indicating that the drop target accepts the dragged data when this is not true. [Read more about getDropOperation.](react-aria:useDrop#getdropoperation)

In the below example, the drop zone only supports dropping JPEG images. If a JPEG is dragged over the drop zone, it will be highlighted and the operating system will display a copy cursor. If another type is dragged over the drop zone, then there is no visual feedback, indicating that a drop is not accepted.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Packages @Adobe React Spectrum Docs Filetrigger FileTrigger (`packages/@adobe/react-spectrum/docs/filetrigger/FileTrigger.mdx`)

{/* Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/filetrigger';
import typesDocs from 'docs:@react-types/shared/src/events.d.ts';
import {PropTable, HeaderInfo, TypeLink, PageDescription, StateTable} from '@react-spectrum/docs';
import styles from '@react-spectrum/docs/src/docs.css';
import packageData from '@react-spectrum/filetrigger/package.json';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import {Divider} from '@react-spectrum/divider';
import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import {Keyboard} from '@react-spectrum/text';
import Button from '@react-spectrum/docs/pages/assets/component-illustrations/ActionButton.svg';
import Link from '@react-spectrum/docs/pages/assets/component-illustrations/Link.svg';

---
category: Buttons
---

# FileTrigger

<PageDescription>{docs.exports.FileTrigger.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['FileTrigger']}
  since="3.35.0" />

## Example

```tsx example
import {FileTrigger, Button} from '@adobe/react-spectrum';

function Example(){
  let [file, setFile] = React.useState(null);

  return (
    <>
      <FileTrigger
        onSelect={(e) => {
          let files = Array.from(e);
          let filenames = files.map((file) => file.name);
          setFile(filenames);
        }}>
        <Button variant="accent">Select a file</Button>
      </FileTrigger>
      {file && file}
    </>
  )
}
```

## Content

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.

```tsx
import {FileTrigger, Button} from '@adobe/react-spectrum';

<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.

## 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) of files via the `acceptedFileTypes` prop.

```tsx example
<FileTrigger acceptedFileTypes={['image/png']}>
  <Button variant="primary">Select files</Button>
</FileTrigger>
```

## Multiple files

A file trigger can accept multiple files by passing the `allowsMultiple` property.

```tsx example
<FileTrigger allowsMultiple>
  <Button variant="primary">Upload your files</Button>
</FileTrigger>
```

## Directory selection

To enable selecting directories instead of files, use the `acceptDirectory` property.

This reflects the [webkitdirectory](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory) HTML attribute and allows users to select directories and their contents. Please note that support for this feature varies from browser to browser.


```tsx example
function Example () {
  let [files, setFiles] = React.useState([]);

  return (
    <>
      <FileTrigger
        acceptDirectory
        onSelect={(e) => {
          if (e) {
            let fileList = [...e].map(file => file.webkitRelativePath !== "" ? file.webkitRelativePath : file.name);
            setFiles(fileList);
          }
        }} >
        <Button variant="accent">Upload</Button>
      </FileTrigger>
      {files && <ul>
        {files.map((file, index) => (
          <li key={index}>{file}</li>
        ))}
      </ul>}
    </>
  );
}
```

## 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](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/capture).

```tsx example
<FileTrigger defaultCamera="environment">
  <Button variant="accent">Open Camera</Button>
</FileTrigger>
````

## Props

<PropTable component={docs.exports.FileTrigger} links={docs.links} />

---

### Packages @Adobe React Spectrum Docs Form Form (`packages/@adobe/react-spectrum/docs/form/Form.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/form';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/form/package.json';

```jsx import
 import {Checkbox} from '@react-spectrum/checkbox';
 import {Form} from '@react-spectrum/form';
 import {Radio, RadioGroup} from '@react-spectrum/radio';
 import {TextField} from '@react-spectrum/textfield';
 ```

---
category: Forms
---

# Form

<PageDescription>{docs.exports.Form.description}</PageDescription>

<HeaderInfo
 packageData={packageData}
 componentNames={['Form']}
 since="3.0.0" />

## Example

```tsx example
<Form maxWidth="size-3600">
  <TextField label="Email" />
  <TextField label="Password" />
  <Checkbox>Remember me</Checkbox>
</Form>
```

## Content

Form accepts one or more children to render as its form elements. Label alignment, positioning, and other [properties](#visual-options)
are set on the Form itself and propagated to its children to generate a cohesive design. To override these top level Form props on individual children,
set them directly on the child instead.

```tsx example
<Form maxWidth="size-3600" isRequired necessityIndicator="label">
  <TextField label="Name" />
  <TextField label="Email" />
  <TextField label="Address" isRequired={false} />
</Form>
```

## Labeling

### Accessibility

A label should be provided to the Form by adding either the `aria-label` or `aria-labelledby` prop, so that the element will be identified to assistive
technology as a form landmark region to which assistive technology can navigate.

```tsx example
<h3 id="label-3">Personal Information</h3>
<Form maxWidth="size-3600" aria-labelledby="label-3">
  <TextField label="First Name" />
  <TextField label="Last Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
    <Radio value="dragons">Dragons</Radio>
  </RadioGroup>
</Form>
```

## Validation

React Spectrum supports native HTML constraint validation with customizable UI, custom validation functions, realtime validation, and integration with server-side validation errors. The `Form` component facilitates server-side validation by providing error messages to the fields within it.

To provide validation errors, the `validationErrors` prop should be set to an object that maps each field's `name` prop to a string or array of strings representing one or more errors. These are displayed to the user as soon as the `validationErrors` prop is set, and cleared after the user modifies each field's value.

```tsx example
<Form validationErrors={{username: 'Sorry, this username is taken.'}} maxWidth="size-3000">
  <TextField label="Username" name="username" />
</Form>
```

See the [Forms](forms.html) guide to learn more about form validation in React Spectrum, including client-side validation, and integration with other frameworks and libraries.

### Validation behavior

By default, validation errors are displayed to the user in realtime as the value is edited, and do not block form submission. To enable native HTML form validation and prevent form submission when fields are invalid, set the `validationBehavior` prop to `"native"`.

```tsx example
import {ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  <TextField label="Email" name="email" type="email" isRequired />
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

### Focus management

By default, after a user submits a form with validation errors, the first invalid field will be focused. You can prevent this by calling `preventDefault` during the `onInvalid` event, and move focus yourself.

This example shows how to move focus to an [InlineAlert](InlineAlert.html) using the `autoFocus` prop when displaying validation errors at the top of a form.

```tsx example
import {InlineAlert, Heading, Content} from '@adobe/react-spectrum';

function Example() {
  let [isInvalid, setInvalid] = React.useState(false);

  return (
    <Form
      validationBehavior="native"
      /*- begin highlight -*/
      onInvalid={e => {
        e.preventDefault();
        setInvalid(true);
      }}
      /*- end highlight -*/
      onSubmit={e => {
        e.preventDefault();
        setInvalid(false);
      }}
      onReset={() => setInvalid(false)}
      maxWidth="size-3600">
      {isInvalid &&
        /*- begin highlight -*/
        <InlineAlert variant="negative" autoFocus>
        {/*- end highlight -*/}
          <Heading>Unable to submit</Heading>
          <Content>
            Please fix the validation errors below, and re-submit the form.
          </Content>
        </InlineAlert>
      }
      <TextField label="First Name" isRequired />
      <TextField label="Last Name" isRequired />
      <ButtonGroup>
        <Button type="submit" variant="primary">Submit</Button>
        <Button type="reset" variant="secondary">Reset</Button>
      </ButtonGroup>
    </Form>
  );
}
```

## Props

<PropTable component={docs.exports.Form} links={docs.links} />

## Visual options

### Label position and alignment
Top label position, start label alignment
```tsx example
<Form
  labelPosition="top"
  labelAlign="start"
  aria-label="Top position, start alignment example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```
Side label position, start label alignment
```tsx example
<Form
  labelPosition="side"
  labelAlign="start"
  aria-label="Side position, start alignment example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```
Side label position, end label alignment
```tsx example
<Form
  labelPosition="side"
  labelAlign="end"
  aria-label="Side position, end alignment example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

### Quiet

```tsx example
<Form
  isQuiet
  aria-label="Quiet example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <TextField label="Address" />
</Form>
```

### Emphasized

```tsx example
<Form
  isEmphasized
  aria-label="Emphasized example"
  maxWidth="size-3600">
  <TextField label="Name"/>
  <RadioGroup label="Favorite pet" defaultValue="dogs">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

### Disabled

```tsx example
<Form
  isDisabled
  aria-label="Disabled example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

### Required and necessity indicator

Optional label
```tsx example
<Form
  necessityIndicator="label"
  aria-label="Optional with label example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```
Required label
```tsx example
<Form
  isRequired
  necessityIndicator="label"
  aria-label="Required with label example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```
Required with asterisk
```tsx example
<Form
  isRequired
  necessityIndicator="icon"
  aria-label="Required with asterisk example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

### Read only

```tsx example
<Form
  isReadOnly
  aria-label="isReadOnly example"
  maxWidth="size-3600">
  <TextField label="Name" value="John Smith" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

### Validation state

```tsx example
<Form
  validationState="invalid"
  aria-label="Invalid validationState example"
  maxWidth="size-3600"
  marginBottom="size-300">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```
```tsx example
<Form
  validationState="valid"
  aria-label="Valid validationState example"
  maxWidth="size-3600">
  <TextField label="Name" />
  <RadioGroup label="Favorite pet">
    <Radio value="dogs">Dogs</Radio>
    <Radio value="cats">Cats</Radio>
  </RadioGroup>
</Form>
```

---

### Packages @Adobe React Spectrum Docs Icon Custom Icons (`packages/@adobe/react-spectrum/docs/icon/custom-icons.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/icon';
import {HeaderInfo, PropTable} from '@react-spectrum/docs';
import packageData from '@react-spectrum/icon/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Icon} from '@react-spectrum/icon';
```

---
category: Icons
---

# Custom Icons

Custom icons can be used by wrapping them in an Icon component.

<HeaderInfo
  packageData={packageData}
  componentNames={['Icon']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/iconography/'}
  ]}
  since="3.0.0" />

## Example

```tsx example export=true
function CustomIcon(props) {
  return(
    <Icon {...props}>
      <svg viewBox="0 0 36 36">
        <path d="M18.477.593,22.8,12.029l12.212.578a.51.51,0,0,1,.3.908l-9.54,7.646,3.224,11.793a.51.51,0,0,1-.772.561L18,26.805,7.78,33.515a.51.51,0,0,1-.772-.561l3.224-11.793L.692,13.515a.51.51,0,0,1,.3-.908L13.2,12.029,17.523.593A.51.51,0,0,1,18.477.593Z" />
      </svg>
    </Icon>
  );
}

<CustomIcon aria-label="Star" />
```

Wrapping the SVG with Icon will ensure it receives proper styling when used within React Spectrum components:

```tsx example
import {Button, Text} from '@adobe/react-spectrum';

<Button variant="primary">
  <CustomIcon />
  <Text>Favorite</Text>
</Button>
```

## Sizing

Icons support t-shirt sizing. When used inside another React Spectrum component, they'll generally be sized automatically,
but if you use icons standalone, you can use the `size` prop to control the sizing. The default size is "M" in medium scale
(desktop), and "L" in large scale (mobile).

```tsx example
<Flex gap="size-100">
  <CustomIcon aria-label="XXS Star" size="XXS" />
  <CustomIcon aria-label="XS Star" size="XS" />
  <CustomIcon aria-label="S Star" size="S" />
  <CustomIcon aria-label="M Star" size="M" />
  <CustomIcon aria-label="L Star" size="L" />
  <CustomIcon aria-label="XL Star" size="XL" />
  <CustomIcon aria-label="XXL Star" size="XXL" />
</Flex>
```

## Coloring

Icons support four Spectrum semantic colors: `negative`, `notice`, `positive`, and `informative`. Icons within React Spectrum components typically
have their colors styled appropriately, but you can use the `color` prop to adjust the color of any standalone icons.

```tsx example
<Flex gap="size-100">
  <CustomIcon aria-label="Default Star" />
  <CustomIcon aria-label="Negative Star" color="negative" />
  <CustomIcon aria-label="Notification Star" color="notice" />
  <CustomIcon aria-label="Positive Star" color="positive" />
  <CustomIcon aria-label="Informative Star" color="informative" />
</Flex>
```

## Labeling

By default, icons are considered decorative, and are hidden from assistive technology. When used within a component like a button
that has no label, an `aria-label` should be provided to the parent component. If used standalone, an `aria-label` can be provided
to the icon itself.

## Props

<PropTable component={docs.exports.Icon} links={docs.links} />

---

### Packages @Adobe React Spectrum Docs Icon Workflow Icons (`packages/@adobe/react-spectrum/docs/icon/workflow-icons.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/icon';
import {HeaderInfo, PropTable} from '@react-spectrum/docs';
import packageData from '@react-spectrum/icon/package.json';
import workflowIconPackageData from '@spectrum-icons/workflow/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
```

---
category: Icons
---

# Workflow Icons

Workflow icons are graphical metaphors or symbols that can be used to compliment existing experiences.

<HeaderInfo
  packageData={workflowIconPackageData}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/iconography/'}
  ]} />

## Example

```tsx example
import Airplane from '@spectrum-icons/workflow/Airplane';

<Airplane aria-label="Airplane" />
```

## Sizing

Icons support t-shirt sizing. When used inside another React Spectrum component, they'll generally be sized automatically,
but if you use icons standalone, you can use the `size` prop to control the sizing. The default size is "M" in medium scale
(desktop), and "L" in large scale (mobile).

```tsx example
import Beaker from '@spectrum-icons/workflow/Beaker';

<Flex gap="size-100">
  <Beaker aria-label="XXS Beaker" size="XXS" />
  <Beaker aria-label="XS Beaker" size="XS" />
  <Beaker aria-label="S Beaker" size="S" />
  <Beaker aria-label="M Beaker" size="M" />
  <Beaker aria-label="L Beaker" size="L" />
  <Beaker aria-label="XL Beaker" size="XL" />
  <Beaker aria-label="XXL Beaker" size="XXL" />
</Flex>
```

## Coloring

Icons support four Spectrum semantic colors: `negative`, `notice`, `positive`, and `informative`. Icons within React Spectrum components typically
have their colors styled appropriately, but you can use the `color` prop to adjust the color of any standalone icons.

```tsx example
import Alert from '@spectrum-icons/workflow/Alert';

<Flex gap="size-100">
  <Alert aria-label="Default Alert" />
  <Alert aria-label="Negative Alert" color="negative" />
  <Alert aria-label="Notification Alert" color="notice" />
  <Alert aria-label="Positive Alert" color="positive" />
  <Alert aria-label="Informative Alert" color="informative" />
</Flex>
```

## Labeling

By default, icons are considered decorative, and are hidden from assistive technology. When used within a component like a button
that has no label, an `aria-label` should be provided to the parent component. If used standalone, an `aria-label` can be provided
to the icon itself.

```tsx example
import LockClosed from '@spectrum-icons/workflow/LockClosed';

<LockClosed aria-label="Locked" />
```

## Available Icons

A [searchable list of workflow icons](https://spectrum.adobe.com/page/icons/) is available on the Spectrum website.
The name of the icon without any whitespace matches the import in React Spectrum.

**Note**: The Workflow icons we ship should not be wrapped in an `Icon` component like [Custom Icons](custom-icons.html), they are already wrapped.

---

### Packages @Adobe React Spectrum Docs Illustratedmessage IllustratedMessage (`packages/@adobe/react-spectrum/docs/illustratedmessage/IllustratedMessage.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/illustratedmessage';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/illustratedmessage/package.json';

```jsx import
import {Content} from '@react-spectrum/view';
import {Heading} from '@react-spectrum/text';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
```

---
category: Content
keywords: [illustrated message]
---

# IllustratedMessage

<PageDescription>{docs.exports.IllustratedMessage.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['IllustratedMessage']}
  since="3.0.0" />

## Example

```tsx example
import NotFound from '@spectrum-icons/illustrations/NotFound';

<IllustratedMessage>
  <NotFound />
  <Heading>No results</Heading>
  <Content>Try another search</Content>
</IllustratedMessage>
```

## Content

An IllustratedMessage consists of three areas: an illustration, a title, and a body.
Each of these sections can be populated by providing the following components to your IllustratedMessage as children:
`svg`, [Heading](Heading.html) (title), and [Content](Content.html) (body).

```tsx example
import Upload from '@spectrum-icons/illustrations/Upload';

<IllustratedMessage>
  <Upload />
  <Heading>Drag and Drop your file</Heading>
  <Content>Select a File from your computer<br /> or Search Adobe Stock</Content>
</IllustratedMessage>
```

### Accessibility

When an IllustratedMessage has a `svg` and a `Heading`, the `svg` needs an `aria-hidden` prop and a `role` prop set to `presentation`.

## Labeling

### Accessibility

The title of an IllustratedMessage is typically provided via its `Heading`.
If a `Heading` isn't specified, the illustration needs an `aria-label` prop to identify it to assistive technology.
If you pass an SVG in yourself, you'll need to ensure that the `role` prop is set to `img` as well.

```tsx example
<IllustratedMessage>
  <NotFound aria-label="No results" />
</IllustratedMessage>
```

## Props

<PropTable component={docs.exports.IllustratedMessage} links={docs.links} />

## Example illustrations

The below examples make use of illustrations included in the [@spectrum-icons/illustrations](http://npmjs.com/@spectrum-icons/illustrations) package.

### No search results

```tsx example
import NoSearchResults from '@spectrum-icons/illustrations/NoSearchResults';

<IllustratedMessage>
  <NoSearchResults />
  <Heading>No matching results</Heading>
  <Content>Try another search.</Content>
</IllustratedMessage>
```

### 403 Forbidden

```tsx example
import Unauthorized from '@spectrum-icons/illustrations/Unauthorized';

<IllustratedMessage>
  <Unauthorized />
  <Heading>Error 403: Access not allowed</Heading>
  <Content>You do not have permission to access this page. Try checking the URL or visit a different page.</Content>
</IllustratedMessage>
```

### 404 Not found

```tsx example
<IllustratedMessage>
  <NotFound />
  <Heading>Error 404: Page not found</Heading>
  <Content>This page isn't available. Try checking the URL or visit a different page.</Content>
</IllustratedMessage>
```

### 500 Internal server error

```tsx example
import Error from '@spectrum-icons/illustrations/Error';

<IllustratedMessage>
  <Error />
  <Heading>Error 500: Internal server error</Heading>
  <Content>Something went wrong. Please try again later.</Content>
</IllustratedMessage>
```

### 503 Service unavailable

```tsx example
import Unavailable from '@spectrum-icons/illustrations/Unavailable';

<IllustratedMessage>
  <Unavailable />
  <Heading>Error 503: Service unavailable</Heading>
  <Content>This page isn't working. Try a different page or try again later.</Content>
</IllustratedMessage>
```

### 504 Gateway timeout

```tsx example
import Timeout from '@spectrum-icons/illustrations/Timeout';

<IllustratedMessage>
  <Timeout />
  <Heading>Error 504: Server timeout</Heading>
  <Content>The server took too long. Please try again later.</Content>
</IllustratedMessage>
```

---

### Packages @Adobe React Spectrum Docs Image Image (`packages/@adobe/react-spectrum/docs/image/Image.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/image';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/image/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Image} from '@react-spectrum/image';
```

---
category: Content
---

# Image

<PageDescription>{docs.exports.Image.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Image']}
  since="3.0.0" />

## Examples

```tsx example
<Image src="https://i.imgur.com/Z7AzH2c.png" alt="Sky and roof" />
```

## Content

The `Image` component represents an image within a Spectrum container
such as a [Dialog](Dialog.html). `Image` provides no specific styling
by itself, but receives styling from the parent container. In addition,
`Image` will be automatically placed within the container's layout
according to Spectrum guidelines.

**Note: Images must have an `alt` attribute.** If the image is
considered decorative and should not be announced by screen readers,
then set `alt=""` to suppress the warning.

See [Dialog](Dialog.html#examples) for examples of how to use the
`Image` component in the context of a Spectrum container.

### Internationalization

To internationalize an `Image`, a localized string should be passed to the `alt` prop.

## Props

<PropTable component={docs.exports.Image} links={docs.links} />

## Visual options

### Decorative

```tsx example
<Flex width="200px">
  <Image src="https://i.imgur.com/c3gTKSJ.jpg" alt="" />
</Flex>
```

### Object Fit

```tsx example
<Flex width="100%" height="200px">
  <Image
    src="https://i.imgur.com/c3gTKSJ.jpg"
    alt="Eiffel Tower at sunset"
    objectFit="cover" />
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Inlinealert InlineAlert (`packages/@adobe/react-spectrum/docs/inlinealert/InlineAlert.mdx`)

{/* Copyright 2023 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/inlinealert';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/inlinealert/package.json';

```jsx import
import {InlineAlert} from '@react-spectrum/inlinealert';
import {Content} from '@adobe/react-spectrum';
import {Heading} from '@react-spectrum/text';
```

---
category: Status
keywords: [inline alert, alert]
---

# InlineAlert

<PageDescription>{docs.exports.InlineAlert.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['InlineAlert']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/in-line-alert/'}
  ]}
  since="3.29.0" />

## Example

```tsx example
<InlineAlert>
  <Heading>Payment Information</Heading>
  <Content>Enter your billing address, shipping address, and payment method to complete your purchase.</Content>
</InlineAlert>
```

## Content

Inline alerts contain a title and body. They also include an icon for non-neutral variants.

```tsx example
<InlineAlert variant="positive">
  <Heading>Payment Information</Heading>
  <Content>Enter your billing address, shipping address, and payment method to complete your purchase.</Content>
</InlineAlert>
```

### Accessibility

Inline alerts are given the [alert role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role), which means they should only be used for information that requires the user's immediate attention.

### Internationalization

To internationalize an InlineAlert, localized strings should be set as the title and body content of the InlineAlert.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the InlineAlert is automatically flipped.

## Props

<PropTable component={docs.exports.InlineAlert} links={docs.links} />

## Visual options

### Variant
[View guidelines](https://spectrum.adobe.com/page/in-line-alert/#Options)

When inline alerts have a semantic meaning, they should use the appropriate variant.
The default variant is neutral, and should be used when the message is neutral in tone or when its semantics do not fit any of the other variants.

#### Informative

```tsx example
<InlineAlert variant="info">
  <Heading>Accepted Payment Methods</Heading>
  <Content>Only major credit cards are accepted for payment. Direct debit is currently unavailable.</Content>
</InlineAlert>
```

#### Positive

```tsx example
<InlineAlert variant="positive">
  <Heading>Purchase completed</Heading>
  <Content>You'll get a confirmation email with your order details shortly.</Content>
</InlineAlert>
```

#### Notice

```tsx example
<InlineAlert variant="notice">
  <Heading>Update payment information</Heading>
  <Content>The saved credit card for your account has expired. Update your payment information to complete the purchase.</Content>
</InlineAlert>
```

#### Negative

```tsx example
<InlineAlert variant="negative">
  <Heading>Unable to process payment</Heading>
  <Content>There was an error processing your payment. Please check that your credit card information is correct, then try again.</Content>
</InlineAlert>
```

---

### Packages @Adobe React Spectrum Docs Labeledvalue LabeledValue (`packages/@adobe/react-spectrum/docs/labeledvalue/LabeledValue.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/labeledvalue';
import types from 'docs:./types.ts';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/labeledvalue/package.json';

```jsx import
import {LabeledValue} from '@react-spectrum/labeledvalue';
```

---
category: Status
keywords: [label, value, read only]
---

# LabeledValue

<PageDescription>{docs.exports.LabeledValue.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['LabeledValue']}
  since="3.22.0" />

## Example

```tsx example
<LabeledValue label="File name" value="Budget.xls" />
```

## Value

In addition to a string as shown above, a `LabeledValue` accepts numbers, dates, times, and lists of strings in the `value` prop.

### Numbers

When the `value` prop is set to a number, `LabeledValue` formats it according to the user's locale.

```tsx example
<LabeledValue label="Number of cookies" value={1024} />
```

Custom `formatOptions` can also be provided to format the value as a percentage, unit, currency, etc. This prop is compatible
with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat).

```tsx example
<LabeledValue label="File size" value={1.2} formatOptions={{style: 'unit', unit: 'megabyte'}} />
```

An object with `start` and `end` properties may also be provided to format a numeric range.

```tsx example
<LabeledValue label="Price range" value={{start: 150, end: 400}} formatOptions={{style: 'currency', currency: 'USD', minimumFractionDigits: 0}} />
```

### Dates and times

The `value` prop may be set to a JavaScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object, or one of the types from [@internationalized/date](react-aria:internationalized/date/) to display a date or time, which is formatted according to the user's locale.

```tsx example
import {today, getLocalTimeZone} from '@internationalized/date';

<LabeledValue label="Date modified" value={today(getLocalTimeZone()).subtract({weeks: 1})} />
```

By default, the formatting depends on the type of value provided. Above, a [CalendarDate](react-aria:internationalized/date/CalendarDate) is provided, so only the date is displayed. To display a time, pass a [Time](react-aria:internationalized/date/Time) object. You can also provide a [CalendarDateTime](react-aria:internationalized/date/CalendarDateTime) or [ZonedDateTime](react-aria:internationalized/date/ZonedDateTime) to display a date with a time.

```tsx example
import {now, getLocalTimeZone} from '@internationalized/date';

<LabeledValue label="Page load time" value={now(getLocalTimeZone())} />
```

An object with `start` and `end` properties may also be provided to format a date or time range.

```tsx example
import {Time} from '@internationalized/date';

<LabeledValue label="Business hours" value={{start: new Time(8, 30), end: new Time(18)}} />
```

Custom `formatOptions` can also be provided control the exact date format. This prop is compatible
with the option parameter of [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat).

```tsx example
<LabeledValue label="Appointment date" value={new Date(2022, 6, 5)} formatOptions={{dateStyle: 'short'}} />
```

### Lists

When the `value` prop is set to an array of strings, they are rendered as a comma-separated list according to the user's locale.

```tsx example
<LabeledValue label="Pizza toppings" value={['Pepperoni', 'Pineapple', 'Mushroom', 'Garlic']} />
```

By default, the list is displayed as a conjunction (an "and"-based grouping of items). This may be changed to a disjunction (an "or"-based grouping), or a pure comma-separated list using the `formatOptions` prop. This is compatible with the option parameter of [Intl.ListFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat).

```tsx example
<LabeledValue label="Interests" value={['Travel', 'Hiking', 'Snorkeling', 'Camping']} formatOptions={{type: 'unit'}} />
```

### Components

The value can be a component and will be rendered as provided. Components cannot be editable.

```tsx example
import {Link} from '@adobe/react-spectrum';

<LabeledValue label="Website" value={<Link href="https://www.adobe.com/">Adobe.com</Link>} />
```

## Labeling

A visual label must be provided to the `LabeledValue` using the `label` prop.

### Internationalization

In order to internationalize a `LabeledValue`, a localized string should be passed to the `label` prop.

`LabeledValue` automatically formats numbers, dates, times, and lists according to the user's locale, as defined by the [Provider](Provider.html#locales) component. String values provided to a `LabeledValue` should be translated accordingly.

## Props

<PropTable component={{props: types.exports.LabeledValueProps}} links={types.links} />

## Visual options

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/field-label/#Label-position)

By default, the label is positioned above the `LabeledValue`. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the `LabeledValue` and "end" refers to the right-most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<LabeledValue label="File name" value="Onboarding.pdf" labelPosition="side" labelAlign="end" />
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a LabeledValue.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<LabeledValue
  label="Aperture"
  value="f/1.5"
  contextualHelp={
    <ContextualHelp>
      <Heading>What is the aperture?</Heading>
      <Content>The aperture setting controls the amount of light reaching the image sensor.</Content>
    </ContextualHelp>
  } />
```

---

### Packages @Adobe React Spectrum Docs Layout Flex (`packages/@adobe/react-spectrum/docs/layout/Flex.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/layout';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/layout/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {View} from '@react-spectrum/view';
```

---
category: Layout
---

# Flex

<PageDescription>{docs.exports.Flex.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Flex']}
  since="3.0.0" />

## Introduction

The `Flex` component can be used to layout its children in one dimension with
[flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox).
Any React Spectrum component can be used as a child, and `Flex` components can be nested to create
more complex layouts.

The `gap`, `rowGap` and `columnGap` can be defined with [Spectrum dimension variables](styling.html#dimension-values)
to ensure consistency across applications, and allow the layout to adapt to different devices automatically.
These values can be autocompleted in many IDEs for convenience.

All `Flex` props also support object syntax to define responsive layouts that change at certain breakpoints.
See the [layout docs](layout.html#responsive-layout) for more details.

## Examples

### Vertical stack

This example shows a simple vertical stack, with a gap between each item defined
using a [Spectrum dimension variable](styling.html#dimension-values).

```tsx example
<Flex direction="column" width="size-2000" gap="size-100">
  <View backgroundColor="celery-600" height="size-800" />
  <View backgroundColor="blue-600" height="size-800" />
  <View backgroundColor="magenta-600" height="size-800" />
</Flex>
```

### Horizontal stack

This example shows a horizontal stack.

```tsx example
<Flex direction="row" height="size-800" gap="size-100">
  <View backgroundColor="celery-600" width="size-800" />
  <View backgroundColor="blue-600" width="size-800" />
  <View backgroundColor="magenta-600" width="size-800" />
</Flex>
```

### Nesting

This example shows how you can nest flexboxes to create more complicated layouts. It also uses the `flex`
prop on one of the children to expand it to fill the repaining space.

```tsx example
<Flex direction="column" gap="size-100">
  <View backgroundColor="celery-600" height="size-800" />
  <Flex direction="row" height="size-3000" gap="size-100">
    <View backgroundColor="indigo-600" width="size-2000" />
    <View backgroundColor="seafoam-600" flex />
  </Flex>
  <View backgroundColor="magenta-600" height="size-800" />
</Flex>
```

### Wrapping

This example shows how to enable wrapping of items into multiple rows. Resize your browser window to see the
items reflow.

```tsx import
let baseColors = ['celery', 'chartreuse', 'yellow', 'magenta', 'fuchsia', 'purple', 'indigo', 'seafoam', 'red', 'orange', 'green', 'blue'];
let colors = [];
for (let color of baseColors) {
  for (let i = 4; i <= 7; i++) {
    colors.push(`${color}-${i}00`);
  }
}
```

```tsx example
<Flex direction="row" gap="size-100" wrap>
  {colors.map(color =>
    <View key={color} backgroundColor={color} width="size-800" height="size-800" />
  )}
</Flex>
```

### Alignment

The `alignItems` prop can be used to align items along the cross axis. When `direction` is `"column"`, this refers to
horizontal alignment, and when `direction` is `"row"` it refers to vertical alignment.

This example horizontally centers items in a vertical stack.

```tsx example
<Flex direction="column" gap="size-100" alignItems="center">
  <View backgroundColor="celery-600" width="size-800" height="size-800" />
  <View backgroundColor="blue-600" width="size-2000" height="size-800" />
  <View backgroundColor="magenta-600" width="size-800" height="size-800" />
</Flex>
```

**NOTE**: the default value for `alignItems` is `"stretch"` according to the CSS spec. This means that if your items do
not have a size defined in the cross direction, then they will be stretched to fill the height of the container.
This may be undesirable in some cases, e.g. a group of buttons with varying heights. Ensure you set
an `alignItems` value to account for this.

### Justification

The `justifyContent` prop can be used to align items along the main axis. When `direction` is `"column"`, this refers
to vertical alignment, and when `direction` is `"row"` it refers to horizontal alignment.

This example vertically centers the stack of items within the available space defined by a container.

```tsx example
<View height="size-3000" borderWidth="thin" borderColor="dark">
  <Flex direction="column" gap="size-100" justifyContent="center" height="100%">
    <View backgroundColor="celery-600" width="size-800" height="size-800" />
    <View backgroundColor="blue-600" width="size-2000" height="size-800" />
    <View backgroundColor="magenta-600" width="size-800" height="size-800" />
  </Flex>
</View>
```

## Props

<PropTable component={docs.exports.Flex} links={docs.links} />

---

### Packages @Adobe React Spectrum Docs Layout Grid (`packages/@adobe/react-spectrum/docs/layout/Grid.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/layout';
import {HeaderInfo, PropTable, FunctionAPI, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/layout/package.json';

```jsx import
import {Grid, repeat} from '@react-spectrum/layout';
import {View} from '@react-spectrum/view';
```

---
category: Layout
---

# Grid

<PageDescription>{docs.exports.Grid.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Grid']}
  since="3.0.0" />

## Introduction

The `Grid` component can be used to layout its children in two dimensions with
[CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout).
Any React Spectrum component can be used as a child, and [Spectrum dimension variables](styling.html#dimension-values)
can be used to define sizing and spacing, which ensures consistency across applications, and allows the layout to adapt
to different devices automatically. In addition, these values can be autocompleted in many IDEs for convenience.

All `Grid` props also support object syntax to define responsive layouts that change at certain breakpoints.
See the [layout docs](layout.html#responsive-layout) for more details.

## Examples

### Explicit grids

This example shows how to build a common application layout with a header, sidebar, content area, and footer.
It uses the `areas` prop to define the grid areas, along with `columns` and `rows` to define the sizes.
Each child uses the `gridArea` prop to declare which area it should be placed in.

```tsx example
<Grid
  areas={[
    'header  header',
    'sidebar content',
    'footer  footer'
  ]}
  columns={['1fr', '3fr']}
  rows={['size-1000', 'auto', 'size-1000']}
  height="size-6000"
  gap="size-100">
  <View backgroundColor="celery-600" gridArea="header" />
  <View backgroundColor="blue-600" gridArea="sidebar" />
  <View backgroundColor="purple-600" gridArea="content" />
  <View backgroundColor="magenta-600" gridArea="footer" />
</Grid>
```

### Implicit grids

This example creates an implicit grid. It declares the columns using the `repeat` function to automatically generate
as many columns as fit, and uses the `autoRows` prop to set the size of the implicitly created rows. The items are
centered horizontally within the container, and have a gap between them defined
using a [Spectrum dimension variable](styling.html#dimension-values).
Resize your browser to see how items reflow.

```tsx import
let baseColors = ['celery', 'chartreuse', 'yellow', 'magenta', 'fuchsia', 'purple', 'indigo', 'seafoam', 'red', 'orange', 'green', 'blue'];
let colors = [];
for (let color of baseColors) {
  for (let i = 4; i <= 7; i++) {
    colors.push(`${color}-${i}00`);
  }
}
```

```tsx example
<Grid
  columns={repeat('auto-fit', 'size-800')}
  autoRows="size-800"
  justifyContent="center"
  gap="size-100">
  {colors.map(color =>
    <View key={color} backgroundColor={color} />
  )}
</Grid>
```

## Props

<PropTable component={docs.exports.Grid} links={docs.links} />

## Helper functions

React Spectrum offers JavaScript versions of the CSS functions that are often used with CSS grid.
These allow using Spectrum variables to define dimensions, and are typed to allow IDE autocomplete.

### repeat

The [repeat](https://developer.mozilla.org/en-US/docs/Web/CSS/repeat) function can be used to make
a repeating fragment of the columns or rows list.

<FunctionAPI function={docs.exports.repeat} links={docs.links} />

### minmax

The [minmax](https://developer.mozilla.org/en-US/docs/Web/CSS/minmax) function defines a size range
greater than or equal to `min` and less than or equal to `max`.

<FunctionAPI function={docs.exports.minmax} links={docs.links} />

### fitContent

The [fitContent](https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content) function clamps a given
size to an available size.

<FunctionAPI function={docs.exports.fitContent} links={docs.links} />

---

### Packages @Adobe React Spectrum Docs Link Link (`packages/@adobe/react-spectrum/docs/link/Link.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/link';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/link/package.json';

```jsx import
import {Link} from '@react-spectrum/link';
import {View} from '@react-spectrum/view';
```

---
category: Navigation
---

# Link

<PageDescription>{docs.exports.Link.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Link']}
  sourceData={[{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/link/'}]}
  since="3.0.0" />

## Example

```tsx example
<Link href="https://www.imdb.com/title/tt6348138/" target="_blank">The missing link.</Link>
```

## Content


Links accept content as children. If the link has an href prop, it will be rendered as an `<a>` element.

```tsx example
<Link href="https://adobe.com" target="_blank">Adobe.com</Link>
```

### JavaScript handled links

When a `<Link`> does not have an `href` prop, it is rendered as a `<span role="link">` instead of an `<a>`. Events will need to be handled in JavaScript with the `onPress` prop.

Note: this will not behave like a native link. Browser features like context menus and open in new tab will not apply.

```tsx example
<Link onPress={() => alert('Pressed link')}>Adobe</Link>
```

### Client side routing

The `<Link>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

### Internationalization

In order to internationalize a link, a localized string should be passed to the `children` prop.

### Accessibility

When an `href` is not provided, the link component will expose the accessible role to assistive technology as a "link".

```tsx example
<Link onPress={e => alert(`clicked "${e.target.textContent}" Link`)}>
  I forgot my password
</Link>
```

Be mindful of what the experience is for users navigating with screen readers. Make sure to give enough context about where the link will take the user.

The quiet style must only be used when the placement and context of the link is explicit enough that a visible underline isn’t necessary. It must not be used within, for example, a paragraph of text.

## Props

<PropTable component={docs.exports.Link} links={docs.links} />

## Visual options
[View Guidelines](https://spectrum.adobe.com/page/link/#Options)

### Primary
```tsx example
<p>Would you like to <Link variant="primary">learn more</Link> about this fine component?</p>
```

### Secondary
```tsx example
<p>Would you like to <Link variant="secondary">learn more</Link> about this fine component?</p>
```

### Over background
```tsx example
<View backgroundColor="positive" padding="size-300">
  <Link variant="overBackground">Learn more here!</Link>
</View>
```

### Quiet
```tsx example
<p>Would you like to <Link isQuiet>learn more</Link> about this fine component?</p>
```

---

### Packages @Adobe React Spectrum Docs List ListView (`packages/@adobe/react-spectrum/docs/list/ListView.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import Anatomy from './anatomy.svg';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import docs from 'docs:@react-spectrum/list';
import dndDocs from 'docs:@react-spectrum/dnd';
import gridlistUtil from 'docs:@react-aria/test-utils';
import {HeaderInfo, PropTable, PageDescription, TypeLink, ClassAPI, VersionBadge} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-spectrum/list/package.json';

```jsx import
import {ActionMenu} from '@react-spectrum/menu';
import Delete from '@spectrum-icons/workflow/Delete';
import Edit from '@spectrum-icons/workflow/Edit';
import {Flex} from '@react-spectrum/layout';
import {Heading, Text} from '@react-spectrum/text';
import {Image} from '@react-spectrum/image';
import {Item, ListView} from '@react-spectrum/list';
```

---
category: Collections
keywords: [listview, collections]
---

# ListView

<PageDescription>{docs.exports.ListView.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Item', 'ListView']}
  since="3.21.0" />

## Example
```tsx example
<ListView selectionMode="multiple" aria-label="Static ListView items example" maxWidth="size-6000">
  <Item>Adobe Photoshop</Item>
  <Item>Adobe InDesign</Item>
  <Item>Adobe AfterEffects</Item>
  <Item>Adobe Illustrator</Item>
  <Item>Adobe Lightroom</Item>
</ListView>
```

## Content
ListView is a [collection component](collections.html) that provides users with a way to view, select, navigate, or drag and drop items in a list. While it may feel similar to the [ListBox](ListBox.html)
component, ListView offers greater flexibility in the contents it can render and can distinguish between row selection and actions performed on a row. This makes ListView an ideal component for use cases such as file
managers.

Basic usage of ListView, seen in the example above, shows the use of a static collection where the contents of the ListView are hard coded.
Dynamic collections, as shown below, can be used when the options come from an external data source such as an API, or update over time. Providing the data dynamically allows ListView
to automatically cache the rendering of each item, which dramatically improves performance.

Each item has a unique key defined by the data. In the example below, the `key` of each row element is implicitly defined by the id property of the row object.
See [collections](collections.html#unique-keys) to learn more about keys in dynamic collections.


```tsx example
const items = [
  {id: 1, name: 'Adobe Photoshop'},
  {id: 2, name: 'Adobe XD'},
  {id: 3, name: 'Adobe InDesign'},
  {id: 4, name: 'Adobe AfterEffects'},
  {id: 5, name: 'Adobe Illustrator'},
  {id: 6, name: 'Adobe Lightroom'},
  {id: 7, name: 'Adobe Premiere Pro'},
  {id: 8, name: 'Adobe Fresco'},
  {id: 9, name: 'Adobe Dreamweaver'}
];

<ListView items={items} selectionMode="multiple" maxWidth="size-6000" height="250px" aria-label="Dynamic ListView items example">
  {(item) => <Item>{item.name}</Item>}
</ListView>
```

### Internationalization
To internationalize a ListView, all text content within the ListView should be localized. This includes the `aria-label` provided to the ListView if any.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of ListView is automatically flipped.

## Labeling
### Accessibility
An `aria-label` must be provided to the ListView for accessibility. If the ListView is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

## Asynchronous loading
ListView supports loading data asynchronously, and will display a progress circle reflecting the current load state,
set by the `loadingState` prop. It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data.
See the docs for more information.

```tsx example
import {useAsyncList} from '@adobe/react-spectrum';

interface Character {
  name: string
}

function AsyncList() {
  let list = useAsyncList<Character>({
    async load({signal, cursor}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=`, {signal});
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <ListView
      selectionMode="multiple"
      aria-label="Async loading ListView example"
      maxWidth="size-6000"
      height="size-3000"
      items={list.items}
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}>
      {(item) => (
        <Item key={item.name}>{item.name}</Item>
      )}
    </ListView>
  );
}
```

## Complex items

<Anatomy />

Items within a ListView also allow for additional content used to add context or provide additional actions to items. Descriptions, illustrations, and thumbnails can be added to
the children of `<Item>` as shown in the example below. If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
Additionally, components such as `<ActionButton>`, `<ActionGroup>`, and `<ActionMenu>` will be styled appropriately if included within an item. Providing the `hasChildItems` prop
to an `<Item>` will add a chevron icon to the end of the row to visually indicate that the row has children.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Selection

By default, ListView doesn't allow row selection, but this can be enabled using the `selectionMode` prop.
Use `defaultSelectedKeys` to provide a default set of selected rows. Note that the value of the selected keys must match the `key` prop of the Item.

The example below enables multiple selection mode, and uses `defaultSelectedKeys` to select the rows with keys "Charizard" and "Venusaur".

```tsx example
<ListView maxWidth="size-6000" selectionMode="multiple" defaultSelectedKeys={["Charizard", "Venusaur"]} aria-label="ListView multiple selection example">
  <Item key="Charizard">
    Charizard
  </Item>
  <Item key="Blastoise">
    Blastoise
  </Item>
  <Item key="Venusaur">
    Venusaur
  </Item>
  <Item key="Pikachu">
    Pikachu
  </Item>
</ListView>
```

### Controlled selection

To programmatically control row selection, use the `selectedKeys` prop paired with the `onSelectionChange` callback. The `key` prop from the selected rows will
be passed into the callback when the row is pressed, allowing you to update state accordingly. Note that the value of the selected keys must match the `key` prop of the Item.

Here is how you would control selection for the above example.

```tsx example export=true
import type {SpectrumListViewProps} from '@react-spectrum/list';

function PokemonList<T>(props: Omit<SpectrumListViewProps<T>, 'children'>) {
  let rows = [
    {id: 1, name: 'Charizard'},
    {id: 2, name: 'Blastoise'},
    {id: 3, name: 'Venusaur'},
    {id: 4, name: 'Pikachu'}
  ];

  let [selectedKeys, setSelectedKeys] = React.useState(props.defaultSelectedKeys || new Set([2]));

  return (
    <ListView maxWidth="size-6000" aria-label="ListView with controlled selection" selectionMode="multiple" {...props} items={rows} selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
      {(item) => (
        <Item>
          {item.name}
        </Item>
      )}
    </ListView>
  );
}
```

### Single selection

To limit users to selecting only a single item at a time, `selectionMode` can be set to `single`.

```tsx example
// Using the same list as above
<PokemonList selectionMode="single" selectionStyle="highlight" aria-label="ListView with single selection" />
```

### Disallow empty selection

ListView also supports a `disallowEmptySelection` prop which forces the user to have at least one row in the ListView selected at all times.
In this mode, if a single row is selected and the user presses it, it will not be deselected.

```tsx example
// Using the same list as above
<PokemonList disallowEmptySelection aria-label="ListView with empty selection disallowed" />
```

### Disabled rows

You can disable specific rows by providing an array of keys to ListView via the `disabledKeys` prop. This will disable all interactions on disabled rows, unless the `disabledBehavior` prop is used to change this behavior.

```tsx example
// Using the same list as above
<PokemonList disabledKeys={[3]} aria-label="ListView with disabled rows" />
```

If you set the `disabledBehavior` prop to `selection`, interactions such as focus, dragging, or actions can still be performed on disabled rows.
```tsx example
<Flex wrap gap="size-300">
  <PokemonList
    disabledKeys={[3]}
    defaultSelectedKeys={[]}
    disabledBehavior="all"
    aria-label="ListView with all interaction disabled for disabled rows"
    width="size-2400"
    onAction={key => alert(`Opening item ${key}...`)}
  />
  <PokemonList
    disabledKeys={[3]}
    defaultSelectedKeys={[]}
    disabledBehavior="selection"
    aria-label="ListView with selection disabled for disabled rows"
    width="size-2400"
    onAction={key => alert(`Opening item ${key}...`)}
  />
</Flex>
```

### Highlight selection

By default, ListView uses the checkbox selection style, which includes a checkbox in each row for selection. When the selectionStyle prop is set to `"highlight"`, the checkboxes are hidden,
 and the selected rows are displayed with a highlighted background instead.

In addition to changing the appearance, the selection behavior also changes depending on the `selectionStyle` prop. In the default checkbox selection style, clicking, tapping, or pressing
the <Keyboard>Space</Keyboard> or <Keyboard>Enter</Keyboard> keys toggles selection for the focused row. Using the arrow keys moves focus but does not change selection.

In the highlight selection style, however, clicking a row with the mouse _replaces_ the selection with only that row. Using the arrow keys moves both focus and selection. To select multiple rows,
modifier keys such as <Keyboard>Ctrl</Keyboard>, <Keyboard>Cmd</Keyboard>, and <Keyboard>Shift</Keyboard> can be used. On touch screen devices, selection always behaves as toggle since modifier
keys may not be available.

These selection styles implement the behaviors defined in [Aria Practices](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/#keyboardinteraction).

```tsx example
// Using the same list as above
<PokemonList selectionStyle="highlight" aria-label="Highlight selection ListView" />
```

## Row actions

ListView supports row actions via the `onAction` prop, which is useful for functionality such as navigation. When nothing is selected, the ListView performs actions by default when clicking or tapping a row.
Items may be selected using the checkbox, or by long pressing on touch devices. When at least one item is selected, the ListView is in selection mode, and clicking or tapping a row toggles the selection. Actions may also
be triggered via the <Keyboard>Enter</Keyboard> key, and selection using the <Keyboard>Space</Keyboard> key.

This behavior is slightly different in the highlight selection style, where single clicking selects the row and actions are performed via double click. Touch and keyboard behaviors are unaffected.

```tsx example
// Checkbox selection with onAction
<Flex wrap gap="size-300">
  <PokemonList onAction={key => alert(`Opening item ${key}...`)} aria-label="Checkbox selection ListView with row actions" width="size-2400" />
  <PokemonList selectionStyle="highlight" onAction={key => alert(`Opening item ${key}...`)} aria-label="Highlight selection ListView with row actions" width="size-2400" />
</Flex>
```

### Links

Items in a ListView may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Links behave the same way as described above for row actions depending on the `selectionMode` and `selectionStyle`.

```tsx example
<ListView aria-label="Links" selectionMode="multiple">
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</ListView>
```

#### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Drag and drop

To enable drag and drop in a ListView, you must provide the drag and drop hooks sourced from <TypeLink links={dndDocs.links} type={dndDocs.exports.useDragAndDrop} /> to the ListView's `dragAndDropHooks` prop.
See the examples below for various common drag and drop use cases. For more information on `useDragAndDrop` and the various supported ways to perform a drag and drop interaction,
please see the [drag and drop documentation](dnd.html).

### Draggable ListView and droppable ListView

The example below demonstrates how to create a draggable ListView and a droppable ListView.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoList />
```

### Handling folder drops

The example below replicates the previous example but demonstrates how to handle on item drops.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoListFolder />
```

### Reorderable

The example below demonstrates how to make a ListView draggable and droppable at the same time. The ListView below supports reordering its own rows via drag and drop.
<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<ReorderableList />
```

### Bi-directional dragging

The example below demonstrates how to create a pair of ListViews that supports dragging and dropping any items between each list, but disables
the ability to drop into a folder. Each list is internally reorderable.
<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragBetweenListsExample />
```

### Overriding default drop operation

The example below demonstrates how to use `getDropOperation` to specify the default drop operation of the droppable list.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoListDefaultCopy />
```

### Custom drag previews

Use the `renderPreview` prop to provide a custom drag preview. `keys` and `draggedKey` are passed to this function, where `keys` includes all the keys of the items being dragged, and `draggedKey` is the key of the item the user initiated the drag from.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```tsx example export=true render=false
import {View} from '@react-spectrum/view';

function CustomDragPreviewExample() {
  let list = useListData({
    initialItems: [
      {id: '1', type: 'file', name: 'Adobe Photoshop'},
      {id: '2', type: 'file', name: 'Adobe XD'},
      {id: '3', type: 'file', name: 'Adobe InDesign'},
      {id: '4', type: 'file', name: 'Adobe AfterEffects'}
    ]
  });

  let {dragAndDropHooks} = useDragAndDrop({
    getItems: (keys) => [...keys].map(key => {
      let item = list.getItem(key);
      return {
        'custom-app-type': JSON.stringify(item),
        'text/plain': item.name
      };
    }),
    /*- begin highlight -*/
    renderPreview: (keys, draggedKey) => (
      <View backgroundColor="gray-50" padding="size-100" borderRadius="medium" borderWidth="thin" borderColor="blue-500">
        <strong>Custom Preview</strong>
        <div>Keys: [{[...keys].join(', ')}]</div>
        <div>Dragged: {draggedKey}</div>
      </View>
    )
    /*- end highlight -*/
  });

  return (
    <ListView
      aria-label="Draggable ListView with custom drag preview"
      selectionMode="multiple"
      width="size-3600"
      height="size-2400"
      dragAndDropHooks={dragAndDropHooks}
      items={list.items}>
      {item => (
        <Item textValue={item.name}>
          {item.name}
        </Item>
      )}
    </ListView>
  );
}
```

</details>

```tsx example
<CustomDragPreviewExample />
```

## Props

<PropTable component={docs.exports.ListView} links={docs.links} />

## Visual options
### Quiet

```tsx example export=true
function ListExample(props) {
  return (
    <ListView selectionMode="multiple" aria-label="Quiet ListView example" width="size-3000" {...props}>
      <Item>Adobe AfterEffects</Item>
      <Item>Adobe Dreamweaver</Item>
      <Item>Adobe Acrobat</Item>
    </ListView>
  );
}

<ListExample isQuiet />
```

### Density
The amount of vertical padding that each row contains can be modified by providing the `density` prop.

```tsx example
<Flex wrap gap="size-300">
  <ListExample density="compact" aria-label="Compact ListView example" />
  <ListExample density="spacious" aria-label="Spacious ListView example" />
</Flex>
```

### Overflow mode
By default, text content that overflows its row will be truncated. You can have it wrap instead by passing `overflowMode="wrap"`
to the ListView.

```tsx example
<ListExample overflowMode="wrap" aria-label="Text wrapping ListView example" width="size-2000" />
```

### Empty state
Use the `renderEmptyState` prop to customize what the ListView will display if there are no rows provided.

```tsx example
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';
import {Heading} from '@react-spectrum/text';

function renderEmptyState() {
  return (
    <IllustratedMessage>
      <NotFound />
      <Heading>No results</Heading>
      <Content>No results found</Content>
    </IllustratedMessage>
  );
}

<ListView
  selectionMode="multiple"
  aria-label="Example ListView for empty state"
  maxWidth="size-6000"
  height="size-3000"
  renderEmptyState={renderEmptyState}>
  {[]}
</ListView>
```

## Testing

The ListView features automatic virtualization and may need specific mocks in a test environment to enable said virtualization properly.
It also features long press interactions on its rows depending on the row actions provided and if user is interacting with the list on
a touch device. Please see the following sections in the testing docs for more information on how to handle these
behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/list/test/ListView.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common gridlist interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the gridlist tester and a sample of how you could use it in your test suite.

```ts
// ListView.test.ts
import {render, within} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/ListView.html#testing

it('ListView can select a row via keyboard', async function () {
  // Render your test component/app and initialize the gridlist tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <ListView data-testid="test-gridlist" selectionMode="single">
        ...
      </ListView>
    </Provider>
  );
  let gridListTester = testUtilUser.createTester('GridList', {root: getByTestId('test-gridlist'), interactionType: 'keyboard'});

  let row = gridListTester.getRows()[0];
  expect(within(row).getByRole('checkbox')).not.toBeChecked();
  expect(gridListTester.getSelectedRows()).toHaveLength(0);

  await gridListTester.toggleRowSelection({row: 0});
  expect(within(row).getByRole('checkbox')).toBeChecked();
  expect(gridListTester.getSelectedRows()).toHaveLength(1);

  await gridListTester.toggleRowSelection({row: 0});
  expect(within(row).getByRole('checkbox')).not.toBeChecked();
  expect(gridListTester.getSelectedRows()).toHaveLength(0);
});
```

<ClassAPI links={gridlistUtil.links} class={gridlistUtil.exports.GridListTester} />

---

### Packages @Adobe React Spectrum Docs Listbox ListBox (`packages/@adobe/react-spectrum/docs/listbox/ListBox.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/listbox';
import {HeaderInfo, PropTable, PageDescription, ClassAPI, VersionBadge} from '@react-spectrum/docs';
import packageData from '@react-spectrum/listbox/package.json';
import listboxUtils from 'docs:@react-aria/test-utils';

```jsx import
import {ListBox, Section, Item} from '@react-spectrum/listbox';
import {Flex} from '@react-spectrum/layout';
import Book from '@spectrum-icons/workflow/Book';
import BulkEditUsers from '@spectrum-icons/workflow/BulkEditUsers';
import Draw from '@spectrum-icons/workflow/Draw';
import {Text} from '@react-spectrum/text';
import {Avatar} from "@react-spectrum/avatar";
```

---
category: Collections
---

# ListBox

<PageDescription>{docs.exports.ListBox.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ListBox, Item, Section']}
  since="3.0.0" />

## Example

```tsx example
<ListBox width="size-2400" aria-label="Alignment">
  <Item>Left</Item>
  <Item>Middle</Item>
  <Item>Right</Item>
</ListBox>
```

## Content
A ListBox displays a list of options, and allows users to select one or more of them. It follows the [Collection Components](collections.html) API, accepting both static and dynamic collections. Similar to [Picker](Picker.html), ListBox accepts `<Item>` elements as children, each with a `key` prop. Basic usage of the ListBox, seen in the example above, shows multiple options populated with a string. Static collections, as in this example, can be used when the full list of options is known ahead of time.

Dynamic collections, as shown below, can be used when the options come from an external data source such as an API call, or update over time. Providing the data in this way allows for ListBox to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of options is passed to the Listbox using the `items` prop. Each item accepts a key prop, which is passed to the `onSelectionChange` handler, when present, to identify the selected item. Alternatively, if the item objects contain an `id` property, as shown in the example below, then this is used automatically and a `key` prop is not required. See the [Events](#events) section for more detail on selection. By default, selection is not enabled, however this can be changed using the `selectionMode` prop. See [Selection](#selection) for more information.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];
  let [animalId, setAnimalId] = React.useState(null);

  return (
    <>
      <ListBox width="size-2400" aria-label="Animals" items={options} selectionMode="single" onSelectionChange={setAnimalId}>
        {item => <Item>{item.name}</Item>}
      </ListBox>
      <p>Animal id: {animalId}</p>
    </>
  );
}
```
### Accessibility
ListBoxes should be labeled using the `aria-label` prop.  If the ListBox is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

### Internationalization
To internationalize a ListBox, a localized string should be passed to the `children` of each `Item`.
For languages that are read right to left (e.g. Hebrew and Arabic), the layout of the ListBox is flipped.

## Selection
ListBox supports no selection, single and multiple selection modes using the `selectionMode` prop. Setting selected options can be done by using the `defaultSelectedKeys` or `selectedKeys` prop. The selected key corresponds to the `key` of an item. See <a href="#events" title="Events">Events</a> for more details on selection events.
Additionally, see the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let options = [
    {name: 'Koala'},
    {name: 'Kangaroo'},
    {name: 'Platypus'},
    {name: 'Bald Eagle'},
    {name: 'Bison'},
    {name: 'Skunk'}
  ];
  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set(['Bison']));

  return (
    <Flex direction="row" gap="size-350">
      <ListBox
        selectionMode="multiple"
        aria-label="Pick an animal"
        items={options}
        defaultSelectedKeys={['Bison', 'Koala']}
        width="size-2400">
        {item => <Item key={item.name}>{item.name}</Item>}
      </ListBox>

      <ListBox
        selectionMode="multiple"
        aria-label="Pick an animal"
        items={options}
        selectedKeys={selectedKeys}
        onSelectionChange={setSelectedKeys}
        width="size-2400">
        {item => <Item key={item.name}>{item.name}</Item>}
      </ListBox>
    </Flex>
  );
}
```

## Links

By default, interacting with an item in a ListBox triggers `onSelectionChange`. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Link items in a ListBox are not selectable.

```tsx example
<ListBox aria-label="Links">
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</ListBox>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
ListBox supports sections in order to group options. Sections can be used by wrapping groups of Items in a `Section` component. Each `Section` takes a `title` and `key` prop.

### Static Items
```tsx example
<ListBox width="size-2400" aria-label="Pick your favorite" selectionMode="single">
  <Section title="Animals">
    <Item key="Aardvark">Aardvark</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Snake">Snake</Item>
  </Section>
  <Section title="People">
    <Item key="Danni">Danni</Item>
    <Item key="Devon">Devon</Item>
    <Item key="Ross">Ross</Item>
  </Section>
</ListBox>
```
### Dynamic Items
Sections used with dynamic items are populated from a hierarchical data structure. Similarly to the props on `ListBox`, `Section` takes an array of data using the `items` prop.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let options = [
    {name: 'Australian', children: [
      {id: 2, name: 'Koala'},
      {id: 3, name: 'Kangaroo'},
      {id: 4, name: 'Platypus'}
    ]},
    {name: 'American', children: [
      {id: 6, name: 'Bald Eagle'},
      {id: 7, name: 'Bison'},
      {id: 8, name: 'Skunk'}
    ]}
  ];
  let [selected, setSelected] = React.useState<Selection>(new Set());

  return (
    <ListBox
      aria-label="Pick an animal"
      items={options}
      selectedKeys={selected}
      selectionMode="single"
      onSelectionChange={setSelected}
      width="size-2400">
      {item => (
        <Section key={item.name} items={item.children} title={item.name}>
          {item => <Item>{item.name}</Item>}
        </Section>
      )}
    </ListBox>
  );
}
```

## Events
ListBox supports selection via mouse, keyboard, and touch. You can handle all of these via the `onSelectionChange`
prop. ListBox will pass the selected `key` to the `onSelectionChange` handler.

The following example uses an `onSelectionChange` handler to update the selection stored in React state.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function StaticExample() {
  let [frequency, setFrequency] = React.useState<Selection>(new Set());

  return (
    <>
      <ListBox
        aria-label="Choose frequency"
        selectionMode="single"
        onSelectionChange={selected => setFrequency(selected)}
        width="size-2400">
        <Item key="Rarely">Rarely</Item>
        <Item key="Sometimes">Sometimes</Item>
        <Item key="Always">Always</Item>
      </ListBox>
      <p>You selected: {[...frequency][0]}</p>
    </>
  );
}
```

When using ListBox with dynamic items, selection works much the same way using `key`. However, if your data already has an `id` property (as is common with many data sets), ListBox can use that id without needing to specify a `key` prop. The below example shows ListBox using the id of each item from the `items` array as the selected value without the need for `key`. Note that `key` will always take precedence if set.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function DynamicExample() {
  let [animalId, setAnimalId] = React.useState<Selection>(new Set());
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];

  return (
    <>
      <ListBox
        selectionMode="single"
        aria-label="Pick an animal"
        items={options}
        onSelectionChange={selected => setAnimalId(selected)}
        width="size-2400">
        {item => <Item>{item.name}</Item>}
      </ListBox>
      <p>Your favorite animal has id: {[...animalId][0]}</p>
    </>
  );
}
```

## Complex Items
Items within ListBox also allow for additional content used to better communicate options. Icons, avatars, and descriptions can be added to the `children` of `Item` as shown in the example below.
If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
See Icon's [labeling](workflow-icons.html#labeling) section and Avatar's [accessibility](Avatar.html#accessibility) section for more information on how to label these elements.

```tsx example
<ListBox width="size-2400" aria-label="Options" selectionMode="single">
  <Section title="Permission">
    <Item textValue="Read">
      <Book size="S" />
      <Text>Read</Text>
      <Text slot="description">Read Only</Text>
    </Item>
    <Item textValue="Write">
      <Draw size="S" />
      <Text>Write</Text>
      <Text slot="description">Read and Write Only</Text>
    </Item>
    <Item textValue="Admin">
      <BulkEditUsers size="S" />
      <Text>Admin</Text>
      <Text slot="description">Full access</Text>
    </Item>
  </Section>
</ListBox>
```

### With avatars

```tsx example
<ListBox width="size-2400" aria-label="Options" selectionMode="single">
  <Section title="Users">
    <Item textValue="User 1">
      <Avatar src="https://i.imgur.com/kJOwAdv.png" />
      <Text>User 1</Text>
    </Item>
    <Item textValue="User 2">
      <Avatar src="https://i.imgur.com/kJOwAdv.png" />
      <Text>User 2</Text>
    </Item>
    <Item textValue="User 3">
      <Avatar src="https://i.imgur.com/kJOwAdv.png" />
      <Text>User 3</Text>
    </Item>
    <Item textValue="User 4">
      <Avatar src="https://i.imgur.com/kJOwAdv.png" />
      <Text>User 4</Text>
    </Item>
  </Section>
</ListBox>
```

## Asynchronous loading

ListBox supports loading data asynchronously, and will display a progress circle when the `isLoading` prop is set.
It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data.
See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Pokemon {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Pokemon>({
    async load({signal, cursor}) {
      // If no cursor is available, then we're loading the first page.
      // Otherwise, the cursor is the next URL to load, as returned from the previous page.
      let res = await fetch(cursor || 'https://pokeapi.co/api/v2/pokemon', {signal});
      let json = await res.json();
      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <Flex maxHeight="size-2400">
      <ListBox
        aria-label="Pick a Pokemon"
        items={list.items}
        isLoading={list.isLoading}
        onLoadMore={list.loadMore}
        width="size-2400">
        {item => <Item key={item.name}>{item.name}</Item>}
      </ListBox>
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.ListBox} links={docs.links} />

## Visual options
### Loading

```tsx example
<ListBox
  isLoading
  aria-label="Choose frequency"
  selectionMode="single"
  width="size-1200">
  {[]}
</ListBox>
```

### Disabled
Use the `disabledKeys` prop to specify which item keys to disable in the ListBox.

```tsx example
<ListBox width="size-2400" aria-label="Pick your favorite" disabledKeys={["Snake", "Ross"]} selectionMode="single">
  <Section title="Animals">
    <Item key="Aardvark">Aardvark</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Snake">Snake</Item>
  </Section>
  <Section title="People">
    <Item key="Danni">Danni</Item>
    <Item key="Devon">Devon</Item>
    <Item key="Ross">Ross</Item>
  </Section>
</ListBox>
```

## Testing

The ListBox features automatic virtualization and may need specific mocks in a test environment to enable said virtualization properly.
Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Virtualized Components](./testing.html#virtualized-components)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/listbox/test/ListBox.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common listbox interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the listbox tester and a sample of how you could use it in your test suite.

```ts
// ListBox.test.ts
import {render} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/ListBox.html#testing

it('ListBox can select an option via keyboard', async function () {
  // Render your test component/app and initialize the listbox tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <ListBox selectionMode="single" data-testid="test-listbox">
        ...
      </ListBox>
    </Provider>
  );
  let listboxTester = testUtilUser.createTester('ListBox', {root: getByTestId('test-listbox'), interactionType: 'keyboard'});

  await listboxTester.toggleOptionSelection({option: 4});
  expect(listboxTester.getOptions()[4]).toHaveAttribute('aria-selected', 'true');
});
```

<ClassAPI links={listboxUtils.links} class={listboxUtils.exports.ListBoxTester} />

---

### Packages @Adobe React Spectrum Docs Menu ActionMenu (`packages/@adobe/react-spectrum/docs/menu/ActionMenu.mdx`)

{/* Copyright 2022 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/menu';
import {HeaderInfo, PropTable} from '@react-spectrum/docs';
import packageData from '@react-spectrum/menu/package.json';

```jsx import
import {ActionMenu, Item, Section} from '@react-spectrum/menu';
import Copy from '@spectrum-icons/workflow/Copy';
import Cut from '@spectrum-icons/workflow/Cut';
import {Flex} from '@react-spectrum/layout';
import Paste from '@spectrum-icons/workflow/Paste';
```

---
category: Collections
keywords: [action menu, dropdown]
---

# ActionMenu

<p>{docs.exports.ActionMenu.description}</p>

<HeaderInfo
  packageData={packageData}
  componentNames={['ActionMenu']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/popover/'}
  ]}
  since="3.18.0" />

## Example

```tsx example
<ActionMenu>
  <Item>Cut</Item>
  <Item>Copy</Item>
  <Item>Paste</Item>
</ActionMenu>
```

## Content

ActionMenu follows the [Collection Components](collections.html) API,
accepting both static and dynamic collections. See [Menu](Menu.html#content) for further explanation.

```tsx example
function Example() {
  let actionMenuItems = [
    {name: 'Cut'},
    {name: 'Copy'},
    {name: 'Paste'},
    {name: 'Select All'}
  ];

  return (
    <ActionMenu items={actionMenuItems}>
      {item => <Item key={item.name}>{item.name}</Item>}
    </ActionMenu>
  );
}
```

### Trays
On mobile, ActionMenus automatically display in a tray instead of a popover to improve usability.

### Internationalization
In order to internationalize an ActionMenu, the content provided to all child items should be localized.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the ActionMenu is flipped.

## Events
ActionMenu supports the `onAction` prop, which is called when the user presses a menu item. It receives the key of the item as an argument, which can be used to perform the relevant action.

```tsx example
function Example() {
  let [action, setAction] = React.useState(null);

  return (
    <>
      <ActionMenu onAction={setAction}>
        <Item key="cut">Cut</Item>
        <Item key="copy">Copy</Item>
        <Item key="paste">Paste</Item>
      </ActionMenu>
      <p>Action: {action}</p>
    </>
  );
}
```

## Links

By default, interacting with an item in an ActionMenu triggers `onAction`. Items may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component.

```tsx example
<ActionMenu>
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</ActionMenu>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
ActionMenu supports sections in order to group options. Sections can be used by wrapping groups of Items in a `Section` component. Each `Section` takes a `title` and `key` prop.

### Static Items

```tsx example
<ActionMenu>
  <Section title="File">
    <Item key="new">New</Item>
    <Item key="open">Open...</Item>
  </Section>
  <Section title="Save">
    <Item key="save">Save</Item>
    <Item key="saveAs">Save As...</Item>
    <Item key="saveAll">Save All</Item>
  </Section>
</ActionMenu>
```

### Dynamic Items

Sections used with dynamic items are populated from a hierarchical data structure. Similarly to the props on ActionMenu, `<Section>` takes an array of data using the `items` prop.

```tsx example
function Example() {
  let openWindows = [
    {
      name: 'Reversion',
      id: 'reversion',
      children: [
        {id: 'undo', name: 'Undo'},
        {id: 'redo', name: 'Redo'}
      ]
    },
    {
      name: 'Clipboard',
      id: 'clipboard',
      children: [
        {id: 'cut', name: 'Cut'},
        {id: 'copy', name: 'Copy'},
        {id: 'paste', name: 'Paste'}
      ]
    }
  ];

  return (
    <ActionMenu
      items={openWindows}>
      {item => (
        <Section items={item.children} title={item.name}>
          {item => <Item>{item.name}</Item>}
        </Section>
      )}
    </ActionMenu>
  );
}
```

### Accessibility

Sections without a `title` must provide an `aria-label` for accessibility.

## Complex Menu Items

Items within ActionMenu also allow for additional content used to better communicate options. Icons and descriptions can be added to the `children` of `Item` as shown in the example below. If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.

```tsx example
import {Keyboard, Text} from '@react-spectrum/text';
<ActionMenu>
  <Item key="cut" textValue="cut">
    <Cut />
    <Text>Cut</Text>
    <Keyboard>⌘X</Keyboard>
  </Item>
  <Item key="copy" textValue="copy">
    <Copy />
    <Text>Copy</Text>
    <Keyboard>⌘C</Keyboard>
  </Item>
  <Item key="paste" textValue="paste">
    <Paste />
    <Text>Paste</Text>
    <Keyboard>⌘V</Keyboard>
  </Item>
</ActionMenu>
```

## Props

<PropTable component={docs.exports.ActionMenu} links={docs.links} />

## Visual options

### Quiet

[View guidelines](https://spectrum.adobe.com/page/action-button/#Quiet)

```tsx example
<ActionMenu
  isQuiet
  items={[
    {name: 'Cut', id: 'cut'},
    {name: 'Copy', id: 'copy'},
    {name: 'Paste', id: 'paste'}
  ]}>
  {item => <Item>{item.name}</Item>}
</ActionMenu>
```

### Autofocus

Applying `autoFocus` to the ActionMenu sets focus to the ActionMenu trigger.

### Disabled

```tsx example
<ActionMenu
  items={[
    {name: 'Undo', id: 'undo'},
    {name: 'Redo', id: 'redo'},
    {name: 'Cut', id: 'cut'},
    {name: 'Copy', id: 'copy'},
    {name: 'Paste', id: 'paste'}
  ]}
  isDisabled>
  {item => <Item>{item.name}</Item>}
</ActionMenu>
```

### Disabled items

```tsx example
<ActionMenu
  items={[
    {name: 'Undo', id: 'undo'},
    {name: 'Redo', id: 'redo'},
    {name: 'Cut', id: 'cut'},
    {name: 'Copy', id: 'copy'},
    {name: 'Paste', id: 'paste'}
  ]}
  disabledKeys={['redo', 'paste']}>
  {item => <Item>{item.name}</Item>}
</ActionMenu>
```

### Align and direction

[View guidelines](https://spectrum.adobe.com/page/popover/#Placement)

The `align` prop aligns the ActionMenu menu relative to the trigger and the `direction` prop controls the direction the ActionMenu will render.

```tsx example
<Flex gap="size-100">
  <ActionMenu align="start">
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
  <ActionMenu align="end" direction="top" shouldFlip={false}>
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
  <ActionMenu direction="start" align="start">
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
  <ActionMenu direction="end" align="end">
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
</Flex>
```

### Flipping
By default, the ActionMenu menu flips direction automatically upon opening when space is limited. To change this, set the `shouldFlip` prop to `false`. Try scrolling the viewport close to the edge of the trigger in the example to see this in action.

```tsx example
<Flex gap="size-100">
  <ActionMenu shouldFlip>
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
  <ActionMenu shouldFlip={false}>
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
  </ActionMenu>
</Flex>
```

### Open

The `isOpen` and `defaultOpen` props on the ActionMenu control whether the menu is open by default.
They apply controlled and uncontrolled behavior on the Menu respectively.

```tsx example
function Example() {
  let [open, setOpen] = React.useState(false);

  return (
    <ActionMenu
      isOpen={open}
      onOpenChange={setOpen}>
      <Item key="cut">Cut</Item>
      <Item key="copy">Copy</Item>
      <Item key="paste">Paste</Item>
    </ActionMenu>
  );
}
```

## Testing

The ActionMenu features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your configuration, this overlay may render as a tray or a dropdown. Please see the following sections in the
testing docs for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/menu/test/ActionMenu.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Menu Menu (`packages/@adobe/react-spectrum/docs/menu/Menu.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import contextualHelpTriggerTypes from 'docs:@react-spectrum/menu';
import submenuTriggerTypes from 'docs:@react-spectrum/menu';
import docs from 'docs:@react-spectrum/menu';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/menu/package.json';
import {Keyboard} from '@react-spectrum/text';

```jsx import
import {ActionButton} from '@react-spectrum/button'
import Copy from '@spectrum-icons/workflow/Copy';
import Cut from '@spectrum-icons/workflow/Cut';
import {Item, Menu, MenuTrigger, Section} from '@react-spectrum/menu';
import Paste from '@spectrum-icons/workflow/Paste';
```

---
category: Collections
keywords: [menu trigger, dropdown, action menu]
---

# Menu

<PageDescription>{docs.exports.Menu.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Menu', 'MenuTrigger', 'ContextualHelpTrigger']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/menu/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<MenuTrigger>
  <ActionButton>
    Edit
  </ActionButton>
  <Menu onAction={(key) => alert(key)}>
    <Item key="cut">Cut</Item>
    <Item key="copy">Copy</Item>
    <Item key="paste">Paste</Item>
    <Item key="replace">Replace</Item>
  </Menu>
</MenuTrigger>
```

## Content

Menu follows the [Collection Components](collections.html) API, accepting both static and dynamic collections. Similar to [Picker](Picker.html), Menu accepts `<Item>` elements as children, each with a `key` prop. Basic usage of Menu, seen in the example above, shows multiple items populated with a string. Static collections, as in this example, can be used when the full list of items is known ahead of time.

Dynamic collections, as shown below, can be used when the items come from an external data source such as an API call, or update over time. Providing the data in this way allows for Menu to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of items is passed to the Menu using the `items` prop. Each item accepts a `key` prop, which is passed to the event handler to identify the selected item. Alternatively, if the item objects contain an id property, this is then used automatically and a key prop is not required. See the [Events](#events) section for more detail on selection and actions.

```tsx example
function Example() {
  let menuItems = [
    {name: 'Cut'},
    {name: 'Copy'},
    {name: 'Paste'},
    {name: 'Replace'}
  ];

  return (
    <MenuTrigger>
      <ActionButton>
        Edit
      </ActionButton>
      <Menu items={menuItems}>
        {item => <Item key={item.name}>{item.name}</Item>}
      </Menu>
    </MenuTrigger>
  );
}
```

### Trays
On mobile, Menus automatically display in a tray instead of a popover to improve usability.

### Internationalization
In order to internationalize a Menu, the content provided to all child items should be localized.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the Menu is flipped.

## Events
Use the `onSelectionChange` prop as a callback to handle press events on items when selectionMode is either single or multiple. See [Selection](#selection) for more information.

Menu also supports the `onAction` callback when `selectionMode` is `none` (default).

```tsx example
function Example() {
  let [action, setAction] = React.useState(null);

  return (
    <>
      <MenuTrigger>
        <ActionButton>
          Edit
        </ActionButton>
        <Menu onAction={setAction}>
          <Item key="cut">Cut</Item>
          <Item key="copy">Copy</Item>
          <Item key="paste">Paste</Item>
        </Menu>
      </MenuTrigger>
      <p>Action: {action}</p>
    </>
  );
}
```

## Selection
Menu supports multiple selection modes. By default, selection is disabled, however this can be changed using the `selectionMode` prop.
Use `defaultSelectedKeys` to provide a default set of selected items (uncontrolled) and `selectedKeys` to set the selected items (controlled). The value of the selected keys must match the `key` prop of the items.
See the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set(['middle']));

  return (
    <>
      <MenuTrigger>
        <ActionButton>
          Align
        </ActionButton>
        <Menu selectionMode="single" selectedKeys={selected} onSelectionChange={setSelected}>
          <Item key="left">Left</Item>
          <Item key="middle">Middle</Item>
          <Item key="right">Right</Item>
        </Menu>
      </MenuTrigger>
      <p>Current selection (controlled): {[...selected]}</p>
    </>
  );
}
```

Set `selectionMode` prop to `multiple` to allow more than one selection.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set(['Sidebar', 'Console']));

  return (
    <>
      <MenuTrigger closeOnSelect={false}>
        <ActionButton>
          Show
        </ActionButton>
        <Menu selectionMode="multiple" selectedKeys={selected} onSelectionChange={setSelected}>
          <Item key='Sidebar'>Sidebar</Item>
          <Item key='Searchbar'>Searchbar</Item>
          <Item key='Tools'>Tools</Item>
          <Item key='Console'>Console</Item>
        </Menu>
      </MenuTrigger>
      <p>Current selection (controlled): {selected === 'all' ? 'all' : [...selected].join(', ')}</p>
    </>
  );
}
```

## Links

By default, interacting with an item in a Menu triggers `onAction` and optionally `onSelectionChange` depending on the `selectionMode`. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Link items in a menu are not selectable.

```tsx example
<MenuTrigger>
  <ActionButton>Links</ActionButton>
  <Menu>
    <Item href="https://adobe.com/" target="_blank">Adobe</Item>
    <Item href="https://apple.com/" target="_blank">Apple</Item>
    <Item href="https://google.com/" target="_blank">Google</Item>
    <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
  </Menu>
</MenuTrigger>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
Menu supports sections in order to group options. Sections can be used by wrapping groups of Items in a `Section` component. Each `Section` takes a `title` and `key` prop.

### Static Items

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set(['bold', 'left']));

  return (
    <MenuTrigger>
      <ActionButton>
        Edit
      </ActionButton>
      <Menu selectionMode="multiple" selectedKeys={selected} onSelectionChange={setSelected}>
        <Section title="Styles">
          <Item key="bold">Bold</Item>
          <Item key="underline">Underline</Item>
        </Section>
        <Section title="Align">
          <Item key="left">Left</Item>
          <Item key="middle">Middle</Item>
          <Item key="right">Right</Item>
        </Section>
      </Menu>
    </MenuTrigger>
  );
}
```

### Dynamic Items

Sections used with dynamic items are populated from a hierarchical data structure. Similarly to the props on Menu, `<Section>` takes an array of data using the `items` prop.

```tsx example
import type {Selection} from '@adobe/react-spectrum';

function Example() {
  let [selected, setSelected] = React.useState<Selection>(new Set([1,3]));
  let openWindows = [
    {
      name: 'Left Panel',
      id: 'left',
      children: [
        {id: 1, name: 'Final Copy (1)'}
      ]
    },
    {
      name: 'Right Panel',
      id: 'right',
      children: [
        {id: 2, name: 'index.ts'},
        {id: 3, name: 'package.json'},
        {id: 4, name: 'license.txt'}
      ]
    }
  ];

  return (
    <MenuTrigger>
      <ActionButton>
        Window
      </ActionButton>
      <Menu
        items={openWindows}
        selectionMode="multiple"
        selectedKeys={selected}
        onSelectionChange={setSelected}>
        {item => (
          <Section items={item.children} title={item.name}>
            {item => <Item>{item.name}</Item>}
          </Section>
        )}
      </Menu>
    </MenuTrigger>
  );
}
```

### Accessibility

Sections without a `title` must provide an `aria-label` for accessibility.

## Complex Menu Items

Items within Menu also allow for additional content used to better communicate options. Icons and descriptions can be added to the `children` of `Item` as shown in the example below. If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.

```tsx example
import {Keyboard, Text} from '@react-spectrum/text';
<MenuTrigger>
  <ActionButton>
    Edit
  </ActionButton>
  <Menu>
    <Item key="cut" textValue="cut">
      <Cut />
      <Text>Cut</Text>
      <Keyboard>⌘X</Keyboard>
    </Item>
    <Item key="copy" textValue="copy">
      <Copy />
      <Text>Copy</Text>
      <Keyboard>⌘C</Keyboard>
    </Item>
    <Item key="paste" textValue="paste">
      <Paste />
      <Text>Paste</Text>
      <Keyboard>⌘V</Keyboard>
    </Item>
  </Menu>
</MenuTrigger>
```

## Unavailable Items

ContextualHelpTrigger disables a menu item's action and replaces it with a popover with information on why the item is unavailable and may link users to more information elsewhere.

The ContextualHelpTrigger accepts exactly
two children: the `Item` which triggers opening of the Dialog and the Dialog itself. The trigger must be
the first child passed into the ContextualHelpTrigger and should be an `Item`. Similar to
ContextualHelp, the layout of the Dialog is very deliberate. See [ContextualHelp](ContextualHelp.html#content) for further explanation.

By default, a ContextualHelpTrigger's Dialog is opened by hovering, pressing the trigger element or activating
it via the <Keyboard>Space</Keyboard>, <Keyboard>Enter</Keyboard>, or <Keyboard>Right Arrow</Keyboard> keys.
Hovering another item or pressing the <Keyboard>Esc</Keyboard> key will close the Dialog and leave the Menu open.

Setting the `isUnavailable` prop on the ContextualHelpTrigger makes the menu item unavailable and enables the Dialog with contextual help, allowing for programmatic control.

Note that the Menu's `onAction` and `onSelectionChange`
callbacks will not fire for items made unavailable by a ContextualHelpTrigger.

The example below illustrates how one would setup a Menu to use ContextualHelpTrigger.

```tsx example keepIndividualImports
import {Content, Dialog, Heading} from '@adobe/react-spectrum';
import {ContextualHelpTrigger} from '@react-spectrum/menu';

<MenuTrigger>
  <ActionButton>Edit</ActionButton>
  <Menu>
    <Item key="undo">Undo</Item>
    <Item key="redo">Redo</Item>
    <ContextualHelpTrigger isUnavailable>
      <Item key="cut">Cut</Item>
      <Dialog>
        <Heading>Cut</Heading>
        <Content>Please select text for 'Cut' to be enabled.</Content>
      </Dialog>
    </ContextualHelpTrigger>
    <ContextualHelpTrigger isUnavailable>
      <Item key="copy">Copy</Item>
      <Dialog>
        <Heading>Copy</Heading>
        <Content>Please select text for 'Copy' to be enabled.</Content>
      </Dialog>
    </ContextualHelpTrigger>
    <ContextualHelpTrigger>
      <Item key="paste">Paste</Item>
      <Dialog>
        <Heading>Paste</Heading>
        <Content>You have nothing to 'Paste'.</Content>
      </Dialog>
    </ContextualHelpTrigger>
  </Menu>
</MenuTrigger>
```

## Submenus

Submenus can be created by wrapping an item and a menu in a `SubmenuTrigger`. The `SubmenuTrigger` accepts exactly two children: the `Item` which triggers opening of the submenu, and the `Menu` itself.
Each submenu's Menu accepts its own set of menu props, allowing you to customize its user action and selection behavior.

### Static

```tsx example keepIndividualImports

import {SubmenuTrigger} from '@react-spectrum/menu';

<MenuTrigger>
  <ActionButton>Actions</ActionButton>
  <Menu onAction={(key) => alert(`Root menu ${key} action`)}>
    <Item key="Copy">Copy</Item>
    <Item key="Cut">Cut</Item>
    <Item key="Paste">Paste</Item>
      <SubmenuTrigger>
        <Item key="Share">Share</Item>
        <Menu onAction={(key) => alert(`Share menu ${key} action`)}>
          <Item key="Copy Link">Copy Link</Item>
          <SubmenuTrigger>
            <Item key="Email">Email</Item>
            <Menu onAction={(key) => alert(`Email menu ${key} action`)}>
              <Item key="Attachment">Email as Attachment</Item>
              <Item key="Link">Email as Link</Item>
            </Menu>
          </SubmenuTrigger>
          <Item key="SMS">SMS</Item>
        </Menu>
      </SubmenuTrigger>
    <Item key="Delete">Delete</Item>
  </Menu>
</MenuTrigger>
```

### Dynamic

You can define a recursive function to render the nested menu items dynamically.

```tsx example keepIndividualImports
import {SubmenuTrigger} from '@react-spectrum/menu';

let items = [
  {name: 'Copy'},
  {name: 'Cut'},
  {name: 'Paste'},
  {name: 'Share', children: [
    {name: 'Copy Link'},
    {name: 'Email', children: [
      {name: 'Email as Attachment'},
      {name: 'Email as Link'},
    ]},
    {name: 'SMS'},
  ]},
  {name: 'Delete'}
];

<MenuTrigger>
  <ActionButton>Actions</ActionButton>
  <Menu items={items}>
    {function renderSubmenu(item) {
      if (item.children) {
        return (
          <SubmenuTrigger>
            <Item key={item.name}>{item.name}</Item>
            <Menu items={item.children}>
              {(item) => renderSubmenu(item)}
            </Menu>
          </SubmenuTrigger>
        );
      } else {
        return <Item key={item.name}>{item.name}</Item>;
      }
    }}
  </Menu>
</MenuTrigger>
```

## Props

### Menu props

<PropTable component={docs.exports.Menu} links={docs.links} />

### ContextualHelpTrigger Props
<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(docs.exports.SpectrumMenuDialogTriggerProps.properties))
  }
}} links={contextualHelpTriggerTypes.links} />

### SubmenuTrigger Props
<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(docs.exports.SpectrumSubmenuTriggerProps.properties))
  }
}} links={submenuTriggerTypes.links} />

## Visual Options

### Autofocus

Applying `autoFocus` to the Menu of the MenuTrigger sets focus to a Menu Item
within the Menu upon opening.

### Disabled

```tsx example
<MenuTrigger>
  <ActionButton>
    Filter
  </ActionButton>
  <Menu
    items={[
      {name: 'tiff', id: 'a1b2c3'},
      {name: 'png', id: 'g5h1j9'},
      {name: 'jpg', id: 'p8k3i4'},
      {name: 'PDF', id: 'j7i3a0'}
    ]}
    disabledKeys={['a1b2c3', 'p8k3i4']}>
    {item => <Item>{item.name}</Item>}
  </Menu>
</MenuTrigger>
```

---

### Packages @Adobe React Spectrum Docs Menu MenuTrigger (`packages/@adobe/react-spectrum/docs/menu/MenuTrigger.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/menu';
import menuUtil from 'docs:@react-aria/test-utils';
import {HeaderInfo, PropTable, PageDescription, ClassAPI, VersionBadge} from '@react-spectrum/docs';
import packageData from '@react-spectrum/menu/package.json';
import {Keyboard} from '@react-spectrum/text';

```jsx import
import {ActionButton} from '@react-spectrum/button'
import {Item, Menu, MenuTrigger} from '@react-spectrum/menu';
import {Flex} from '@react-spectrum/layout';
```

---
category: Collections
keywords: [menu, dropdown, action menu]
---

# MenuTrigger

<PageDescription>{docs.exports.MenuTrigger.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['MenuTrigger', 'Menu']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/popover/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<MenuTrigger>
  <ActionButton>
    Edit
  </ActionButton>
  <Menu>
    <Item>Cut</Item>
    <Item>Copy</Item>
    <Item>Paste</Item>
  </Menu>
</MenuTrigger>
```

## Content

The MenuTrigger accepts exactly two children: the element which triggers the opening of the Menu and the Menu itself. The trigger element must be the first child passed into the MenuTrigger and should support press events.

## Events

MenuTrigger accepts an `onOpenChange` handler which is triggered whenever the Menu is opened or closed.

```tsx example
function Example() {
  let [isOpen, setIsOpen] = React.useState(false);

  return (
    <Flex gap="size-100" alignItems="center">
      <MenuTrigger onOpenChange={setIsOpen}>
        <ActionButton>
            Edit
        </ActionButton>
        <Menu>
          <Item key="cut">Cut</Item>
          <Item key="copy">Copy</Item>
          <Item key="paste">Paste</Item>
        </Menu>
      </MenuTrigger>
      <div>Currently open: {isOpen.toString()}</div>
    </Flex>
  );
}
```

## Long press
By default, a MenuTrigger's Menu is opened by pressing the trigger element or activating it via the <Keyboard>Space</Keyboard> or <Keyboard>Enter</Keyboard> keys. However, there may be cases in which your trigger element
should perform a separate default action on press such as selection, and should only display the Menu when long pressed. This behavior can be changed by providing `"longPress"` to the `trigger` prop. With this prop, the Menu will only be opened upon
pressing and holding the trigger element or by using the <Keyboard>Option</Keyboard> (<Keyboard>Alt</Keyboard> on Windows) + <Keyboard>Down Arrow</Keyboard>/<Keyboard>Up Arrow</Keyboard> keys while focusing the trigger element.

The example below illustrates how one would setup a MenuTrigger to have long press behavior.

```tsx example
import CloneStamp from '@spectrum-icons/workflow/CloneStamp';
import Crop from '@spectrum-icons/workflow/Crop';
import CropRotate from '@spectrum-icons/workflow/CropRotate';
import Slice from '@spectrum-icons/workflow/Slice';
import {Text} from '@react-spectrum/text';

<MenuTrigger trigger="longPress">
  <ActionButton
    aria-label="Crop tool"
    onPress={() => alert('Cropping!')}>
    <Crop />
  </ActionButton>
  <Menu>
    <Item textValue="Crop Rotate">
      <CropRotate />
      <Text>Crop Rotate</Text>
    </Item>
    <Item textValue="Slice">
      <Slice />
      <Text>Slice</Text>
    </Item>
    <Item textValue="Clone stamp">
      <CloneStamp />
      <Text>Clone Stamp</Text>
    </Item>
  </Menu>
</MenuTrigger>
```

## Props

<PropTable component={docs.exports.MenuTrigger} links={docs.links} />

## Visual options

### Align and direction

[View guidelines](https://spectrum.adobe.com/page/popover/#Placement)

The `align` prop aligns the Menu relative to the trigger and the `direction` prop controls the direction the Menu will render.

```tsx example
<Flex gap="size-100">
  <MenuTrigger align="start">
    <ActionButton>Edit</ActionButton>
    <Menu>
      <Item key="cut">Cut</Item>
      <Item key="copy">Copy</Item>
      <Item key="paste">Paste</Item>
    </Menu>
  </MenuTrigger>
  <MenuTrigger align="end" direction="top" shouldFlip={false}>
    <ActionButton>View</ActionButton>
    <Menu>
      <Item key="side">Side bar</Item>
      <Item key="options">Page options</Item>
      <Item key="edit">Edit Panel</Item>
    </Menu>
  </MenuTrigger>
  <MenuTrigger direction="start" align="start">
    <ActionButton>Edit</ActionButton>
    <Menu>
      <Item key="cut">Cut</Item>
      <Item key="copy">Copy</Item>
      <Item key="paste">Paste</Item>
    </Menu>
  </MenuTrigger>
  <MenuTrigger direction="end" align="end">
    <ActionButton>View</ActionButton>
    <Menu>
      <Item key="side">Side bar</Item>
      <Item key="options">Page options</Item>
      <Item key="edit">Edit Panel</Item>
    </Menu>
  </MenuTrigger>
</Flex>
```


### Close on selection

By default, the Menu closes when an item is selected. To change this, set the `closeOnSelect` prop to `false`. This might be useful when multiple selection is used. See [menu selection](./Menu.html#selection) for more information.

```tsx example
<MenuTrigger closeOnSelect={false}>
  <ActionButton>
    View
  </ActionButton>
  <Menu selectionMode="multiple">
    <Item key="side">Side bar</Item>
    <Item key="options">Page options</Item>
    <Item key="edit">Edit Panel</Item>
  </Menu>
</MenuTrigger>
```

### Flipping
By default, the Menu flips direction automatically upon opening when space is limited. To change this, set the `shouldFlip` prop to `false`. Try scrolling the viewport close to the edge of the trigger in the example to see this in action.

```tsx example
<Flex gap="size-100">
  <MenuTrigger shouldFlip>
    <ActionButton>
      View
    </ActionButton>
    <Menu>
      <Item key="side">Side bar</Item>
      <Item key="options">Page options</Item>
      <Item key="edit">Edit Panel</Item>
    </Menu>
  </MenuTrigger>
  <MenuTrigger shouldFlip={false}>
    <ActionButton>
      Edit
    </ActionButton>
    <Menu>
      <Item key="cut">Cut</Item>
      <Item key="copy">Copy</Item>
      <Item key="paste">Paste</Item>
    </Menu>
  </MenuTrigger>
</Flex>
```

### Open

The `isOpen` and `defaultOpen` props on the MenuTrigger control whether the Menu is open by default.
They apply controlled and uncontrolled behavior on the Menu respectively.

```tsx example
function Example() {
  let [open, setOpen] = React.useState(false);

  return (
    <MenuTrigger
      isOpen={open}
      onOpenChange={setOpen}>
      <ActionButton>
        View
      </ActionButton>
      <Menu selectionMode="multiple">
        <Item key="side">Side bar</Item>
        <Item key="options">Page options</Item>
        <Item key="edit">Edit Panel</Item>
      </Menu>
    </MenuTrigger>
  );
}
```

## Testing

The Menu features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your configuration, this overlay may render as a tray or a dropdown and may feature long press interactions on the
trigger itself. Please see the following sections in the testing docs for more information on how to handle these
behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/menu/test/MenuTrigger.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common menu interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the menu tester and a sample of how you could use it in your test suite.

```ts
// Menu.test.ts
import {render} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/MenuTrigger.html#testing

it('Menu can open its submenu via keyboard', async function () {
  // Render your test component/app and initialize the menu tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <MenuTrigger>
        <Button data-testid="test-menutrigger">Menu trigger</Button>
        ...
      </MenuTrigger>
    </Provider>
  );
  let menuTester = testUtilUser.createTester('Menu', {root: getByTestId('test-menutrigger'), interactionType: 'keyboard'});

  await menuTester.open();
  expect(menuTester.getMenu()).toBeInTheDocument();
  let submenuTriggers = menuTester.getSubmenuTriggers();
  expect(submenuTriggers).toHaveLength(1);

  let submenuTester = await menuTester.openSubmenu({submenuTrigger: 'Share…'});
  expect(submenuTester.getMenu()).toBeInTheDocument();

  await submenuTester.toggleOptionSelection({option: submenuTester.getOptions()[0]});
  expect(submenuTester.getMenu()).not.toBeInTheDocument();
  expect(menuTester.getMenu()).not.toBeInTheDocument();
});
```

<ClassAPI links={menuUtil.links} class={menuUtil.exports.MenuTester} />

---

### Packages @Adobe React Spectrum Docs Meter Meter (`packages/@adobe/react-spectrum/docs/meter/Meter.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/meter';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/meter/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Meter} from '@react-spectrum/meter';
```

---
category: Status
---

# Meter

<PageDescription>{docs.exports.Meter.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Meter']}
  sourceData={[{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/meter/'}]}
  since="3.0.0" />

## Example

```tsx example
<Meter label="Storage space" value={35} />
```

## Value

Meters are controlled with the `value` prop.
By default, the `value` prop represents the current percentage of progress, as the minimum and maximum values default to 0 and 100, respectively.

```tsx example
<Meter
  label="Storage space"
  value={25} />
```

Alternatively, a different scale can be used by setting the `minValue` and `maxValue` props.

```tsx example
<Meter
  label="Widgets Used"
  minValue={50}
  maxValue={150}
  value={100} />
```

Values are formatted as a percentage by default, but this can be modified by using the `formatOptions` prop to specify a different format.
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.

```tsx example
<Meter
  label="Currency"
  formatOptions={{style: 'currency', currency: 'JPY'}}
  value={60} />
```

## Labeling
Value labels are shown above the Meter by default, but they can also be moved to the side or hidden as needed.
The label text should be in sentence case.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <Meter label="Label" value={25} variant="warning" />
  <Meter label="Label" labelPosition="side" value={25} variant="warning" />
  <Meter label="Label" showValueLabel={false} value={25} variant="warning" />
</Flex>
```

The value label can be updated via the `valueLabel` prop in cases where showing a different scale makes sense.
```tsx example
<Meter label="Progress" marginBottom="size-300" value={25} valueLabel="1 of 4" variant="warning" />
```

By default, the value label is formatted as a percentage. This can be customized using the following props.

* `showValueLabel`: Allows you to display or hide the value label.
* `formatOptions`: Allows you to customize the format of the value.
* `valueLabel`: Allows you to customize the value label to any string.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <Meter
    label="Space used"
    showValueLabel={false}
    value={90}
    variant="critical" />

  <Meter
    label="Space used"
    valueLabel="54 of 60GB"
    value={90} variant="critical" />

  <Meter
    label="Space used"
    formatOptions={{style: 'percent', minimumFractionDigits: 2}}
    value={89.123}
    variant="critical" />
</Flex>
```

### Accessibility

Depending on the visualization being used (i.e. depending on the `showValueLabel` prop), a `label`, `aria-label`, or `aria-labelledby` prop is required.

### Internationalization

To internationalize a Meter, a localized string should be passed to the `label` prop, `aria-label` prop, or value of the associated `aria-labelledby` element.

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the meter is automatically flipped. In addition,
Meter automatically uses the current locale to format the value label.

## Props

<PropTable component={docs.exports.Meter} links={docs.links} />

## Visual options

### Size
[View guidelines](https://spectrum.adobe.com/page/meter/#Size)

```tsx example
<Flex direction="column" gap="size-300">
  <Meter label="Space used" size="S" value={90} variant="critical" />
  <Meter label="Space used" size="L" value={90} variant="critical" />
</Flex>
```

### Variants
[View guidelines](https://spectrum.adobe.com/page/meter/#Options)

```tsx example
<Flex direction="column" gap="size-300">
  <Meter label="Space used" value={25} variant="informative" />
  <Meter label="Space used" value={25} variant="positive" />
  <Meter label="Space used" value={90} variant="critical" />
  <Meter label="Space used" value={70} variant="warning" />
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Numberfield NumberField (`packages/@adobe/react-spectrum/docs/numberfield/NumberField.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/numberfield';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/numberfield/package.json';

```jsx import
import {NumberField} from '@react-spectrum/numberfield';
import {Flex} from '@react-spectrum/layout';
```

---
category: Forms
keywords: [number field, input]
---

# NumberField

<PageDescription>{docs.exports.NumberField.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['NumberField']}
  sourceData={[]}
  since="3.10.0" />

## Example

```tsx example
<NumberField label="Width" defaultValue={1024} minValue={0}  />
```

## Value

A NumberField's `value` is empty by default, but an initial, uncontrolled, value can be provided using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop.

```tsx example
function Example() {
  let [value, setValue] = React.useState(15);

  return (
    <Flex gap="size-150" wrap>
      <NumberField
        label="Cookies (Uncontrolled)"
        defaultValue={15}
        minValue={0} />

      <NumberField
        label="Cookies (Controlled)"
        value={value}
        onChange={setValue}
        minValue={0} />
    </Flex>
  );
}
```

### HTML forms

NumberField supports the `name` prop for integration with HTML forms. The value will be submitted to the server as a raw number (e.g. `45`), not as a locale-dependent formatted string (e.g. `"$45.00"`).

```tsx example
<NumberField
  label="Transaction amount"
  name="amount"
  defaultValue={45}
  formatOptions={{
    style: 'currency',
    currency: 'USD'
  }} />
```

## Labeling

A visual label should be provided for the NumberField using the `label` prop. If the NumberField is required, the `isRequired` and
`necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-150" wrap>
  <NumberField label="Cookies" minValue={0} />
  <NumberField label="Cookies" isRequired necessityIndicator="icon" minValue={0}  />
  <NumberField label="Cookies" isRequired necessityIndicator="label" minValue={0}  />
  <NumberField label="Cookies" necessityIndicator="label" minValue={0}  />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the NumberField for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a NumberField, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Number formatting

The NumberField value can be formatted by using the `formatOptions` prop.
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.
Currently only standard notation is supported, though scientific, engineering, and compact notation may be supported in the future.

NumberField supports three numeral systems; Latin, Arabic-Indic, and Han positional decimal. Regardless of the locale, these three
can be parsed from typed input. Initial rendering will appear in the [default numeral system](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem) for the locale unless explicitly overridden.

### Decimals

The following example uses the `signDisplay` option to include the plus sign for positive numbers, for example to display an offset from some value.
In addition, it always displays a minimum of 1 digit after the decimal point, and allows up to 2 fraction digits.
If the user enters more than 2 fraction digits, the result will be rounded.

```tsx example
<NumberField
  label="Adjust exposure"
  formatOptions={{
    signDisplay: 'exceptZero',
    minimumFractionDigits: 1,
    maximumFractionDigits: 2
  }}
  defaultValue={0} />
```

### Percentages

The `style: 'percent'` option can be passed to the `formatOptions` prop to treat the value as a percentage. In this mode,
the value is multiplied by 100 before it is displayed, i.e. `0.45` is displayed as `45%`. The reverse is also true: when the
user enters a value, the `onChange` event will be triggered with the entered value divided by 100. When the percent option
is enabled, the default step automatically changes to `0.01` such that incrementing and decrementing occurs by `1%`. This can
be overridden with the `step` prop. [See below](#step-values) for details.

```tsx example
<NumberField
  label="Sales tax"
  formatOptions={{style: 'percent'}}
  minValue={0}
  defaultValue={0.05} />
```

### Currency values

The `style: 'currency'` option can be passed to the `formatOptions` prop to treat the value as a currency value. The `currency`
option must also be passed to set the currency code (e.g. `USD`) to use. In addition, the `currencyDisplay` option can be
used to choose whether to display the currency symbol, currency code, or currency name. Finally, the `currencySign` option
can be set to `accounting` to use accounting notation for negative numbers, which uses parentheses rather than a minus sign
in some locales.

If you need to allow the user to change the currency, you should include a separate dropdown next to the NumberField.
The NumberField itself will not determine the currency from the user input.

```tsx example
<NumberField
  label="Transaction amount"
  defaultValue={45}
  formatOptions={{
    style: 'currency',
    currency: 'EUR',
    currencyDisplay: 'code',
    currencySign: 'accounting'
  }} />
```

### Units

The `style: 'unit'` option can be passed to the `formatOptions` prop to format the value with a unit of measurement. The `unit`
option must also be passed to set which unit to use (e.g. `inch`). In addition, the `unitDisplay` option can be used to choose
whether to display the unit in long, short, or narrow format.

If you need to allow the user to change the unit, you should include a separate dropdown next to the number field.
The number field itself will not determine the unit from the user input.

**Note:** The `unit` style is not currently supported in Safari. A [polyfill](https://formatjs.io/docs/polyfills/intl-numberformat/)
may be necessary.

```tsx example
<NumberField
  label="Package width"
  defaultValue={4}
  minValue={0}
  formatOptions={{
    style: 'unit',
    unit: 'inch',
    unitDisplay: 'long'
  }} />
```

## Minimum and maximum values

The `minValue` and `maxValue` props can be used to limit the entered value to a specific range. The value will be clamped
when the user blurs the input field. In addition, the increment and decrement buttons will be disabled when the value is
within one `step` value from the bounds ([see below](#step-values) for info about steps). Ranges can be open ended by only
providing either `minValue` or `maxValue` rather than both.

If a valid range is known ahead of time, it is a good idea to provide it to `NumberField` so it can optimize the experience.
For example, when the minimum value is greater than or equal to zero, it is possible to use a numeric keyboard on iOS rather
than a full text keyboard (necessary to enter a minus sign).

```tsx example
<NumberField
  label="Enter your age"
  minValue={0} />
```

## Step values

The `step` prop can be used to snap the value to certain increments. If there is a `minValue` defined, the steps are calculated
starting from the minimum. For example, if `minValue={2}`, and `step={3}`, the valid step values would be 2, 5, 8, 11, etc. If no
`minValue` is defined, the steps are calculated starting from zero and extending in both directions. In other words, such that the
values are evenly divisible by the step. A `step` can be any positive decimal. If no `step` is defined, any decimal value may be typed, but incrementing and decrementing
snaps the value to an integer.

If the user types a value that is between two steps and blurs the input, the value will be snapped to the nearest step. When
incrementing or decrementing, the value is snapped to the nearest step that is higher or lower, respectively.
When incrementing or decrementing from an empty field, the value starts at the `minValue` or `maxValue`, respectively, if defined.
Otherwise, the value starts from `0`.

```tsx example
<Flex direction="column" gap="size-150">
  <NumberField
    label="Step"
    step={10} />
  <NumberField
    label="Step + minValue"
    minValue={2}
    step={3} />
  <NumberField
    label="Step + minValue + maxValue"
    minValue={2}
    maxValue={21}
    step={3} />
</Flex>
```

## Events

NumberField accepts an `onChange` prop which is triggered whenever the value is committed by the user. This happens on blur of the field
or on interaction with the stepper functionality, arrow keys or stepper buttons.
For a full list of supported events, see the [Props](#props) table below.

The example below uses `onChange` to update a separate `pre` element with the same values entered into the NumberField.
```tsx example
function Example() {
  let [value, setValue] = React.useState(null);

  return (
    <Flex direction="column" gap="size-150">
      <NumberField
        onChange={setValue}
        label="Number of cookies to buy"
        minValue={0} />
      <pre>How many cookies you are ordering: {isNaN(value) ? 0 : value}</pre>
    </Flex>
  );
}
```

## Validation

NumberField supports the `isRequired` prop to ensure the user enters a value, as well as custom validation functions, realtime validation, and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the number field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <NumberField label="Width" name="width" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `NumberField` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Props

<PropTable component={docs.exports.NumberField} links={docs.links} />

## Visual options

### Quiet

```tsx example
<NumberField label="Cookies" isQuiet minValue={0} />
```

### Hidden Steppers

NumberField stepper buttons are optional.

```tsx example
<NumberField label="Cookies" hideStepper minValue={0} />
```

### Disabled

```tsx example
<NumberField label="Cookies" isDisabled minValue={0} />
```

### Read only

The `isReadOnly` boolean prop makes the NumberField's text content immutable. Unlike `isDisabled`, the NumberField remains focusable
and the contents can still be copied. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<NumberField label="Cookies" defaultValue={15} isReadOnly minValue={0} />
```

### Label alignment and position
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)

By default, the label is positioned above the NumberField. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the NumberField and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<NumberField label="Cookies" labelPosition="side" labelAlign="end" minValue={0} />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a NumberField. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
  let [value, setValue] = React.useState(1);
  let isValid = React.useMemo(() => value > 0 || Number.isNaN(value), [value]);

  return (
    <NumberField
      validationState={Number.isNaN(value) ? undefined : (isValid ? 'valid' : 'invalid')}
      value={value}
      onChange={setValue}
      label="Positive numbers only"
      description="Enter a positive number."
      errorMessage={value === 0 ? 'Is zero positive?' : 'Positive numbers are bigger than 0.'}
    />
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a NumberField.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<NumberField
  label="Exposure"
  formatOptions={{
    signDisplay: 'exceptZero',
    minimumFractionDigits: 1,
    maximumFractionDigits: 2
  }}
  defaultValue={0}
  contextualHelp={
    <ContextualHelp>
      <Heading>What is exposure?</Heading>
      <Content>Exposure adjusts how bright the image is.</Content>
    </ContextualHelp>
  } />
```

### Custom width

[View guidelines](https://spectrum.adobe.com/page/text-field/#Width)

```tsx example
<NumberField label="Cookies" width="size-3600" maxWidth="100%" minValue={0} />
```

---

### Packages @Adobe React Spectrum Docs Picker Picker (`packages/@adobe/react-spectrum/docs/picker/Picker.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/picker';
import selectUtil from 'docs:@react-aria/test-utils';
import {HeaderInfo, PropTable, PageDescription, ClassAPI, VersionBadge} from '@react-spectrum/docs';
import packageData from '@react-spectrum/picker/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Picker, Item, Section} from '@react-spectrum/picker';
import Book from '@spectrum-icons/workflow/Book';
import BulkEditUsers from '@spectrum-icons/workflow/BulkEditUsers';
import Draw from '@spectrum-icons/workflow/Draw';
import {Text} from '@react-spectrum/text';
import {Avatar} from "@react-spectrum/avatar";
```

---
category: Pickers
keywords: [select, collections, dropdown]
---

# Picker

<PageDescription>{docs.exports.Picker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Picker', 'Item', 'Section']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/picker/'}
  ]}
  since="3.0.0" />

## Example
```tsx example
<Picker label="Choose frequency">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

## Content
Picker follows the [Collection Components](collections.html) API, accepting both static and dynamic collections. Similar to [Menu](Menu.html), Picker accepts `<Item>` elements as children, each with a `key` prop. Basic usage of Picker, seen in the example above, shows multiple options populated with a string. Static collections, as in this example, can be used when the full list of options is known ahead of time.

Dynamic collections, as shown below, can be used when the options come from an external data source such as an API call, or update over time. Providing the data in this way allows Picker to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of options is passed to the Picker using the `items` prop. Each item accepts a key prop, which is passed to the `onSelectionChange` handler to identify the selected item. Alternatively, if the item objects contain an `id` property, as shown in the example below, then this is used automatically and a `key` prop is not required. See the [Events](#events) section for more detail on selection.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];
  let [animalId, setAnimalId] = React.useState(null);

  return (
    <>
      <Picker label="Pick an animal" items={options} onSelectionChange={setAnimalId}>
        {item => <Item>{item.name}</Item>}
      </Picker>
      <p>Animal id: {animalId}</p>
    </>
  );
}
```

### Trays
On mobile, Pickers automatically display in a tray instead of a popover to improve usability.

### Internationalization
To internationalize a Picker, a localized string should be passed to the `children` of each `Item`.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the Picker is automatically flipped.

## Labeling
Picker can be labeled using the `label` prop. If no label is provided, an alternative text label must be provided to identify the control for accessibility. This should be added using the `aria-label` prop. If the Picker is a required field, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Picker label="Choose frequency" isRequired necessityIndicator="icon">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
```tsx example
<Picker label="Choose frequency" isRequired necessityIndicator="label">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
```tsx example
<Picker label="Choose frequency" necessityIndicator="label">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

## Selection
Setting a selected option can be done by using the `defaultSelectedKey` or `selectedKey` prop. The selected key corresponds to the `key` of an item. See [Events](#events) for more details on selection events.
Additionally see the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
import type {Key} from '@adobe/react-spectrum';

function Example() {
  let options = [
    {name: 'Koala'},
    {name: 'Kangaroo'},
    {name: 'Platypus'},
    {name: 'Bald Eagle'},
    {name: 'Bison'},
    {name: 'Skunk'}
  ];
  let [animal, setAnimal] = React.useState<Key>("Bison");

  return (
    <Flex gap="size-150" wrap>
      <Picker
        label="Pick an animal (uncontrolled)"
        items={options}
        defaultSelectedKey="Bison">
        {item => <Item key={item.name}>{item.name}</Item>}
      </Picker>

      <Picker
        label="Pick an animal (controlled)"
        items={options}
        selectedKey={animal}
        onSelectionChange={selected => setAnimal(selected)}>
        {item => <Item key={item.name}>{item.name}</Item>}
      </Picker>
    </Flex>
  );
}
```

### HTML forms

Picker supports the `name` prop for integration with HTML forms. The `key` of the selected item will be submitted to the server.

```tsx example
<Picker
  label="Favorite Animal"
  ///- begin highlight -///
  name="favoriteAnimalId"
  ///- end highlight -///
>
  <Item key="panda">Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
</Picker>
```

## Links

By default, interacting with an item in a Picker triggers `onSelectionChange`. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Link items in a `Picker` are not selectable.

```tsx example
<Picker label="Project">
  <Item href="https://example.com/" target="_blank">Create new…</Item>
  <Item>Proposal</Item>
  <Item>Budget</Item>
  <Item>Onboarding</Item>
</Picker>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
Picker supports sections in order to group options. Sections can be used by wrapping groups of items in a `Section` element. Each `Section` takes a `title` and `key` prop.

### Static items
```tsx example
<Picker label="Pick your favorite">
  <Section title="Animals">
    <Item key="Aardvark">Aardvark</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Snake">Snake</Item>
  </Section>
  <Section title="People">
    <Item key="Danni">Danni</Item>
    <Item key="Devon">Devon</Item>
    <Item key="Ross">Ross</Item>
  </Section>
</Picker>
```
### Dynamic items
Sections used with dynamic items are populated from a hierarchical data structure. Similarly to the props on `Picker`, `Section` takes an array of data using the `items` prop.

```tsx example
function Example() {
  let options = [
    {name: 'Australian', children: [
      {id: 2, name: 'Koala'},
      {id: 3, name: 'Kangaroo'},
      {id: 4, name: 'Platypus'}
    ]},
    {name: 'American', children: [
      {id: 6, name: 'Bald Eagle'},
      {id: 7, name: 'Bison'},
      {id: 8, name: 'Skunk'}
    ]}
  ];

  return (
    <Picker label="Pick an animal" items={options} onSelectionChange={selected => alert(selected)}>
      {item => (
        <Section key={item.name} items={item.children} title={item.name}>
          {item => <Item>{item.name}</Item>}
        </Section>
      )}
    </Picker>
  );
}
```

## Events
Picker supports selection via mouse, keyboard, and touch. You can handle all of these via the `onSelectionChange`
prop. Picker will pass the selected `key` to the `onSelectionChange` handler.

The following example uses an `onSelectionChange` handler to update the selection stored in React state.

```tsx example
function StaticExample() {
  let [frequency, setFrequency] = React.useState(null);

  return (
    <>
      <Picker label="Choose frequency" onSelectionChange={selected => setFrequency(selected)}>
        <Item key="Rarely">Rarely</Item>
        <Item key="Sometimes">Sometimes</Item>
        <Item key="Always">Always</Item>
      </Picker>
      <p>You selected {frequency}</p>
    </>
  );
}
```

When using Picker with dynamic items, selection works much the same way using `key`. However, if your data already has an `id` property (as is common with many data sets), Picker can use that id without needing to specify a `key` prop. The below example shows Picker using the id of each item from the `items` array as the selected value without the need for `key`. Note that `key` will always take precedence if set.

```tsx example
function DynamicExample() {
  let [animalId, setAnimalId] = React.useState(null);
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];

  return (
    <>
      <Picker label="Pick an animal" items={options} onSelectionChange={selected => setAnimalId(selected)}>
        {item => <Item>{item.name}</Item>}
      </Picker>
      <p>Your favorite animal has id: {animalId}</p>
    </>
  );
}
```

## Complex items
Items within Picker also allow for additional content used to better communicate options. Icons, avatars, and descriptions can be added to the `children` of `Item` as shown in the example below.
If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
See Icon's [labeling](workflow-icons.html#labeling) section and Avatar's [accessibility](Avatar.html#accessibility) section for more information on how to label these elements.

```tsx example
<Picker label="Options">
  <Section title="Permission">
    <Item textValue="Read">
      <Book size="S" />
      <Text>Read</Text>
      <Text slot="description">Read Only</Text>
    </Item>
    <Item textValue="Write">
      <Draw size="S" />
      <Text>Write</Text>
      <Text slot="description">Read and Write Only</Text>
    </Item>
    <Item textValue="Admin">
      <BulkEditUsers size="S" />
      <Text>Admin</Text>
      <Text slot="description">Full access</Text>
    </Item>
  </Section>
</Picker>
```

### With avatars

```tsx example
<Picker label="Select a user">
  <Item textValue="User 1">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 1</Text>
  </Item>
  <Item textValue="User 2">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 2</Text>
  </Item>
  <Item textValue="User 3">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 3</Text>
  </Item>
  <Item textValue="User 4">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 4</Text>
  </Item>
</Picker>
```

## Asynchronous loading

Picker supports loading data asynchronously, and will display a progress circle when the `isLoading` prop is set.
It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data.
See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Pokemon {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Pokemon>({
    async load({signal, cursor}) {
      // If no cursor is available, then we're loading the first page.
      // Otherwise, the cursor is the next URL to load, as returned from the previous page.
      let res = await fetch(cursor || 'https://pokeapi.co/api/v2/pokemon', {signal});
      let json = await res.json();
      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <Picker
      label="Pick a Pokemon"
      items={list.items}
      isLoading={list.isLoading}
      onLoadMore={list.loadMore}>
      {item => <Item key={item.name}>{item.name}</Item>}
    </Picker>
  );
}
```

## Validation

Picker supports the `isRequired` prop to ensure the user selects an option, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <Picker label="Favorite animal" name="animal" isRequired>
  {/*- end highlight -*/}
    <Item>Aardvark</Item>
    <Item>Cat</Item>
    <Item>Dog</Item>
    <Item>Kangaroo</Item>
    <Item>Panda</Item>
    <Item>Snake</Item>
  </Picker>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `Picker` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Props

<PropTable component={docs.exports.Picker} links={docs.links} />

## Visual options

### Label alignment and position

By default, the label is positioned above the Picker. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the Picker and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<Picker label="Choose frequency" labelPosition="side" labelAlign="end">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
### Quiet
```tsx example
<Picker label="Choose frequency" isQuiet>
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
### Disabled
```tsx example
<Picker label="Choose frequency" isDisabled>
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/picker/#Help-text-(description-and-error-message))

Both a description and an error message can be supplied to a Picker. The description is always visible unless `isInvalid` is true and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
    let [animalId, setAnimalId] = React.useState(null);
    let options = [
      {id: 1, name: 'Aardvark'},
      {id: 2, name: 'Cat'},
      {id: 3, name: 'Dog'},
      {id: 4, name: 'Kangaroo'},
      {id: 5, name: 'Koala'},
      {id: 6, name: 'Penguin'},
      {id: 7, name: 'Snake'},
      {id: 8, name: 'Turtle'},
      {id: 9, name: 'Wombat'}
    ];
  let isValid = React.useMemo(() => animalId !== 2 && animalId !== 7, [animalId]);

  return (
    <Picker
      isInvalid={!isValid}
      label="Favorite animal"
      description="Pick your favorite animal, you will be judged."
      errorMessage={animalId === 2 ? 'The author of this example is a dog person.' : 'Oh no it\'s a snake! Choose anything else.'}
      items={options}
      selectedKey={animalId}
      onSelectionChange={selected => setAnimalId(selected)}>
      {item => <Item>{item.name}</Item>}
    </Picker>
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a Picker.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<Picker
  label="Engineering major"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Major changes</Heading>
      <Content>Once you have changed your major, you cannot change it back.</Content>
    </ContextualHelp>
  }>
  <Item>Aerospace</Item>
  <Item>Mechanical</Item>
  <Item>Civil</Item>
  <Item>Nuclear</Item>
  <Item>Industrial</Item>
  <Item>Chemical</Item>
  <Item>Agricultural</Item>
  <Item>Electrical</Item>
</Picker>
```

### Custom widths
```tsx example
<Flex direction="column" rowGap="size-150">
  <Picker label="Choose frequency" width="size-3600" maxWidth="100%">
    <Item key="rarely">Rarely</Item>
    <Item key="sometimes">Sometimes</Item>
    <Item key="always">Always</Item>
  </Picker>

  <Picker label="Choose animal" menuWidth="size-6000">
    <Item key="Emu">Emu</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Platypus">Platypus</Item>
  </Picker>
</Flex>
```

### Align and direction
```tsx example
<Flex direction="column" gap="size-150">
  <Picker label="Choose frequency" align="end" menuWidth="size-3000">
    <Item key="rarely">Rarely</Item>
    <Item key="sometimes">Sometimes</Item>
    <Item key="always">Always</Item>
  </Picker>

  <Picker label="Choose animal" direction="top">
    <Item key="Emu">Emu</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Platypus">Platypus</Item>
  </Picker>
</Flex>
```

### Menu state
The open state of the menu can be controlled via the `defaultOpen` and `isOpen` props

```tsx example
function Example() {
  let [open, setOpen] = React.useState(false);

  return (
    <Picker
      label="Frequency"
      isOpen={open}
      onOpenChange={setOpen}>
      <Item key="rarely">Rarely</Item>
      <Item key="sometimes">Sometimes</Item>
      <Item key="always">Always</Item>
    </Picker>
  );
}
```

## Testing

The Picker features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your device configuration, this overlay may render as a tray or a dropdown. Additionally, the Picker features automatic virtualization
and may need specific mocks in a test environment to enable said virtualization properly. Please see the following sections in the testing docs
for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/picker/test/Picker.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common select interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the select tester and a sample of how you could use it in your test suite.

```ts
// Picker.test.ts
import {render} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/Picker.html#testing

it('Picker can select an option via keyboard', async function () {
  // Render your test component/app and initialize the select tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <Picker data-testid="test-select">
      ...
      </Picker>
    </Provider>
  );
  let selectTester = testUtilUser.createTester('Select', {root: getByTestId('test-select'), interactionType: 'keyboard'});
  let trigger = selectTester.getTrigger();
  expect(trigger).toHaveTextContent('Select…');

  await selectTester.toggleOptionSelection({option: 'Cat'});
  expect(trigger).toHaveTextContent('Cat');
});
```

<ClassAPI links={selectUtil.links} class={selectUtil.exports.SelectTester} />

---

### Packages @Adobe React Spectrum Docs Progress ProgressBar (`packages/@adobe/react-spectrum/docs/progress/ProgressBar.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/progress';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/progress/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {ProgressBar} from '@react-spectrum/progress';
import {View} from '@react-spectrum/view';
```

---
category: Status
keywords: [progress bar]
---

# ProgressBar

<PageDescription>{docs.exports.ProgressBar.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ProgressBar']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/progress-bar/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<ProgressBar label="Loading…" value={50} />
```

## Value

ProgressBars are controlled with the `value` prop.
By default, the `value` prop represents the current percentage of progress, as the minimum and maximum values default to 0 and 100, respectively.

```tsx example
<ProgressBar label="Loading…" value={25} />
```

Alternatively, a different scale can be used by setting the `minValue` and `maxValue` props.

```tsx example
<ProgressBar label="Loading…" minValue={50} maxValue={150} value={100} />
```

Values are formatted as a percentage by default, but this can be modified by using the `formatOptions` prop to specify a different format.
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.

```tsx example
<ProgressBar label="Loading…" formatOptions={{style: 'currency', currency: 'JPY'}} value={60} />
```

### Indeterminate
[View guidelines](https://spectrum.adobe.com/page/progress-bar/#Indeterminate)

By default, ProgressBars are determinate. Use a determinate ProgressBar when progress can be calculated against a specific goal.

```tsx example
<ProgressBar label="Loading…" value={50} />
```

Use an indeterminate ProgressBar when the wait time or effort to completion can not be determined.

```tsx example
<ProgressBar label="Loading…" isIndeterminate />
```

## Labeling
[View guidelines](https://spectrum.adobe.com/page/progress-bar/#Label)

Labels and value labels are shown by default on top, but they can also be moved to the side or hidden as needed.
The label text should be in sentence case.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <ProgressBar label="Loading…" value={30} />
  <ProgressBar label="Loading…" labelPosition="side" value={30} />
  <ProgressBar label="Loading…" showValueLabel={false} value={30} />
</Flex>
```

By default, the value label is formatted as a percentage. This can be customized using the following props.

* `showValueLabel`: Allows you to display or hide the value label.
* `formatOptions`: Allows you to customize the format of the value.
* `valueLabel`: Allows you to customize the value label to any string.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <ProgressBar label="Loading…" showValueLabel={false} value={30} />
  <ProgressBar label="Loading…" valueLabel="30 of 60 dogs" value={30} />
  <ProgressBar label="Loading…" formatOptions={{style: 'percent', minimumFractionDigits: 2}} value={30.123} />
</Flex>
```

### Accessibility

Depending on the visualization being used (i.e. depending on the `showValueLabel` prop), a `label`, `aria-label`, or `aria-labelledby` prop is required.

If using the `staticColor` prop, ensure the background offers enough contrast for the ProgressBar to be legible and meets color contrast guidelines.

### Internationalization

To internationalize a ProgressBar, a localized string should be passed to the `label` prop, `aria-label` prop, or value of the associated `aria-labelledby` element.

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout, for both determinate and indeterminate options, is automatically flipped. In addition,
ProgressBar automatically uses the current locale to format the value label.


## Props

<PropTable component={docs.exports.ProgressBar} links={docs.links} />

## Visual options

### Static color

When a ProgressBar needs to be placed on top of a dark background, use `staticColor='white'`. When it is placed over a light background, use `staticColor='black'`.

```tsx example
<View backgroundColor="static-blue-700" padding="size-300">
  <ProgressBar label="Loading…" staticColor="white" value={5} />
</View>
<View backgroundColor="static-yellow-400" padding="size-300">
  <ProgressBar label="Loading…" staticColor="black" value={5} />
</View>
```

### Size
[View guidelines](https://spectrum.adobe.com/page/progress-bar/#Size)

```tsx example
<Flex direction="column" gap="size-300">
  <ProgressBar label="Small" size="S" value={70} />
  <ProgressBar label="Large" size="L" value={70} />
</Flex>
```

---

### Packages @Adobe React Spectrum Docs Progress ProgressCircle (`packages/@adobe/react-spectrum/docs/progress/ProgressCircle.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/progress';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/progress/package.json';

```jsx import
import {ProgressCircle} from '@react-spectrum/progress';
import {View} from '@react-spectrum/view';
```

---
category: Status
keywords: [progress circle]
---

# ProgressCircle

<PageDescription>{docs.exports.ProgressCircle.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['ProgressCircle']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/progress-circle/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<ProgressCircle aria-label="Loading…" value={50} />
```

## Value

ProgressCircles are controlled with the `value` prop.
By default, the `value` prop represents the current percentage of progress, as the minimum and maximum values default to 0 and 100, respectively.

```tsx example
<ProgressCircle aria-label="Loading…" value={25} />
```

Alternatively, a different scale can be used by setting the `minValue` and `maxValue` props.

```tsx example
<ProgressCircle aria-label="Loading…" minValue={50} maxValue={150} value={100} />
```

### Indeterminate
[View guidelines](https://spectrum.adobe.com/page/progress-circle/#Indeterminate)

By default, ProgressCircles are determinate. Use a determinate ProgressCircle when progress can be calculated against a specific goal.

```tsx example
<ProgressCircle aria-label="Loading…" value={50} />
```

Use an indeterminate ProgressCircle when progress is happening but the time or effort to completion can’t be determined.

```tsx example
<ProgressCircle aria-label="Loading…" isIndeterminate />
```

### Accessibility

An `aria-label` must be provided for accessibility. If the ProgressCircle is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

If using the `staticColor` prop, ensure the background offers enough contrast for the ProgressCircle to be legible and meets color contrast guidelines.

### Internationalization

To internationalize a ProgressCircle, a localized string should be passed to the `aria-label` prop (or value of the associated `aria-labelledby` element).

For languages that are read right-to-left (e.g. Hebrew and Arabic), the fill of both determinate and indeterminate ProgressCircles continues to spin clockwise.

## Props

<PropTable component={docs.exports.ProgressCircle} links={docs.links} />

## Visual options

### Static color

When a ProgressCircle needs to be placed on top of a dark background, use `staticColor='white'`. When it is placed over a light background, use `staticColor='black'`.

```tsx example
<View backgroundColor="static-blue-700" padding="size-300">
  <ProgressCircle aria-label="Loading…" staticColor="white" isIndeterminate />
</View>
<View backgroundColor="static-yellow-400" padding="size-300">
  <ProgressCircle aria-label="Loading…" staticColor="black" isIndeterminate />
</View>
```

### Size
[View guidelines](https://spectrum.adobe.com/page/progress-circle/#Size)

```tsx example
<ProgressCircle aria-label="Loading…" marginEnd="size-300" size="S" value={15} />
<ProgressCircle aria-label="Loading…" marginEnd="size-300" value={30} />
<ProgressCircle aria-label="Loading…" size="L" value={60} />
```

---

### Packages @Adobe React Spectrum Docs Provider Provider (`packages/@adobe/react-spectrum/docs/provider/Provider.mdx`)

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/provider';
import {HeaderInfo, PropTable, PageDescription, TypeLink} from '@react-spectrum/docs';
import packageData from '@react-spectrum/provider/package.json';

```jsx import
import {Checkbox} from '@react-spectrum/checkbox';
import {TextField} from '@react-spectrum/textfield';
import {Flex} from '@react-spectrum/layout';
import {Picker, Item} from '@react-spectrum/picker';
import {ActionButton} from '@react-spectrum/button';
import {RadioGroup, Radio} from '@react-spectrum/radio';
import {View} from '@react-spectrum/view';
```

---
category: Application
keywords: [theme, locale, application, colorstop]
---

# Provider

<PageDescription>{docs.exports.Provider.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Provider', 'useProvider']}
  since="3.0.0" />

## Example

```tsx example
import {Provider} from '@react-spectrum/provider';
import {theme} from '@react-spectrum/theme-default';
import {Button} from '@react-spectrum/button';

function App() {
  return (
    <Provider theme={theme}>
      <Button variant="accent">
        Hello React Spectrum!
      </Button>
    </Provider>
  );
}
```

## Application provider

A Provider must be the root component of your application. All other React Spectrum components rely on the Provider to define the theme, locale, and other settings that they need in order to render.

### Themes
In order to provide the styling attributes that components need to render, you must pass a theme as a prop to the root provider in your application. Themes consist of a light and dark color scheme, along with medium and large platform scales. By default, React Spectrum will select the color scheme according to the user’s operating system setting, and the scale according to the device type (e.g. touch vs mouse input). To read more details about how theming works in React Spectrum, see the [theming docs](theming.html).

### Color Schemes
We recommend supporting both light and dark color schemes in your app, however, if you need to override this with an application specific setting, you can use the `colorScheme` prop.

```tsx example
<Provider theme={theme} colorScheme="light">
  <ActionButton margin="size-100">I'm a light button</ActionButton>
</Provider>
```

See the [styling docs](styling.html) for more information about using Spectrum color variables in your app to ensure it adapts to light and dark mode properly.

### Locales
Another important setting for your application is the locale. By default, React Spectrum chooses the locale matching the user’s browser/operating system language, but this can be overridden with the locale prop if you have an application specific setting. This prop accepts a [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) language code. A list of supported locales is available [here](react-aria:quality#internationalization#supported-locales).


```tsx
<Provider theme={theme} locale={appSettings.locale}>
  <YourApp />
</Provider>
```

To access the current locale anywhere in your application, see the [useLocale](react-aria:useLocale) hook.

### Breakpoints

The Provider component can also be used to set the responsive breakpoints for your application, which are used by [layout components](layout.html#responsive-layout) and [style props](styling.html#responsive-styles) of all components within the Provider. By default, React Spectrum provides 5 breakpoints, which correspond to common device resolutions:

* S – 640px
* M - 768px
* L – 1024px
* XL - 1280px
* XXL - 1536px

These breakpoints can be overridden by passing the `breakpoints` prop to the `Provider` component. Any components within the Provider will consume these breakpoints and apply their style props accordingly. By default, React Spectrum uses t-shirt style names for breakpoints, but you can name custom breakpoints however you like.

This example specifies two breakpoints: `tablet` and `desktop`. It displays a [View](View.html) that changes color depending on which breakpoint is matched: green by default, blue at the `tablet` breakpoint, and magenta at the `desktop` breakpoint. See the docs for [style props](styling.html#responsive-styles) for more details.

```tsx example
<Provider theme={theme} breakpoints={{tablet: 640, desktop: 1024}}>
  <View height="size-1000" backgroundColor={{base: 'celery-600', tablet: 'blue-600', desktop: 'magenta-600'}} />
</Provider>
```

### Client side routing

The Provider component accepts an optional `router` prop. This enables React Spectrum components that render links to perform client side navigation using your application or framework's client side router. See the [client side routing guide](routing.html) for details on how to set this up.

```tsx
let navigate = useNavigateFromYourRouter();

<Provider theme={theme} router={{navigate}}>
  <YourApp />
</Provider>
```

## Property groups
Provider can also be used to define common properties for a group of components within it. For example, a group of components could be disabled together rather than individually by setting the `isDisabled` prop on any parent provider.

```tsx example
<Flex direction="column" gap="size-100" alignItems="start">
  <Provider isDisabled>
    <RadioGroup label="Favorite animal">
      <Radio value="dogs">Dogs</Radio>
      <Radio value="cats">Cats</Radio>
      <Radio value="horses">Horses</Radio>
    </RadioGroup>
    <Checkbox>I agree</Checkbox>
    <Button variant="primary">Submit</Button>
  </Provider>
</Flex>
```

Provider supports many other properties that can be used in this way: `isQuiet`, `isEmphasized`, `isDisabled`, `isRequired`, `isReadOnly`, and `validationState`. These will be applied to any child components that support them.

Property groups can also be nested. For example, a group of components could be made quiet or emphasized, with a sub-group that is also disabled. The inner-most provider will override outer ones, as will corresponding props on the components themselves.

The following example shows a registration form, which disables a picker and submit button until an email address is entered. All elements within the form use a quiet style, except the submit button, which overrides the provider setting using a prop.

```tsx example
function Register() {
  let [email, setEmail] = React.useState('');

  return (
    <Flex direction="column" gap="size-100" alignItems="start">
      <Provider isQuiet>
        <TextField
          label="Email"
          value={email}
          onChange={setEmail} />
        <Provider isDisabled={email.length === 0}>
          <Picker label="Favorite color">
            <Item key="magenta">Magenta</Item>
            <Item key="indigo">Indigo</Item>
            <Item key="chartreuse">Chartreuse</Item>
          </Picker>
          <Button variant="primary">Submit</Button>
        </Provider>
      </Provider>
    </Flex>
  );
}
```

## Props

<PropTable component={docs.exports.Provider} links={docs.links} />

## useProvider
The <TypeLink links={docs.links} type={docs.exports.useProvider} /> hook can be used to access the various properties applied by the nearest parent Provider. This can be useful for adapting a custom component to the current color scheme or scale.

The example below uses the `colorScheme` returned from `useProvider` to display either a moon or sun icon depending on the current color scheme. Toggle the theme using the switcher in the top right corner of the page to see the icon change.

```tsx example
import Light from '@spectrum-icons/workflow/Light';
import Moon from '@spectrum-icons/workflow/Moon';
import {useProvider} from '@react-spectrum/provider';

function Example() {
  let {colorScheme} = useProvider();

  return colorScheme === 'dark'
    ? <Moon aria-label="In dark theme" />
    : <Light aria-label="In light theme" />
}

<Example />
```

---

### Packages @Adobe React Spectrum Docs Radio RadioGroup (`packages/@adobe/react-spectrum/docs/radio/RadioGroup.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/radio';
import packageData from '@react-spectrum/radio/package.json';
import {HeaderInfo, PropTable, PageDescription, VersionBadge, ClassAPI} from '@react-spectrum/docs';

```jsx import
import {Radio, RadioGroup} from '@react-spectrum/radio';
import {Flex} from '@react-spectrum/layout';
```

---
category: Forms
keywords: [radio group, radio]
---

# RadioGroup

<PageDescription>{docs.exports.Radio.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['RadioGroup', 'Radio']}
  sourceData={[
  {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/radio-button/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<RadioGroup label="Favorite pet">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

## Content

RadioGroup accepts multiple Radio elements as children.
Each Radio represents an option that can be selected, labeled by its children.

**Note:** A Radio cannot be used outside of a RadioGroup.

## Value

RadioGroup only allows single selection. An initial, uncontrolled value can be provided to the RadioGroup using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState('yes');

  return (
    <Flex gap="size-300">
      <RadioGroup label="Are you a wizard? (uncontrolled)" defaultValue="yes">
        <Radio value="yes">Yes</Radio>
        <Radio value="no">No</Radio>
      </RadioGroup>

      <RadioGroup label="Are you a wizard? (controlled)" value={selected} onChange={setSelected}>
        <Radio value="yes">Yes</Radio>
        <Radio value="no">No</Radio>
      </RadioGroup>
    </Flex>
  );
}
```

### HTML forms

RadioGroup supports the `name` prop, paired with the Radio `value` prop, for integration with HTML forms.

```tsx example
<RadioGroup label="Favorite pet" name="pet">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

## Labeling
A visual label should be provided for the RadioGroup using the `label` prop. If the RadioGroup is required, the `isRequired` and
`necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-300" wrap>
  <RadioGroup label="Favorite avatar">
    <Radio value="wizard">Wizard</Radio>
    <Radio value="dragon">Dragon</Radio>
  </RadioGroup>

  <RadioGroup label="Favorite avatar" isRequired necessityIndicator="icon">
    <Radio value="wizard">Wizard</Radio>
    <Radio value="dragon">Dragon</Radio>
  </RadioGroup>

  <RadioGroup label="Favorite avatar" isRequired necessityIndicator="label">
    <Radio value="wizard">Wizard</Radio>
    <Radio value="dragon">Dragon</Radio>
  </RadioGroup>

  <RadioGroup label="Favorite avatar" necessityIndicator="label">
   <Radio value="wizard">Wizard</Radio>
   <Radio value="dragon">Dragon</Radio>
  </RadioGroup>
</Flex>
```
### Accessibility

If a visible label isn't specified for a RadioGroup, an `aria-label` must be provided for accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

Radio elements should always have a visible label.

### Internationalization

To internationalize a RadioGroup, a localized string should be passed to the `label` prop and as the child content of the Radio elements.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the Radio is automatically placed on the right side of the text. When the necessityIndicator prop is set to "label", a localized string will be provided for "(required)" or "(optional)" automatically.

## Events

RadioGroup accepts an `onChange` prop, which is triggered when a user changes the selected value.
The example below uses `onChange` to log how the user is interacting with the component.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState(null);

  return (
    <>
      <RadioGroup label="Favorite avatar" value={selected} onChange={setSelected}>
        <Radio value="wizard">Wizard</Radio>
        <Radio value="dragon">Dragon</Radio>
      </RadioGroup>
      <div>You have selected: {selected}</div>
    </>
  );
}
```

## Validation

RadioGroup supports the `isRequired` prop to ensure the user selects an option, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native">
  {/*- begin highlight -*/}
  <RadioGroup label="Favorite pet" name="pet" isRequired>
  {/*- end highlight -*/}
    <Radio value="dogs">Dog</Radio>
    <Radio value="cats">Cat</Radio>
    <Radio value="dragon">Dragon</Radio>
  </RadioGroup>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `RadioGroup` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## RadioGroup props

<PropTable component={docs.exports.RadioGroup} links={docs.links} />

## Radio props

<PropTable component={docs.exports.Radio} links={docs.links} />

## Visual options

### Orientation

RadioGroups are vertically oriented by default.
The `orientation` prop can be used to change the orientation to horizontal.

```tsx example
<RadioGroup label="Favorite avatar" orientation="horizontal">
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

### Label position and alignment
[View guidelines](https://spectrum.adobe.com/page/radio-button/#Label)

By default, the label is positioned above the RadioGroup.
The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can
be used to align the label as "start" or "end".
For left-to-right (LTR) languages, "start" refers to the left most edge of the RadioGroup
and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<RadioGroup label="Favorite avatar" labelPosition="side" labelAlign="end">
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/radio-group/#Help-text-(description-and-error-message))

Both a description and an error message can be supplied to a RadioGroup. The description is always visible unless `isInvalid` is true and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState('dogs');
  let isValid = selected === 'dogs';

  return (
    <RadioGroup
      aria-label="Favorite pet"
      onChange={setSelected}
      isInvalid={!isValid}
      description="Please select a pet."
      errorMessage={
        selected === 'cats'
          ? 'No cats allowed.'
          : 'Please select dogs.'
      }>
      <Radio value="dogs">
        Dogs
      </Radio>
      <Radio value="cats">
        Cats
      </Radio>
      <Radio value="dragons">
        Dragons
      </Radio>
    </RadioGroup>
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a RadioGroup.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<RadioGroup
  label="T-shirt size"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Size and fit</Heading>
      <Content>Our sizes run on the small side. Choose a size up from your usual.</Content>
    </ContextualHelp>
  }>
  <Radio value="S">Small</Radio>
  <Radio value="M">Medium</Radio>
  <Radio value="L">Large</Radio>
</RadioGroup>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/radio-button/#Disabled)

```tsx example
<RadioGroup label="Favorite avatar" isDisabled>
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

```tsx example
<RadioGroup label="Favorite avatar">
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon" isDisabled>Dragon</Radio>
</RadioGroup>
```

### Read only
[View guidelines](https://spectrum.adobe.com/page/radio-button/#Read-only)

The isReadOnly prop makes the selection immutable. Unlike isDisabled, the RadioGroup remains focusable.
See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<RadioGroup label="Favorite avatar" defaultValue="wizard" isReadOnly>
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

### Emphasized
[View guidelines](https://spectrum.adobe.com/page/radio-button/#Emphasis)

```tsx example
<RadioGroup label="Favorite avatar" defaultValue="dragon" isEmphasized>
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

---

### Packages @Adobe React Spectrum Docs Searchfield SearchField (`packages/@adobe/react-spectrum/docs/searchfield/SearchField.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/searchfield';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/searchfield/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {SearchField} from '@react-spectrum/searchfield';
import User from '@spectrum-icons/workflow/User';
```

---
category: Forms
keywords: [search field, input]
---

# SearchField

<PageDescription>{docs.exports.SearchField.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['SearchField']}
  sourceData={[
  {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/search-field/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
function Example() {
  let [submittedText, setSubmittedText] = React.useState(null);

  return (
    <>
      <SearchField
        label="Search"
        onSubmit={setSubmittedText} />
      <p>Submitted text: {submittedText}</p>
    </>
  );
}
```

## Value

A SearchField's `value` is empty by default, but an initial, uncontrolled, value can be provided using the `defaultValue` prop.
Alternatively, a controlled value can be provided using the `value` prop.

```tsx example
function Example() {
  let [searchValue, setSearchValue] = React.useState('puppies');
  return (
    <Flex gap="size-300">
      <SearchField
        defaultValue="puppies"
        label="Search (uncontrolled)" />

      <SearchField
        value={searchValue}
        onChange={setSearchValue}
        label="Search (controlled)" />
    </Flex>
  );
}
```

### HTML forms

SearchField supports the `name` prop for integration with HTML forms. In addition, attributes such as `type`, `pattern`, `inputMode`, and others are passed through to the underlying `<input>` element.

```tsx example
<SearchField label="Email" name="email" type="email" />
```

## Labeling

A visual label should be provided for the SearchField using the `label` prop. If the SearchField is required, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Flex gap="size-300" wrap>
  <SearchField label="Search" />
  <SearchField label="Search" isRequired necessityIndicator="icon" />
  <SearchField label="Search" isRequired necessityIndicator="label" />
  <SearchField label="Search" necessityIndicator="label" />
</Flex>
```

### Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the SearchField for
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
the `id` of the labeling element instead.

### Internationalization

In order to internationalize a SearchField, a localized string should be passed to the `label` or `aria-label` prop.
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.

## Events

The most commonly used handlers for events in SearchField are the:
- `onChange` prop which is triggered whenever the value is edited by the user.
- `onSubmit` prop which is triggered whenever the value is submitted by the user.
- `onClear` prop which is triggered whenever the value is cleared by the user.

The example below uses `onChange`, `onSubmit`, and `onClear` to update two separate elements with the text entered into the SearchField.

```tsx example
function Example() {
  let [currentText, setCurrentText] = React.useState('');
  let [submittedText, setSubmittedText] = React.useState('');

  return (
    <div>
      <SearchField
        onClear={() => setCurrentText('')}
        onChange={setCurrentText}
        onSubmit={setSubmittedText}
        label="Your text"
        value={currentText}
      />
      <pre>Mirrored text: {currentText}</pre>
      <pre>Submitted text: {submittedText}</pre>
    </div>
  );
}
```

## Validation

SearchField supports native HTML [constraint validation](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation) props such as `isRequired`, `minLength`, and `pattern`, as well as custom validation functions, realtime validation, and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically. Errors are displayed when the user blurs the search field or submits the form.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <SearchField label="Search" name="search" isRequired />
  {/*- end highlight -*/}
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `SearchField` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Props

<PropTable component={docs.exports.SearchField} links={docs.links} />

## Visual options

### Quiet

```tsx example
<SearchField label="Search" isQuiet />
```

### Disabled

```tsx example
<SearchField label="Search" isDisabled />
```

### Read only

The `isReadOnly` boolean prop makes the SearchField's text content immutable. Unlike `isDisabled`, the SearchField remains focusable
and the contents can still be copied. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<SearchField label="Search" defaultValue="abc@adobe.com" isReadOnly />
```

### Label alignment and position

By default, the label is positioned above the SearchField. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the SearchField and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<SearchField label="Search" labelPosition="side" labelAlign="end" />
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/help-text/#Usage-guidelines)

Both a description and an error message can be supplied to a SearchField. The description is always visible unless the `validationState` is “invalid” and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
<Flex gap="size-100" wrap>
  <SearchField label="Search" defaultValue="Burritos" validationState="valid" description="Enter a query." />
  <SearchField label="Search" validationState="invalid" errorMessage="Empty input is not allowed." />
</Flex>
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a SearchField.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<SearchField
  label="Search"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Search tips</Heading>
      <Content>You can use modifiers like "date:" and "from:" to search by specific attributes.</Content>
    </ContextualHelp>
  } />
```

### Custom width

```tsx example
<SearchField label="Search" width="size-3600" />
```

### Custom icon
The icon in the SearchField can be changed to suit the theme of a search. For instance, if the SearchField was for searching users, an icon relating to that would help convey meaning. See the [Icons page](./workflow-icons.html) for more.
```tsx example
<SearchField label="Search for users" icon={<User />} />
```

---

### Packages @Adobe React Spectrum Docs Slider RangeSlider (`packages/@adobe/react-spectrum/docs/slider/RangeSlider.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/slider';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/slider/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {RangeSlider} from '@react-spectrum/slider';
```

---
category: Forms
after_version: 3.0.0-alpha.0
---

# RangeSlider

<PageDescription>{docs.exports.RangeSlider.description}</PageDescription>

<HeaderInfo
packageData={packageData}
componentNames={['RangeSlider']}
sourceData={[{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/slider/'}]}
since="3.7.0" />

## Example

```tsx example
<RangeSlider label="Range" defaultValue={{start: 12, end: 36}} />
```

## Value

RangeSliders are controlled with the `value` prop and uncontrolled with the `defaultValue` prop.
This value consists of two parts, `start` and `end`. Both parts must fall between
the RangeSlider's minimum and maximum values, which default to 0 and 100 respectively.

```tsx example
function Example() {
  let [value, setValue] = React.useState({start: 25, end: 75});
  return (
    <Flex gap="size-150" wrap>
      <RangeSlider
        label="Range (uncontrolled)"
        defaultValue={{start: 25, end: 75}} />
      <RangeSlider
        label="Range (controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

Alternatively, a different scale can be used by setting the `minValue` and `maxValue` props.

```tsx example
<RangeSlider
  label="Range"
  minValue={50}
  maxValue={150}
  defaultValue={{start: 75, end: 100}} />
```

The slider value can be formatted by using the `formatOptions` prop.
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.

```tsx example
<RangeSlider
  label="Price range"
  formatOptions={{style: 'currency', currency: 'JPY'}}
  defaultValue={{start: 75, end: 100}} />
```

### HTML forms

RangeSlider supports the `startName` and `endName` props for integration with HTML forms.

```tsx example
<RangeSlider
  label="Range"
  defaultValue={{start: 12, end: 36}}
  startName="start"
  endName="end" />
```

## Labeling
Value labels are shown above the Slider by default, but they can also be moved to the side or hidden as needed.
The label text should be in sentence case.

```tsx example
<Flex direction="column" maxWidth="size-5000" gap="size-300">
  <RangeSlider label="Jeans price range" formatOptions={{style: 'currency', currency: 'USD'}} defaultValue={{start: 75, end: 100}} />
  <RangeSlider label="Shoes price range" formatOptions={{style: 'currency', currency: 'USD'}} labelPosition="side" defaultValue={{start: 50, end: 100}} />
  <RangeSlider label="Hats price range" formatOptions={{style: 'currency', currency: 'USD'}} showValueLabel={false} defaultValue={{start: 15, end: 30}} />
</Flex>
```

By default, the value label is formatted as a plain number. This can be customized using the following props.

* `showValueLabel`: Allows you to display or hide the value label.
* `formatOptions`: Allows you to customize the format of the value.
* `getValueLabel`: Allows you to provide a custom function to format the value label.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <RangeSlider
    label="Level range"
    showValueLabel={false}
    defaultValue={{start: 75, end: 100}} />

  <RangeSlider
    label="Cacao percentage"
    maxValue={1}
    step={0.001}
    formatOptions={{style: 'percent', minimumFractionDigits: 1}}
    defaultValue={{start: .75, end: 1}} />

  <RangeSlider
    label="Search radius"
    maxValue={200}
    getValueLabel={meters => `${meters.start}m to ${meters.end}m away`}
    defaultValue={{start: 15, end: 60}} />
</Flex>
```

### Accessibility

Depending on the visualization being used (i.e. depending on the `showValueLabel` prop), a `label`, `aria-label`, or `aria-labelledby` prop is required.

### Internationalization

To internationalize a Slider, a localized string should be passed to the `label` prop, `aria-label` prop, or value of the associated `aria-labelledby` element.

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the slider is automatically flipped. In addition,
Slider automatically uses the current locale to format the value label.

## Props

<PropTable component={docs.exports.RangeSlider} links={docs.links} />

## Visual options

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a RangeSlider.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<RangeSlider
  label="Search radius"
  formatOptions={{style: 'unit', unit: 'mile'}}
  defaultValue={{start: 15, end: 60}}
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Ranking</Heading>
      <Content>Search results are sorted by distance from city center.</Content>
    </ContextualHelp>
  } />
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/slider/#Disabled)

```tsx example
<RangeSlider label="Price filter" defaultValue={{start: 25, end: 50}} isDisabled />
```

---

### Packages @Adobe React Spectrum Docs Slider Slider (`packages/@adobe/react-spectrum/docs/slider/Slider.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/slider';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/slider/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Slider} from '@react-spectrum/slider';
```

---
category: Forms
after_version: 3.0.0-alpha.0
---

# Slider

<PageDescription>{docs.exports.Slider.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Slider']}
  sourceData={[{type: 'Spectrum', url: 'https://spectrum.adobe.com/page/slider/'}]}
  since="3.7.0" />

## Example

```tsx example
<Slider label="Cookies to buy" defaultValue={12} />
```

## Value

Sliders are controlled with the `value` prop and uncontrolled with the `defaultValue` prop. This value must fall between
the Slider's minimum and maximum values, which default to 0 and 100 respectively.

```tsx example
function Example() {
  let [value, setValue] = React.useState(25);
  return (
    <Flex gap="size-150" wrap>
      <Slider
        label="Cookies to buy (Uncontrolled)"
        defaultValue={25} />
      <Slider
        label="Cookies to buy (Controlled)"
        value={value}
        onChange={setValue} />
    </Flex>
  );
}
```

Alternatively, a different scale can be used by setting the `minValue` and `maxValue` props.

```tsx example
<Slider
  label="Cookies to buy"
  minValue={50}
  maxValue={150}
  defaultValue={100} />
```

The slider value can be formatted by using the `formatOptions` prop.
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.

```tsx example
<Slider
  label="Currency"
  formatOptions={{style: 'currency', currency: 'JPY'}}
  defaultValue={60} />
```

### HTML forms

Slider supports the `name` prop for integration with HTML forms.

```tsx example
<Slider
  label="Opacity"
  defaultValue={50}
  name="opacity" />
```

## Labeling
Value labels are shown above the Slider by default, but they can also be moved to the side or hidden as needed.
The label text should be in sentence case.

```tsx example
<Flex direction="column" maxWidth="size-5000" gap="size-300">
  <Slider label="Cookies to buy" defaultValue={25} />
  <Slider label="Donuts to buy" labelPosition="side" defaultValue={25} />
  <Slider label="Pastries to buy" showValueLabel={false} defaultValue={25} />
</Flex>
```

By default, the value label is formatted as a plain number. This can be customized using the following props.

* `showValueLabel`: Allows you to display or hide the value label.
* `formatOptions`: Allows you to customize the format of the value.
* `getValueLabel`: Allows you to provide a custom function to format the value label.

```tsx example
<Flex direction="column" maxWidth="size-3000" gap="size-300">
  <Slider
    label="Cookies to buy"
    showValueLabel={false}
    defaultValue={90} />
  <Slider
    label="Percent donus eaten"
    maxValue={1}
    step={0.001}
    formatOptions={{style: 'percent', minimumFractionDigits: 1}}
    defaultValue={0.891} />
  <Slider
    label="Donuts to buy"
    maxValue={60}
    getValueLabel={donuts => `${donuts} of 60 Donuts`} />
</Flex>
```

### Accessibility

Depending on the visualization being used (i.e. depending on the `showValueLabel` prop), a `label`, `aria-label`, or `aria-labelledby` prop is required.

### Internationalization

To internationalize a Slider, a localized string should be passed to the `label` prop, `aria-label` prop, or value of the associated `aria-labelledby` element.

For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the slider is automatically flipped. In addition,
Slider automatically uses the current locale to format the value label.

## Props

<PropTable component={docs.exports.Slider} links={docs.links} />

## Visual options

### Fill
[View guidelines](https://spectrum.adobe.com/page/slider/#Fill)

```tsx example
<Flex direction="column" gap="size-300">
  <Slider label="Opacity" maxValue={1} formatOptions={{style: 'percent'}} defaultValue={0.9} step={0.01} isFilled />
  <Slider label="Exposure" minValue={-5} maxValue={5} defaultValue={1.83} formatOptions={{signDisplay: 'always'}} step={0.01} fillOffset={0} isFilled />
</Flex>
```

### Gradient
[View guidelines](https://spectrum.adobe.com/page/slider/#Gradient)

```tsx example
<Slider label="Filter density" trackGradient={['white', 'rgba(177,141,32,1)']} defaultValue={.3} maxValue={1} step={0.01} formatOptions={{style: 'percent'}} isFilled  />
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a Slider.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<Slider
  label="Exposure"
  minValue={-100}
  maxValue={100}
  defaultValue={0}
  formatOptions={{signDisplay: 'always'}}
  isFilled
  fillOffset={0}
  contextualHelp={
    <ContextualHelp>
      <Heading>What is exposure?</Heading>
      <Content>Exposure adjusts how bright the image is.</Content>
    </ContextualHelp>
  } />
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/slider/#Disabled)

```tsx example
<Slider label="Cookies to share" defaultValue={25} isDisabled />
```

## Testing

The Slider features a draggable handle that the user can interact with to change its value.
Please see the following section in the testing docs for more information on how to simulate this action in your
test suite.

[Simulating move event](./testing.html#simulating-move-event)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/color/test/ColorArea.test.tsx) if you find that the above
isn't sufficient when resolving issues in your own test cases.

---

### Packages @Adobe React Spectrum Docs Statuslight StatusLight (`packages/@adobe/react-spectrum/docs/statuslight/StatusLight.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/statuslight';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/statuslight/package.json';

```jsx import
import {StatusLight} from '@react-spectrum/statuslight';
```

---
category: Status
keywords: [status light, visual indicator]
---

# StatusLight

<PageDescription>{docs.exports.StatusLight.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['StatusLight']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/status-light/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<StatusLight variant="positive">Ready</StatusLight>
```

## Content

A visible label can be provided by passing children. To indicate status, use the [variant](#variant) prop.

```tsx example
<StatusLight variant="positive">Semantic color</StatusLight>
<StatusLight variant="yellow">Label color</StatusLight>
```

### Accessibility
If a visible label isn't specified, an `aria-label` must be provided for accessibility. If the StatusLight is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

In cases where the status changes at runtime, it may be appropriate to add `role="status"` so that the status change will be announced politely by assistive technology.

### Internationalization

To internationalize a StatusLight, a localized string should be set as the child content of the StatusLight.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the StatusLight is automatically flipped.

## Props

<PropTable component={docs.exports.StatusLight} links={docs.links} />

## Visual options

### Variant
[View guidelines](https://spectrum.adobe.com/page/status-light/#Semantic-variants)

When status lights have a semantic meaning, they should use semantic colors.
Use the appropriate color to indicate status as follows.

```tsx example
<StatusLight variant="neutral">Gray: Archived, Deleted, Paused, Draft, Not Started, Ended</StatusLight>
<StatusLight variant="positive">Green: Approved, Complete, Success, New, Purchased, Licensed</StatusLight>
<StatusLight variant="notice">Orange: Needs Approval, Pending, Scheduled, Syncing, Indexing, Processing</StatusLight>
<StatusLight variant="negative">Red: Error, Alert, Rejected, Failed</StatusLight>
<StatusLight variant="info">Blue: Active, In Use, Live, Published</StatusLight>
```

When status lights are used to color code categories and labels commonly found in data visualization,
they use label colors. The ideal usage for these is when there are 8 or fewer categories or labels being color coded.
Use them in the following order to ensure the greatest possible color differences for multiple forms of color blindness:

```tsx example
<StatusLight variant="indigo">Indigo</StatusLight>
<StatusLight variant="celery">Celery</StatusLight>
<StatusLight variant="magenta">Magenta</StatusLight>
<StatusLight variant="yellow">Yellow</StatusLight>
<StatusLight variant="fuchsia">Fuchsia</StatusLight>
<StatusLight variant="seafoam">Seafoam</StatusLight>
<StatusLight variant="chartreuse">Chartreuse</StatusLight>
<StatusLight variant="purple">Purple</StatusLight>
```

### Disabled
[View guidelines](https://spectrum.adobe.com/page/status-light/#Disabled)

Use the `isDisabled` prop to match the state of a containing element.
Note that the `isDisabled` prop alters the visual style of the StatusLight,
but does not convey any state information to assistive technology.

```tsx example
<StatusLight variant="yellow" isDisabled >Yellow</StatusLight>
```

---

### Packages @Adobe React Spectrum Docs Steplist StepList (`packages/@adobe/react-spectrum/docs/steplist/StepList.mdx`)

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/steplist';
import {HeaderInfo, PropTable} from '@react-spectrum/docs';
import packageData from '@react-spectrum/steplist/package.json';

```jsx import
import {StepList} from '@react-spectrum/steplist';
```

---
category: Category Name
keywords: []
after_version: 3.0.0
---

# StepList

---

### Packages @Adobe React Spectrum Docs Switch Switch (`packages/@adobe/react-spectrum/docs/switch/Switch.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/switch';
import {HeaderInfo, PropTable, PageDescription} from '@react-spectrum/docs';
import packageData from '@react-spectrum/switch/package.json';

```jsx import
import {Switch} from '@react-spectrum/switch';
```

---
category: Forms
keywords: [switch, toggle, input]
---

# Switch

<PageDescription>{docs.exports.Switch.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Switch']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/switch/'}
  ]}
  since="3.0.0" />

## Example

```tsx example
<Switch>Low power mode</Switch>

```

## Content

Switches accept children, which are rendered as the label.

Switches are best used for communicating activation (e.g. on/off states), while [checkboxes](./Checkbox.html) are best used for communicating selection (e.g. multiple table rows).
Switches, unlike checkboxes, can't have an error state.

### Accessibility

In certain cases a visible label isn't needed. For example, a Switch located at the top of a panel which toggles the panels options on or off.
If a visible label isn't specified, an `aria-label` must be provided to the Switch for accessibility.
If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

```tsx example
<Switch aria-label="Low power mode" />
```

### Internationalization

To internationalize a Switch, a localized label should be passed to the `children` or `aria-label` prop.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the switch is automatically flipped.

## Value

Switches are not selected by default. The `defaultSelected` prop can be used to set the default state (uncontrolled).
Alternatively, the `isSelected` prop can be used to make the selected state controlled.

```tsx example
function Example() {
  let [selected, setSelection] = React.useState(false);

  return (
    <>
      <Switch
        defaultSelected>
        Low power mode (uncontrolled)
      </Switch>

      <Switch
        isSelected={selected}
        onChange={setSelection}>
        Low power mode (controlled)
      </Switch>
    </>
  )
}
```

### HTML forms

Switch supports the `name` and `value` props for integration with HTML forms.

```tsx example
<Switch name="power" value="low">Low power mode</Switch>
```

## Events

Switches accept a user defined `onChange` prop, triggered whenever the Switch is pressed.
The example below uses `onChange` to alert the user to changes in state.

```tsx example
function Example() {
  let [selected, setSelection] = React.useState(false);

  return (
    <>
      <Switch onChange={setSelection}>
        Switch Label
      </Switch>
      <div>The Switch is on: {selected.toString()}</div>
    </>
  );
}
```

## Props

<PropTable component={docs.exports.Switch} links={docs.links} />

## Visual options

### Disabled
[View guidelines](https://spectrum.adobe.com/page/switch/#Disabled)

```tsx example
<Switch isDisabled>Switch Label</Switch>
```

### Emphasized
[View guidelines](https://spectrum.adobe.com/page/switch/#Emphasized-or-not?)

```tsx example
<Switch isEmphasized defaultSelected>Switch Label</Switch>
```

### Read only

```tsx example
<Switch isReadOnly isSelected>Switch Label</Switch>
```

---

### Packages @Adobe React Spectrum Docs Table TableView (`packages/@adobe/react-spectrum/docs/table/TableView.mdx`)

{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/table';
import dndDocs from 'docs:@react-spectrum/dnd';
import tableUtil from 'docs:@react-aria/test-utils';
import tableTypes from 'docs:@react-stately/table';
import {HeaderInfo, PropTable, PageDescription, TypeLink, VersionBadge, ClassAPI} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-spectrum/table/package.json';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';

```jsx import
import {ActionButton} from '@react-spectrum/button';
import Add from '@spectrum-icons/workflow/Add';
import {Cell, Column, Row, TableView, TableBody, TableHeader} from '@react-spectrum/table';
import {Flex} from '@react-spectrum/layout';
```

---
category: Collections
keywords: [table, grid]
---

# TableView

<PageDescription>{docs.exports.TableView.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Cell', 'Column', 'Row', 'TableView', 'TableBody', 'TableHeader']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/table/'}
  ]}
  since="3.14.0" />

## Example
```tsx example
<TableView aria-label="Example table with static contents" selectionMode="multiple">
  <TableHeader>
    <Column>Name</Column>
    <Column>Type</Column>
    <Column align="end">Date Modified</Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>Games</Cell>
      <Cell>File folder</Cell>
      <Cell>6/7/2020</Cell>
    </Row>
    <Row>
      <Cell>Program Files</Cell>
      <Cell>File folder</Cell>
      <Cell>4/7/2021</Cell>
    </Row>
    <Row>
      <Cell>bootmgr</Cell>
      <Cell>System file</Cell>
      <Cell>11/20/2010</Cell>
    </Row>
    <Row>
      <Cell>log.txt</Cell>
      <Cell>Text Document</Cell>
      <Cell>1/18/2016</Cell>
    </Row>
  </TableBody>
</TableView>
```

## Content
TableView is a complex [collection component](collections.html) that is built up from many child elements including columns, rows, and cells. Columns are defined within a TableHeader element and rows are defined within a TableBody element. Rows contain Cell elements that correspond to each column. Cells can contain any element, allowing you to have focusable children within the TableView.

Basic usage of TableView, seen in the example above, shows the use of a static collection where the contents of the TableView is hard coded. Dynamic collections, as shown below, can be used when the options come from an external data source such as an API, or update over time. Providing the data in this way allows TableView to automatically cache the rendering of each item, which dramatically improves performance.

Columns and rows can be statically defined as children, or generated dynamically using a function based on the data passed to the `columns` or `items` prop respectively. Cells can also be statically defined as children, or generated dynamically based on the columns defined in the TableHeader.

Each column and row has a unique key defined by the data. In the example below, the `uid` property of the column object is used as the `key` for the Column element within the TableHeader. The `key` of each row element is implicitly defined by the id property of the row object. See [collections](collections.html#unique-keys) to learn more about keys in dynamic collections.

```tsx example
let columns = [
  {name: 'Name', uid: 'name'},
  {name: 'Type', uid: 'type'},
  {name: 'Date Modified', uid: 'date'}
];

let rows = [
  {id: 1, name: 'Games', date: '6/7/2020', type: 'File folder'},
  {id: 2, name: 'Program Files', date: '4/7/2021', type: 'File folder'},
  {id: 3, name: 'bootmgr', date: '11/20/2010', type: 'System file'},
  {id: 4, name: 'log.txt', date: '1/18/2016', type: 'Text Document'}
];

<TableView
  aria-label="Example table with dynamic content"
  maxWidth="size-6000">
  <TableHeader columns={columns}>
    {column => (
      <Column
        key={column.uid}
        align={column.uid === 'date' ? 'end' : 'start'}>
        {column.name}
      </Column>
    )}
  </TableHeader>
  <TableBody items={rows}>
    {item => (
      <Row>
        {columnKey => <Cell>{item[columnKey]}</Cell>}
      </Row>
    )}
  </TableBody>
</TableView>
```
### Layout
TableViews are often contained within a page layout that defines the size of the table. For example, a page might have a header or toolbar with a TableView below that fills the remaining vertical space. TableView is designed to scroll internally while the column headers remain fixed. Because of this, TableViews should not be placed within a scrollable container.

The example below shows how to use a [Flex](Flex.html) component to achieve the layout described above. Note the TableView uses the `flex` prop to fill the remainder of the available space.


```
/* Detailed source-code truncated for AI context efficiency. */
```

### Internationalization
To internationalize a TableView, all text content within the TableView should be localized. This includes the `aria-label` provided to the TableView if any.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of TableView is automatically flipped.

## Labeling
### Accessibility
An `aria-label` must be provided to the TableView for accessibility. If the TableView is labeled by a separate element, an `aria-labelledby` prop must be provided using the id of the labeling element instead.

By default, the first column of the TableView is used as the [row header](https://www.w3.org/TR/wai-aria-1.1/#rowheader) and is announced by assistive technology when navigating through the rows. You can override this behavior by providing the `isRowHeader` prop
to one or more Columns, allowing you to customize which columns should label the rows of the TableView.

The example below applies `isRowHeader` to the "First Name" and "Last Name" columns so that each row is announced with the person's full name (e.g. "John Doe").

```tsx example
<TableView aria-label="Example table with static contents">
  <TableHeader>
    <Column isRowHeader>First Name</Column>
    <Column isRowHeader>Last Name</Column>
    <Column align="end">Age</Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>John</Cell>
      <Cell>Doe</Cell>
      <Cell>45</Cell>
    </Row>
    <Row>
      <Cell>Jane</Cell>
      <Cell>Doe</Cell>
      <Cell>37</Cell>
    </Row>
    <Row>
      <Cell>Joe</Cell>
      <Cell>Schmoe</Cell>
      <Cell>67</Cell>
    </Row>
  </TableBody>
</TableView>
```

## Asynchronous loading
TableView supports loading data asynchronously, and will display a progress circle reflecting the current load state,
set by the `loadingState` prop. It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data.
See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Character {
  name: string,
  height: number,
  mass: number,
  birth_year: number
}

function AsyncTable() {
  let columns = [
    {name: 'Name', key: 'name'},
    {name: 'Height', key: 'height'},
    {name: 'Mass', key: 'mass'},
    {name: 'Birth Year', key: 'birth_year'}
  ];

  let list = useAsyncList<Character>({
    async load({signal, cursor}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=`, {signal});
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <TableView aria-label="example async loading table" height="size-3000">
      <TableHeader columns={columns}>
        {(column) => (
          <Column align={column.key !== 'name' ? 'end' : 'start'}>
            {column.name}
          </Column>
        )}
      </TableHeader>
      <TableBody
        items={list.items}
        loadingState={list.loadingState}
        onLoadMore={list.loadMore}>
        {(item) => (
          <Row key={item.name}>{(key) => <Cell>{item[key]}</Cell>}</Row>
        )}
      </TableBody>
    </TableView>
  );
}
```


## Selection

By default, TableView doesn't allow row selection but this can be enabled using the `selectionMode` prop.
Use `defaultSelectedKeys` to provide a default set of selected rows. Note that the value of the selected keys must match the `key` prop of the Row.

The example below enables multiple selection mode, and uses `defaultSelectedKeys` to select the rows with keys "2" and "4".

```tsx example
<TableView aria-label="Example table with multiple selection" selectionMode="multiple" defaultSelectedKeys={['2', '4']}>
  <TableHeader>
    <Column>Name</Column>
    <Column>Type</Column>
    <Column align="end">Level</Column>
  </TableHeader>
  <TableBody>
    <Row key="1">
      <Cell>Charizard</Cell>
      <Cell>Fire, Flying</Cell>
      <Cell>67</Cell>
    </Row>
    <Row key="2">
      <Cell>Blastoise</Cell>
      <Cell>Water</Cell>
      <Cell>56</Cell>
    </Row>
    <Row key="3">
      <Cell>Venusaur</Cell>
      <Cell>Grass, Poison</Cell>
      <Cell>83</Cell>
    </Row>
    <Row key="4">
      <Cell>Pikachu</Cell>
      <Cell>Electric</Cell>
      <Cell>100</Cell>
    </Row>
  </TableBody>
</TableView>
```

### Controlled selection

To programmatically control row selection, use the `selectedKeys` prop paired with the `onSelectionChange` callback. The `key` prop from the selected rows will
be passed into the callback when the row is pressed, allowing you to update state accordingly.

Here is how you would control selection for the above example.

```tsx example export=true
import type {Selection} from '@adobe/react-spectrum';

function PokemonTable(props) {
  let columns = [
    {name: 'Name', uid: 'name'},
    {name: 'Type', uid: 'type'},
    {name: 'Level', uid: 'level'}
  ];

  let rows = [
    {id: 1, name: 'Charizard', type: 'Fire, Flying', level: '67'},
    {id: 2, name: 'Blastoise', type: 'Water', level: '56'},
    {id: 3, name: 'Venusaur', type: 'Grass, Poison', level: '83'},
    {id: 4, name: 'Pikachu', type: 'Electric', level: '100'}
  ];

  let [selectedKeys, setSelectedKeys] = React.useState<Selection>(new Set([2]));

  return (
    <TableView aria-label="Table with controlled selection" selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys} {...props}>
      <TableHeader columns={columns}>
        {column => (
          <Column key={column.uid} align={column.uid === 'level' ? 'end' : 'start'}>
            {column.name}
          </Column>
        )}
      </TableHeader>
      <TableBody items={rows}>
        {item => (
          <Row>
            {columnKey => <Cell>{item[columnKey]}</Cell>}
          </Row>
        )}
      </TableBody>
    </TableView>
  );
}
```

### Single selection

To limit users to selecting only a single item at a time, `selectionMode` can be set to `single`.

```tsx example
// Using the same table as above
<PokemonTable selectionMode="single" />
```

### Disallow empty selection

TableView also supports a `disallowEmptySelection` prop which forces the user to have at least one row in the TableView selected at all times.
In this mode, if a single row is selected and the user presses it, it will not be deselected.

```tsx example
// Using the same table as above
<PokemonTable disallowEmptySelection />
```

### Disabled rows

You can disable specific rows by providing an array of keys to TableView via the `disabledKeys` prop. This will prevent rows from being selectable as shown in the example below.

```tsx example
// Using the same table as above
<PokemonTable selectionMode="multiple" disabledKeys={[3]} />
```

### Highlight selection

By default, TableView uses the checkbox selection style, which includes a checkbox in each row for selection. When the selectionStyle prop is set to `"highlight"`, the checkboxes are hidden,
and the selected rows are displayed with a highlighted background instead.

In addition to changing the appearance, the selection behavior also changes depending on the `selectionStyle` prop. In the default checkbox selection style, clicking, tapping, or pressing
the <Keyboard>Space</Keyboard> or <Keyboard>Enter</Keyboard> keys toggles selection for the focused row. Using the arrow keys moves focus but does not change selection.

In the highlight selection style, however, clicking a row with the mouse _replaces_ the selection with only that row. Using the arrow keys moves both focus and selection. To select multiple rows,
modifier keys such as <Keyboard>Ctrl</Keyboard>, <Keyboard>Cmd</Keyboard>, and <Keyboard>Shift</Keyboard> can be used. On touch screen devices, selection always behaves as toggle since modifier
keys may not be available.

These selection styles implement the behaviors defined in [Aria Practices](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/#keyboardinteraction).

```tsx example
<PokemonTable selectionMode="multiple" selectionStyle="highlight" />
```

## Row actions

TableView supports row actions via the `onAction` prop, which is useful for functionality such as navigation. When nothing is selected, the TableView performs actions by default when clicking or tapping a row.
Items may be selected using the checkbox, or by long pressing on touch devices. When at least one item is selected, the TableView is in selection mode,
and clicking or tapping a row toggles the selection. Actions may also be triggered via the <Keyboard>Enter</Keyboard> key, and selection using the <Keyboard>Space</Keyboard> key.

This behavior is slightly different in the highlight selection style, where single clicking selects the row and actions are performed via double click. Touch and keyboard behaviors are unaffected.

```tsx example
<Flex direction="column" gap="size-300">
  <PokemonTable aria-label="Pokemon table with row actions and checkbox selection" selectionMode="multiple" onAction={key => alert(`Opening item ${key}...`)} />
  <PokemonTable aria-label="Pokemon table with row actions and highlight selection" selectionMode="multiple" selectionStyle="highlight" onAction={key => alert(`Opening item ${key}...`)} />
</Flex>
```

### Links

Table rows may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Row>` component. Links behave the same way as described above for row actions depending on the `selectionMode` and `selectionStyle`.

```tsx example
<TableView aria-label="Bookmarks" selectionMode="multiple">
  <TableHeader>
    <Column>Name</Column>
    <Column>URL</Column>
    <Column>Date added</Column>
  </TableHeader>
  <TableBody>
    <Row href="https://adobe.com/" target="_blank">
      <Cell>Adobe</Cell>
      <Cell>https://adobe.com/</Cell>
      <Cell>January 28, 2023</Cell>
    </Row>
    <Row href="https://google.com/" target="_blank">
      <Cell>Google</Cell>
      <Cell>https://google.com/</Cell>
      <Cell>April 5, 2023</Cell>
    </Row>
    <Row href="https://nytimes.com/" target="_blank">
      <Cell>New York Times</Cell>
      <Cell>https://nytimes.com/</Cell>
      <Cell>July 12, 2023</Cell>
    </Row>
  </TableBody>
</TableView>
```

#### Client side routing

The `<Row>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sorting

TableView supports sorting its data when a column header is pressed. To designate that a Column should support sorting, provide it with
the `allowsSorting` prop. The TableView accepts a `sortDescriptor` prop that defines the current column key to sort by and the sort direction (ascending/descending).
When the user presses a sortable column header, the column's key and sort direction is passed into the `onSortChange` callback, allowing you to update the `sortDescriptor` appropriately.

This example performs client side sorting by passing a `sort` function to the [useAsyncList](react-aria:useAsyncList.html) hook.
See the docs for more information on how to perform server side sorting.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Column widths

By default, TableView divides the available space evenly among the columns. The `Column` component also supports four different width props that allow you to control column sizing behavior: `defaultWidth`, `width`, `minWidth`, and `maxWidth`.

The `width` and `defaultWidth` props define the width of a column. The former defines a controlled width, and the latter defines an uncontrolled width when the column is [resizable](#column-resizing). These props accept fixed pixel values, percentages of the total table width, or [fractional](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout#the_fr_unit) values (the `fr` unit), which represent a fraction of the available space. Columns without a defined width are equivalent to `1fr`.

The `minWidth` and `maxWidth` props define constraints on the size of a column, which may be defined either as fixed pixel values or as percentages of the total table width. These are respected when calculating the size of a column, and also provide limits for column resizing.

```tsx example
<TableView aria-label="Example table for column widths" maxWidth={320}>
  <TableHeader>
    <Column defaultWidth="1fr" align="start">Name</Column>
    <Column maxWidth={80}>Type</Column>
    <Column width={80}>Size</Column>
    <Column minWidth={100} align="end">Date Modified</Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>2021406_Proposal</Cell>
      <Cell>PDF</Cell>
      <Cell>86 KB</Cell>
      <Cell>April 12</Cell>
    </Row>
    <Row>
      <Cell>Budget Template</Cell>
      <Cell>XLS</Cell>
      <Cell>120 KB</Cell>
      <Cell>November 27</Cell>
    </Row>
    <Row>
      <Cell>Onboarding</Cell>
      <Cell>PPT</Cell>
      <Cell>472 KB</Cell>
      <Cell>January 7</Cell>
    </Row>
    <Row>
      <Cell>Welcome</Cell>
      <Cell>TXT</Cell>
      <Cell>24 KB</Cell>
      <Cell>February 11</Cell>
    </Row>
  </TableBody>
</TableView>
```

## Column Resizing

TableView supports resizable columns, allowing users to dynamically adjust the width of a column. To designate that a Column is resizable, provide it with the `allowsResizing` prop. This will render a draggable
resizer handle that becomes visible on hover. Keyboard, touch, and screen reader users can start resizing by interacting with the target column's header and selecting the "Resize column" option
from the dropdown.

### Width values

An initial, uncontrolled width can be provided to a Column using the `defaultWidth` prop. This allows the column width to freely shrink and grow in relation to other column widths. Alternatively, a controlled value can be provided by the `width` prop. The `minWidth` and `maxWidth` props allow you to restrict a Column's size. See [column widths](#column-widths) above for more details.

The example below illustrates how each of the column width props affects their respective column's resize behavior.

```tsx example
<TableView
  aria-label="TableView with resizable columns"
  maxWidth={320}
  height={210} >
  <TableHeader>
    {/*- begin highlight -*/}
    <Column key="file" allowsResizing maxWidth={500}>File Name</Column>
    <Column key="size" width={80}>Size</Column>
    <Column key="date" allowsResizing minWidth={100}>Date Modified</Column>
    {/*- end highlight -*/}
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>2022-Roadmap-Proposal-Revision-012822-Copy(2)</Cell>
      <Cell>214 KB</Cell>
      <Cell>November 27, 2022 at 4:56PM</Cell>
    </Row>
    <Row>
      <Cell>62259692_p0_master1200</Cell>
      <Cell>120 KB</Cell>
      <Cell>January 27, 2021 at 1:56AM</Cell>
    </Row>
    <Row>
      <Cell colSpan={3}>Total space: 334 KB</Cell>
    </Row>
  </TableBody>
</TableView>
```

### Resize events

TableView accepts an `onResize` prop which is triggered whenever a column resizer is moved by the user. This can be used in combination with the `width` prop to update a Column's width in a controlled fashion. TableView also accepts
an `onResizeEnd` prop, which is triggered when the user finishes a column resize operation. Both events receive a Map object containing the widths of every column in the TableView.

The example below uses `onResize` to update each of the TableView's controlled column widths. It also saves the finalized column widths to `localStorage` in `onResizeEnd`, allowing the TableView's state to be preserved between
page loads and refreshes.

```
/* Detailed source-code truncated for AI context efficiency. */
```


## Drag and drop <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

To enable drag and drop in a TableView, you must provide the drag and drop hooks sourced from <TypeLink links={dndDocs.links} type={dndDocs.exports.useDragAndDrop} /> to the TableView's `dragAndDropHooks` prop.
See the examples below for various common drag and drop use cases. For more information on `useDragAndDrop` and the various supported ways to perform a drag and drop interaction,
please see the [drag and drop documentation](dnd.html).

### Draggable TableView and droppable TableView

The example below demonstrates how to create a draggable TableView and a droppable TableView.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoTable />
```

### Handling folder drops

The example below replicates the previous example but demonstrates how to handle on item drops.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoTableFolder />
```

### Reorderable

The example below demonstrates how to make a TableView draggable and droppable at the same time. The TableView below supports reordering its own rows via drag and drop.
<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<ReorderableTable />
```

### Bi-directional dragging

The example below demonstrates how to create a pair of TableViews that supports dragging and dropping any items between each table, but disables
the ability to drop into a folder. Each table is internally reorderable.
<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragBetweenTablesExample />
```

### Overriding default drop operation

The example below demonstrates how to use `getDropOperation` to specify the default drop operation of the droppable table.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```
</details>

```tsx example
<DragIntoTablesDefaultCopy />
```

### Custom drag previews

By default, the drag preview for a dragged row will include the `textValue` provided to that row.
If no `textValue` was provided, it will default to the contents of the columns that are row headers, as specified by the `isRowHeader` prop on columns.
If no row header columns were specified, the first column will be used, as mentioned in the [Accessibility](#accessibility) section.

Use the `renderPreview` prop to provide a custom drag preview. `keys` and `draggedKey` are passed to this function, where `keys` includes all the keys of the items being dragged, and `draggedKey` is the key of the item the user initiated the drag from.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```

</details>

```tsx example
<CustomDragPreviewExample />
```

## Props

### TableView props

<PropTable component={docs.exports.TableView} links={docs.links} style={{marginBottom: '40px'}} />

### TableHeader props

<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(tableTypes.exports.TableHeaderProps.properties))
  }
}} links={tableTypes.links} style={{marginBottom: '40px'}} />

### Column props

<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(docs.exports.SpectrumColumnProps.properties))
  }
}} links={docs.links} style={{marginBottom: '40px'}} />

### TableBody props

<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(tableTypes.exports.TableBodyProps.properties))
  }
}} links={tableTypes.links} style={{marginBottom: '40px'}} />

### Row props

<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(tableTypes.exports.RowProps.properties))
  }
}} links={tableTypes.links} style={{marginBottom: '40px'}} />

### Cell props

<PropTable component={{
  props: {
    properties: Object.fromEntries(Object.entries(tableTypes.exports.CellProps.properties))
  }
}} links={tableTypes.links} />

## Visual options
### Column alignment
[View guidelines](https://spectrum.adobe.com/page/table/#Usage-guidelines)

```tsx example
<TableView aria-label="Example table for column alignment">
  <TableHeader>
    <Column align="start">Name</Column>
    <Column align="center">Type</Column>
    <Column align="end">Size</Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>2021406_Proposal</Cell>
      <Cell>PDF</Cell>
      <Cell>86 KB</Cell>
    </Row>
    <Row>
      <Cell>Budget Template</Cell>
      <Cell>XLS</Cell>
      <Cell>120 KB</Cell>
    </Row>
    <Row>
      <Cell>Onboarding</Cell>
      <Cell>PPT</Cell>
      <Cell>472 KB</Cell>
    </Row>
    <Row>
      <Cell>Welcome</Cell>
      <Cell>TXT</Cell>
      <Cell>24 KB</Cell>
    </Row>
  </TableBody>
</TableView>
```

### Column dividers
[View guidelines](https://spectrum.adobe.com/page/table/#Column-dividers)

```tsx example
<TableView aria-label="Example table for column dividers">
  <TableHeader>
    <Column align="start" showDivider>Name</Column>
    <Column showDivider>Type</Column>
    <Column align="end" showDivider>Size</Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>2021406_Proposal</Cell>
      <Cell>PDF</Cell>
      <Cell>86 KB</Cell>
    </Row>
    <Row>
      <Cell>Budget Template</Cell>
      <Cell>XLS</Cell>
      <Cell>120 KB</Cell>
    </Row>
    <Row>
      <Cell>Onboarding</Cell>
      <Cell>PPT</Cell>
      <Cell>472 KB</Cell>
    </Row>
    <Row>
      <Cell>Welcome</Cell>
      <Cell>TXT</Cell>
      <Cell>24 KB</Cell>
    </Row>
  </TableBody>
</TableView>
```

### Hide header
Individual column headers can be hidden by providing the `hideHeader` prop to the Column. A tooltip is rendered when the column header is focused
to compensate for the lack of a visual title. Note that the `hideHeader` prop is specifically intended for columns that contain ActionButtons instead
of text content.

```tsx example export=true
function TableExample(props) {
  let columns = [
    {name: 'First Name', key: 'firstName'},
    {name: 'Last Name', key: 'lastName'},
    {name: 'Add Info', key: 'addInfo'},
    {name: 'Age', key: 'age'}
  ];

  let rows = [
    {id: '1', firstName: 'John', lastName: 'Doe', age: '45'},
    {id: '2', firstName: 'Jane', lastName: 'Doe', age: '37'},
    {id: '3', firstName: 'Joe', lastName: 'Schmoe', age: '67'},
    {id: '4', firstName: 'Joe', lastName: 'Bloggs', age: '12'},
    {id: '5', firstName: 'Taylor', lastName: 'Rodriguez Lloyd-Atkinson', age: '83'}
  ];

  return (
    <TableView aria-label="Example table with hidden headers" maxWidth="size-6000" {...props}>
      <TableHeader columns={columns}>
        {column => (
          <Column
            hideHeader={column.key === 'addInfo'}
            align={column.key === 'age' ? 'end' : 'start'}
            showDivider={column.key === 'addInfo'}>
            {column.name}
          </Column>
        )}
      </TableHeader>
      <TableBody items={rows}>
        {item =>
          (<Row key={item.id}>
            {key =>
              key === 'addInfo'
              ? <Cell><ActionButton aria-label="Add Info" isQuiet><Add /></ActionButton></Cell>
              : <Cell>{item[key]}</Cell>
            }
          </Row>)
        }
      </TableBody>
    </TableView>
  );
}
```

### Quiet
[View guidelines](https://spectrum.adobe.com/page/table/#Standard-or-quiet)

```tsx example
// Using same setup as hide header example
<TableExample isQuiet />
```

### Density
The amount of vertical padding that each row contains can be modified by providing the `density` prop.

```tsx example
// Using same setup as hide header example
<Flex direction="column" gap="size-300">
  <TableExample density="compact" />
  <TableExample density="spacious" />
</Flex>
```

### Overflow mode
By default, text content that overflows its table cell will be truncated. You can have it wrap instead by passing `overflowMode="wrap"`
to the TableView.

```tsx example
// Using same setup as hide header example
<TableExample overflowMode="wrap" />
```

### Empty state
Use the `renderEmptyState` prop to customize what the TableView will display if there are no rows provided.

```tsx example
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';
import {Heading} from '@react-spectrum/text';

function renderEmptyState() {
  return (
    <IllustratedMessage>
      <NotFound />
      <Heading>No results</Heading>
      <Content>No results found</Content>
    </IllustratedMessage>
  );
}

<TableView aria-label="Example table for empty state" height="size-3000" renderEmptyState={renderEmptyState}>
  <TableHeader>
    <Column>Name</Column>
    <Column>Type</Column>
    <Column>Size</Column>
  </TableHeader>
  <TableBody>
    {[]}
  </TableBody>
</TableView>
```

### Nested columns

TableView supports nesting columns, allowing you to create column groups, or "tiered" column headers. Data for the leaf columns appears in each row of the table body.

```tsx example
<TableView aria-label="Example table for nested columns">
  <TableHeader>
    <Column title="Name">
      <Column isRowHeader>First Name</Column>
      <Column isRowHeader>Last Name</Column>
    </Column>
    <Column title="Information">
      <Column>Age</Column>
      <Column>Birthday</Column>
    </Column>
  </TableHeader>
  <TableBody>
    <Row>
      <Cell>Sam</Cell>
      <Cell>Smith</Cell>
      <Cell>36</Cell>
      <Cell>May 3</Cell>
    </Row>
    <Row>
      <Cell>Julia</Cell>
      <Cell>Jones</Cell>
      <Cell>24</Cell>
      <Cell>February 10</Cell>
    </Row>
    <Row>
      <Cell>Peter</Cell>
      <Cell>Parker</Cell>
      <Cell>28</Cell>
      <Cell>September 7</Cell>
    </Row>
    <Row>
      <Cell>Bruce</Cell>
      <Cell>Wayne</Cell>
      <Cell>32</Cell>
      <Cell>December 18</Cell>
    </Row>
  </TableBody>
</TableView>
```

Nested columns can also be defined dynamically using the function syntax and the `childColumns` prop.
The following example is the same as the example above, but defined dynamically.

```tsx example
interface ColumnDefinition {
  name: string,
  key: string,
  children?: ColumnDefinition[],
  isRowHeader?: boolean
}

let columns: ColumnDefinition[] = [
  {name: 'Name', key: 'name', children: [
    {name: 'First Name', key: 'first', isRowHeader: true},
    {name: 'Last Name', key: 'last', isRowHeader: true}
  ]},
  {name: 'Information', key: 'info', children: [
    {name: 'Age', key: 'age'},
    {name: 'Birthday', key: 'birthday'}
  ]}
];

let rows = [
  {id: 1, first: 'Sam', last: 'Smith', age: 36, birthday: 'May 3'},
  {id: 2, first: 'Julia', last: 'Jones', age: 24, birthday: 'February 10'},
  {id: 3, first: 'Peter', last: 'Parker', age: 28, birthday: 'September 7'},
  {id: 4, first: 'Bruce', last: 'Wayne', age: 32, birthday: 'December 18'}
];

<TableView aria-label="Example table for nested columns">
  <TableHeader columns={columns}>
    {column => (
      <Column isRowHeader={column.isRowHeader} childColumns={column.children}>
        {column.name}
      </Column>
    )}
  </TableHeader>
  <TableBody items={rows}>
    {item => (
      <Row>
        {columnKey => <Cell>{item[columnKey]}</Cell>}
      </Row>
    )}
  </TableBody>
</TableView>
```

## Testing

The TableView features automatic virtualization and may need specific mocks in a test environment to enable said virtualization properly.
It also features long press interactions on its rows depending on the row actions provided and if user is interacting with the list on
a touch device. Please see the following sections in the testing docs for more information on how to handle these
behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/table/test/Table.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common table interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the table tester and a sample of how you could use it in your test suite.

```ts
// TableView.test.ts
import {render, within} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse', advanceTimer: jest.advanceTimersByTime});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/TableView.html#testing

it('TableView can toggle row selection', async function () {
  // Render your test component/app and initialize the table tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <TableView data-testid="test-table" selectionMode="multiple">
      ...
      </TableView>
    </Provider>
  );
  let tableTester = testUtilUser.createTester('Table', {root: getByTestId('test-table')});
  expect(tableTester.getSelectedRows()).toHaveLength(0);

  await tableTester.toggleSelectAll();
  expect(tableTester.getSelectedRows()).toHaveLength(10);

  await tableTester.toggleRowSelection({row: 2});
  expect(tableTester.getSelectedRows()).toHaveLength(9);
  let checkbox = within(tableTester.getRows()[2]).getByRole('checkbox');
  expect(checkbox).not.toBeChecked();

  await tableTester.toggleSelectAll();
  expect(tableTester.getSelectedRows()).toHaveLength(10);
  expect(checkbox).toBeChecked();

  await tableTester.toggleSelectAll();
  expect(tableTester.getSelectedRows()).toHaveLength(0);
});
```

<ClassAPI links={tableUtil.links} class={tableUtil.exports.TableTester} />

---

--- METRICS ---
- Files Extracted: 95
- Estimated Token Budget: ~210602 tokens
- Canonical Reference: https://codewiki.google/github.com/adobe/react-spectrum
