Skip to content
20 changes: 20 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Draggable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client";
import React from 'react';
import {useDrag} from '@react-aria/dnd';

export 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>
);
}
51 changes: 51 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/DropTarget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import React, {JSX} from 'react';
import type {TextDropItem} from '@react-aria/dnd';
import {useDrop} from '@react-aria/dnd';

interface DroppedItem {
message: string;
style?: 'bold' | 'italic';
}

export function DropTarget() {
let [dropped, setDropped] = React.useState<DroppedItem[] | null>(null);
let ref = React.useRef(null);
let {dropProps, isDropTarget} = useDrop({
ref,
async onDrop(e) {
let items = await Promise.all(
(e.items as TextDropItem[])
.filter(item => item.kind === 'text' && (item.types.has('text/plain') || item.types.has('my-app-custom-type')))
.map(async item => {
if (item.types.has('my-app-custom-type')) {
return JSON.parse(await item.getText('my-app-custom-type'));
} else {
return {message: await item.getText('text/plain')};
}
})
);
setDropped(items);
}
});

let message: JSX.Element[] = [<div>{`Drop here`}</div>];
if (dropped) {
message = dropped.map((d, index) => {
let m = d.message;
if (d.style === 'bold') {
message = [<strong>{m}</strong>];
} else if (d.style === 'italic') {
message = [<em>{m}</em>];
}
return <div key={index}>{message}</div>;
});
}

return (
<div {...dropProps} role="button" tabIndex={0} ref={ref} className={`droppable ${isDropTarget ? 'target' : ''}`}>
{message}
</div>
);
}
48 changes: 48 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/FocusRing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{/* Copyright 2025 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 '../../src/Layout';
export default Layout;
import {GroupedPropTable} from '../../src/PropTable';
import {FunctionAPI} from '../../src/FunctionAPI';
import docs from 'docs:@react-aria/focus';

export const section = 'Focus';

# FocusRing

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

## Introduction

`FocusRing` is a utility component that can be used to apply a CSS class when an element has keyboard focus.
This helps keyboard users determine which element on a page or in an application has keyboard focus as they
navigate around. Focus rings are only visible when interacting with a keyboard so as not to distract mouse
and touch screen users. When we are unable to detect if the user is using a mouse or touch screen, such as
switching in from a different tab, we show the focus ring.

If CSS classes are not being used for styling, see [useFocusRing](useFocusRing.html) for a hooks version.

## Props

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

## Example

This example shows how to use `<FocusRing>` to apply a CSS class when keyboard focus is on a button.

```tsx render files={["packages/dev/s2-docs/pages/react-aria/FocusRingExample.css"]}
'use client';
import {FocusRing} from '@react-aria/focus';
import './FocusRingExample.css';

<FocusRing focusRingClass="focus-ring">
<button className="button">Test</button>
</FocusRing>
```
14 changes: 14 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/FocusRingExample.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.button {
-webkit-appearance: none;
appearance: none;
background: green;
border: none;
color: white;
font-size: 14px;
padding: 4px 8px;
}

.button.focus-ring {
outline: 2px solid dodgerblue;
outline-offset: 2px;
}
130 changes: 130 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/FocusScope.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{/* Copyright 2025 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 '../../src/Layout';
export default Layout;
import {GroupedPropTable} from '../../src/PropTable';
import {FunctionAPI} from '../../src/FunctionAPI';
import docs from 'docs:@react-aria/focus';

export const section = 'Focus';

# FocusScope

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

## Introduction

`FocusScope` is a utility component that can be used to manage focus for its descendants.
When the `contain` prop is set, focus is contained within the scope. This is useful when
implementing overlays like modal dialogs, which should not allow focus to escape them while open.
In addition, the `restoreFocus` prop can be used to restore focus back to the previously focused
element when the focus scope unmounts, for example, back to a button which opened a dialog.
A FocusScope can also optionally auto focus the first focusable element within it on mount
when the `autoFocus` prop is set.

The <TypeLink links={docs.links} type={docs.exports.useFocusManager} /> hook can also be used
in combination with a FocusScope to programmatically move focus within the scope. For example,
arrow key navigation could be implemented by handling keyboard events and using a focus manager
to move focus to the next and previous elements.

## Props

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

## FocusManager Interface

To get a focus manager, call the <TypeLink links={docs.links} type={docs.exports.useFocusManager} /> hook
from a component within the FocusScope. A focus manager supports the following methods:

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

## Example

A basic example of a focus scope that contains focus within it is below. Clicking the "Open"
button mounts a FocusScope, which auto focuses the first input inside it. Once open, you can
press the <Keyboard>Tab</Keyboard> key to move within the scope, but focus is contained inside. Clicking the "Close"
button unmounts the focus scope, which restores focus back to the button.

{/* Not implemented yet */}
{/* For a full example of building a modal dialog, see [useDialog](useDialog.html). */}

```tsx render
'use client';
import React from 'react';
import {FocusScope} from '@react-aria/focus';

function Example() {
let [isOpen, setOpen] = React.useState(false);
return (
<>
<button onClick={() => setOpen(true)}>Open</button>
{isOpen &&
<FocusScope contain restoreFocus autoFocus>
<label htmlFor="first-input">First Input</label>
<input id="first-input" />
<label htmlFor="second-input">Second Input</label>
<input id="second-input" />
<button onClick={() => setOpen(false)}>Close</button>
</FocusScope>
}
</>
);
}
```

## useFocusManager Example

This example shows how to use `useFocusManager` to programmatically move focus within a
`FocusScope`. It implements a basic toolbar component, which allows using the left and
right arrow keys to move focus to the previous and next buttons. The `wrap` option is
used to make focus wrap around when it reaches the first or last button.

```tsx render
'use client';
import {FocusScope} from '@react-aria/focus';
import {useFocusManager} from '@react-aria/focus';

function Toolbar(props) {
return (
<div role="toolbar">
<FocusScope>
{props.children}
</FocusScope>
</div>
);
}

function ToolbarButton(props) {
let focusManager = useFocusManager();
let onKeyDown = (e) => {
switch (e.key) {
case 'ArrowRight':
focusManager.focusNext({wrap: true});
break;
case 'ArrowLeft':
focusManager.focusPrevious({wrap: true});
break;
}
};

return (
<button
onKeyDown={onKeyDown}>
{props.children}
</button>
);
}

<Toolbar>
<ToolbarButton>Cut</ToolbarButton>
<ToolbarButton>Copy</ToolbarButton>
<ToolbarButton>Paste</ToolbarButton>
</Toolbar>
```
40 changes: 40 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/I18nProvider.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{/* Copyright 2025 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 '../../src/Layout';
export default Layout;
import {FunctionAPI} from '../../src/FunctionAPI';
import docs from 'docs:@react-aria/i18n';

export const section = 'Internationalization';
export const description = 'Implementing collections in React Aria';


# I18nProvider

## Introduction

`I18nProvider` allows you to override the default locale as determined by the browser/system setting
with a locale defined by your application (e.g. application setting). This should be done by wrapping
your entire application in the provider, which will be cause all child elements to receive the new locale
information via [useLocale](useLocale.html).

## Props

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

## Example

```tsx
import {I18nProvider} from '@react-aria/i18n';

<I18nProvider locale="fr-FR">
<YourApp />
</I18nProvider>
```
25 changes: 25 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/MyToastRegion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';
import React from 'react';
import {UNSTABLE_ToastRegion as ToastRegion, UNSTABLE_Toast as Toast, UNSTABLE_ToastQueue as ToastQueue, UNSTABLE_ToastContent as ToastContent, Button, Text} from 'react-aria-components';

// Define the type for your toast content.
interface MyToastContent {
title: string,
description?: string
}

export function MyToastRegion({queue}: {queue: ToastQueue<MyToastContent>}) {
return (
<ToastRegion queue={queue}>
{({toast}) => (
<Toast toast={toast}>
<ToastContent>
<Text slot="title">{toast.content.title}</Text>
<Text slot="description">{toast.content.description}</Text>
</ToastContent>
<Button slot="close">x</Button>
</Toast>
)}
</ToastRegion>
);
}
Loading