+ );
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/DropTarget.tsx b/packages/dev/s2-docs/pages/react-aria/DropTarget.tsx
new file mode 100644
index 00000000000..2f4cb2e69ea
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/DropTarget.tsx
@@ -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(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[] = [
{`Drop here`}
];
+ if (dropped) {
+ message = dropped.map((d, index) => {
+ let m = d.message;
+ if (d.style === 'bold') {
+ message = [{m}];
+ } else if (d.style === 'italic') {
+ message = [{m}];
+ }
+ return
{message}
;
+ });
+ }
+
+ return (
+
+ {message}
+
+ );
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/FocusRing.mdx b/packages/dev/s2-docs/pages/react-aria/FocusRing.mdx
new file mode 100644
index 00000000000..52d8a4aac79
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/FocusRing.mdx
@@ -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
+
+{docs.exports.FocusRing.description}
+
+## 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
+
+
+
+## Example
+
+This example shows how to use `` 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';
+
+
+
+
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/FocusRingExample.css b/packages/dev/s2-docs/pages/react-aria/FocusRingExample.css
new file mode 100644
index 00000000000..3d335cd4e5b
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/FocusRingExample.css
@@ -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;
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx b/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx
new file mode 100644
index 00000000000..bf41919a10d
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx
@@ -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
+
+{docs.exports.FocusScope.description}
+
+## 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 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
+
+
+
+## FocusManager Interface
+
+To get a focus manager, call the hook
+from a component within the FocusScope. A focus manager supports the following methods:
+
+
+
+## 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 Tab 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 (
+ <>
+
+ {isOpen &&
+
+
+
+
+
+
+
+ }
+ >
+ );
+}
+```
+
+## 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 (
+
+
+ {props.children}
+
+
+ );
+}
+
+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 (
+
+ );
+}
+
+
+ Cut
+ Copy
+ Paste
+
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/I18nProvider.mdx b/packages/dev/s2-docs/pages/react-aria/I18nProvider.mdx
new file mode 100644
index 00000000000..9bdc658f95d
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/I18nProvider.mdx
@@ -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
+
+
+
+## Example
+
+```tsx
+import {I18nProvider} from '@react-aria/i18n';
+
+
+
+
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/MyToastRegion.tsx b/packages/dev/s2-docs/pages/react-aria/MyToastRegion.tsx
new file mode 100644
index 00000000000..3e5e733fe74
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/MyToastRegion.tsx
@@ -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}) {
+ return (
+
+ {({toast}) => (
+
+
+ {toast.content.title}
+ {toast.content.description}
+
+
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/PortalProvider.mdx b/packages/dev/s2-docs/pages/react-aria/PortalProvider.mdx
new file mode 100644
index 00000000000..c161d7d7b79
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/PortalProvider.mdx
@@ -0,0 +1,171 @@
+{/* 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 docs from 'docs:@react-aria/overlays';
+import {FunctionAPI} from '../../src/FunctionAPI';
+
+export const section = 'Server Side Rendering';
+
+# PortalProvider
+
+{docs.exports.UNSAFE_PortalProvider.description}
+
+## Introduction
+
+`UNSAFE_PortalProvider` is a utility wrapper component that can be used to set where components like
+Modals, Popovers, Toasts, and Tooltips will portal their overlay element to. This is typically used when
+your app is already portalling other elements to a location other than the `document.body` and thus requires
+your React Aria components to send their overlays to the same container.
+
+Please note that `UNSAFE_PortalProvider` is considered `UNSAFE` because it is an escape hatch, and there are
+many places that an application could portal to. Not all of them will work, either with styling, accessibility,
+or for a variety of other reasons. Typically, it is best to portal to the root of the entire application, e.g. the `body` element,
+outside of any possible overflow or stacking contexts. We envision `UNSAFE_PortalProvider` being used to group all of the portalled
+elements into a single container at the root of the app or to control the order of children of the `body` element, but you may have use cases
+that need to do otherwise.
+
+## Props
+
+
+
+## Example
+
+The example below shows how you can use `UNSAFE_PortalProvider` to portal your Toasts to an arbitrary container. Note that
+the Toast in this example is taken directly from the [React Aria Components Toast documentation](Toast.html#example), please visit that page for
+a detailed explanation of its implementation.
+
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/MyToastRegion.tsx"]}
+'use client';
+import React from 'react';
+import {Button} from 'vanilla-starter/Button';
+import {MyToastRegion} from './MyToastRegion.tsx'
+import {UNSAFE_PortalProvider} from '@react-aria/overlays';
+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
+}
+
+// Create a global ToastQueue.
+const queue = new ToastQueue();
+
+// See the above Toast docs link for the ToastRegion implementation
+function App() {
+ let container = React.useRef(null);
+ return (
+ <>
+ container.current}>
+
+
+
+
+ Toasts are portalled here!
+
+ >
+ );
+}
+
+
+```
+
+```css render hidden
+.react-aria-ToastRegion {
+ position: unset;
+ bottom: 16px;
+ right: 16px;
+ display: flex;
+ flex-direction: column-reverse;
+ gap: 8px;
+ border-radius: 8px;
+ outline: none;
+
+ &[data-focus-visible] {
+ outline: 2px solid var(--focus-ring-color);
+ outline-offset: 2px;
+ }
+}
+
+.react-aria-Toast {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ background: var(--highlight-background);
+ color: white;
+ padding: 12px 16px;
+ border-radius: 8px;
+ outline: none;
+
+ &[data-focus-visible] {
+ outline: 2px solid var(--focus-ring-color);
+ outline-offset: 2px;
+ }
+
+ .react-aria-ToastContent {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 auto;
+ min-width: 0px;
+
+ [slot=title] {
+ font-weight: bold;
+ }
+ }
+
+ .react-aria-Button[slot=close] {
+ flex: 0 0 auto;
+ background: none;
+ border: none;
+ appearance: none;
+ border-radius: 50%;
+ height: 32px;
+ width: 32px;
+ font-size: 16px;
+ border: 1px solid var(--highlight-foreground);
+ color: white;
+ padding: 0;
+ outline: none;
+
+ &[data-focus-visible] {
+ box-shadow: 0 0 0 2px var(--highlight-background), 0 0 0 4px var(--highlight-foreground);
+ }
+
+ &[data-pressed] {
+ background: var(--highlight-pressed);
+ }
+ }
+}
+
+```
+
+## Contexts
+
+The `getContainer` set by the nearest PortalProvider can be accessed by calling `useUNSAFE_PortalContext`. This can be
+used by custom overlay components to ensure that they are also being consistently portalled throughout your app.
+
+
+
+```tsx
+import {useUNSAFE_PortalContext} from '@react-aria/overlays';
+
+function MyOverlay(props) {
+ let {children} = props;
+ let {getContainer} = useUNSAFE_PortalContext();
+ return ReactDOM.createPortal(children, getContainer());
+}
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/SSRProvider.mdx b/packages/dev/s2-docs/pages/react-aria/SSRProvider.mdx
new file mode 100644
index 00000000000..37f23f1bbbe
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/SSRProvider.mdx
@@ -0,0 +1,41 @@
+{/* 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 docs from 'docs:@react-aria/ssr';
+
+export const section = 'Server Side Rendering';
+export const description = 'Implementing collections in React Aria';
+
+# SSRProvider
+
+## Introduction
+
+If you're using React 16 or 17, `SSRProvider` should be used as a wrapper for the entire application during server side rendering.
+It works together with the [useId](useId.html) hook to ensure that auto generated ids are consistent
+between the client and server by resetting the id internal counter on each request.
+See the [server side rendering](ssr.html) docs for more information.
+
+**Note**: if you're using React 18 or newer, `SSRProvider` is not necessary and can be removed from your app. React Aria uses the
+[React.useId](https://react.dev/reference/react/useId) hook internally when using React 18, which ensures ids are consistent.
+
+## Props
+
+
+
+## Example
+
+```tsx
+import {SSRProvider} from '@react-aria/ssr';
+
+
+
+
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx b/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx
new file mode 100644
index 00000000000..14fb52ee5fe
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx
@@ -0,0 +1,67 @@
+{/* 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 docs from 'docs:@react-aria/visually-hidden';
+import {FunctionAPI} from '../../src/FunctionAPI';
+
+export const section = 'Utilities';
+
+# VisuallyHidden
+
+{docs.exports.VisuallyHidden.description}
+
+## Introduction
+
+`VisuallyHidden` is a utility component that can be used to hide its children visually,
+while keeping them visible to screen readers and other assistive technology. This would
+typically be used when you want to take advantage of the behavior and semantics of a
+native element like a checkbox or radio button, but replace it with a custom styled
+element visually.
+
+## Props
+
+
+
+{/* not implemented yet */}
+{/* ## Example
+
+See [useRadioGroup](useRadioGroup.html#styling) and [useCheckbox](useCheckbox.html#styling)
+for examples of using `VisuallyHidden` to hide native form elements visually. */}
+
+## Hook
+
+In order to allow additional rendering flexibility, the `useVisuallyHidden` hook can be
+used in custom components instead of the `VisuallyHidden` component. It supports the same
+options as the component, and returns props to spread onto the element that should be hidden.
+
+
+
+```tsx
+import {useVisuallyHidden} from '@react-aria/visually-hidden';
+
+let {visuallyHiddenProps} = useVisuallyHidden();
+
+
I am hidden
+```
+
+## Gotchas
+
+VisuallyHidden is positioned absolutely, so it needs a positioned ancestor. Otherwise, it will be positioned relative to the nearest positioned ancestor, which may be the body, causing undesired scroll bars to appear.
+
+```tsx
+
+```
+
diff --git a/packages/dev/s2-docs/pages/react-aria/mergeProps.mdx b/packages/dev/s2-docs/pages/react-aria/mergeProps.mdx
new file mode 100644
index 00000000000..fee98fa10a5
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/mergeProps.mdx
@@ -0,0 +1,70 @@
+{/* 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 docs from 'docs:@react-aria/utils';
+import {FunctionAPI} from '../../src/FunctionAPI';
+
+export const section = 'Utilities';
+
+# mergeProps
+
+{docs.exports.mergeProps.description}
+
+## API
+
+
+
+## Introduction
+
+`mergeProps` is a utility function that combines multiple props objects together in a smart way.
+This can be useful when you need to combine the results of multiple react-aria hooks onto a single
+element. For example, both hooks may return the same event handlers, class names, or ids, and only
+one of these can be applied. `mergeProps` handles combining these props together so that multiple
+event handlers will be chained, multiple classes will be combined, and ids will be deduplicated.
+For all other props, the last prop object overrides all previous ones.
+
+## Example
+
+```tsx
+import {mergeProps} from '@react-aria/utils';
+
+let a = {
+ className: 'foo',
+ onKeyDown(e) {
+ if (e.key === 'Enter') {
+ console.log('enter')
+ }
+ }
+};
+
+let b = {
+ className: 'bar',
+ onKeyDown(e) {
+ if (e.key === ' ') {
+ console.log('space')
+ }
+ }
+};
+
+let merged = mergeProps(a, b);
+```
+
+The result of the above example will be equivalent to this:
+
+```tsx
+let merged = {
+ className: 'foo bar',
+ onKeyDown(e) {
+ a.onKeyDown(e);
+ b.onKeyDown(e);
+ }
+};
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/useClipboard.mdx b/packages/dev/s2-docs/pages/react-aria/useClipboard.mdx
new file mode 100644
index 00000000000..e044de4e0b1
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useClipboard.mdx
@@ -0,0 +1,417 @@
+{/* 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/dnd';
+import sharedDocs from 'docs:@react-types/shared/src/dnd.d.ts';
+export const section = 'Drag and Drop';
+
+# useClipboard
+
+{docs.exports.useClipboard.description}
+
+## API
+
+
+
+## Introduction
+
+Copy and paste is a common way to transfer data between locations, either within or between apps. Browsers support copy and paste of selected text content by default, but rich objects with custom data can also be copied and pasted using the [clipboard events](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent) API. For example, an app could support copying and pasting a selected card representing a rich object to a new location, or allow a user to paste files from their device to upload them. This can provide a keyboard accessible alternative to drag and drop.
+
+The hook provides a simple way to implement copy and paste for a focusable element. When focused, users can press keyboard shortcuts like ⌘C and ⌘V, or even use the browser's "Copy" and "Paste" menu commands, to trigger clipboard events. Multiple items can be copied and pasted at once, each represented in one or more different data formats. Because it uses native browser APIs under the hood, copy and paste uses the operating system clipboard, which means it works between applications (e.g. Finder, Windows Explorer, a native email app, etc.) in addition to within the app.
+
+## Example
+
+This example shows a simple focusable element which supports copying a string when focused, and another element which supports pasting plain text.
+
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/useClipboardExample.css"]}
+'use client';
+import React from 'react';
+import type {TextDropItem} from '@react-aria/dnd';
+import {useClipboard} from '@react-aria/dnd';
+import './useClipboardExample.css';
+import 'vanilla-starter/theme.css';
+
+function Copyable() {
+ let {clipboardProps} = useClipboard({
+ getItems() {
+ return [{
+ 'text/plain': 'Hello world'
+ }];
+ }
+ });
+
+ return (
+
+```
+
+## Copy data
+
+Data to copy can be provided in multiple formats at once. This allows the destination where the user pastes to choose the data that it understands. For example, you could serialize a complex object as JSON in a custom format for use within your own application, and also provide plain text and/or rich HTML fallbacks that can be used when a user pastes in an external application (e.g. an email message).
+
+This can be done by returning multiple keys for an item from the `getItems` function. Types can either be a standard [mime type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) for interoperability with external applications, or a custom string for use within your own app.
+
+In addition to providing items in multiple formats, you can also return multiple drag items from `getItems` to transfer multiple objects in a single copy and paste operation.
+
+This example copies two items, each of which contains representations as plain text, HTML, and a custom app-specific data format. Pasting on the target will use the custom data format to render formatted items. If you paste in an external application supporting rich text, the HTML representation will be used. Dropping in a text editor will use the plain text format.
+
+```tsx render
+'use client';
+import React from 'react';
+import {useClipboard} from '@react-aria/dnd';
+
+function Copyable() {
+ let {clipboardProps} = useClipboard({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world',
+ 'text/html': 'hello world',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'hello world',
+ style: 'bold'
+ })
+ }, {
+ 'text/plain': 'foo bar',
+ 'text/html': 'foo bar',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'foo bar',
+ style: 'italic'
+ })
+ }];
+ }
+ });
+
+ return (
+
+///- end collapse -///
+```
+
+## Paste data
+
+`useClipboard` allows users to paste one or more items, each of which contains data to be pasted. There are three kinds of items:
+
+* `text` – represents data inline as a string in one or more formats
+* `file` – references a file on the user's device
+* `directory` – references the contents of a directory
+
+### Text
+
+A represents textual data in one or more different formats. These may be either standard [mime types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) or custom app-specific formats. Representing data in multiple formats allows drop targets both within and outside an application to choose data in a format that they understand. For example, a complex object may be serialized in a custom format for use within an application, with fallbacks in plain text and/or rich HTML that can be used when a user drops data from an external application.
+
+The example below works with the above `Copyable` example using a custom app-specific data format to transfer rich data. If no such data is available, it falls back to pasting plain text data.
+
+```tsx render
+'use client';
+import React from 'react';
+import {useClipboard} from '@react-aria/dnd';
+
+///- begin collapse -///
+function Copyable() {
+ let {clipboardProps} = useClipboard({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world',
+ 'text/html': 'hello world',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'hello world',
+ style: 'bold'
+ })
+ }, {
+ 'text/plain': 'foo bar',
+ 'text/html': 'foo bar',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'foo bar',
+ style: 'italic'
+ })
+ }];
+ }
+ });
+
+ return (
+
+///- end collapse -///
+```
+### Files
+A references a file on the user's device. It includes the name and mime type of the file, and methods to read the contents as plain text, or retrieve a native [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object which can be attached to form data for uploading.
+This example accepts JPEG and PNG image files, and renders them by creating a local [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL).
+```tsx render
+'use client';
+import React from 'react';
+import {useClipboard} from '@react-aria/dnd';
+import type {FileDropItem} from '@react-aria/dnd';
+
+function Pasteable() {
+ let [file, setFile] = React.useState(null);
+ let {clipboardProps} = useClipboard({
+ async onPaste(items) {
+ let item = items.find(item => item.kind === 'file' && (item.type === 'image/jpeg' || item.type === 'image/png')) as FileDropItem;
+ if (item) {
+ setFile(URL.createObjectURL(await item.getFile()));
+ }
+ }
+ });
+ return (
+
+ {file ? : 'Paste image here'}
+
+ );
+}
+```
+### Directories
+A references the contents of a directory on the user's device. It includes the name of the directory, as well as a method to iterate through the files and folders within the directory. The contents of any folders within the directory can be accessed recursively.
+The `getEntries` method returns an [async iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) object, which can be used in a `for await...of` loop. This provides each item in the directory as either a or , and you can access the contents of each file as discussed above.
+This example renders the file names within a dropped directory in a grid.
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/useClipboardGrid.css"]}
+'use client';
+import React from 'react';
+import {useClipboard} from '@react-aria/dnd'
+import type {DirectoryDropItem} from '@react-aria/dnd';
+import File from '@react-spectrum/s2/icons/File';
+import Folder from '@react-spectrum/s2/icons/Folder';
+import './useClipboardGrid.css';
+
+function Pasteable() {
+ let [files, setFiles] = React.useState(null);
+ let {clipboardProps} = useClipboard({
+ async onPaste(items) {
+ // Find the first dropped item that is a directory.
+ let dir = items.find(item => item.kind === 'directory') as DirectoryDropItem;
+ if (dir) {
+ // Read entries in directory and update state with relevant info.
+ let files = [];
+ for await (let entry of dir.getEntries()) {
+ files.push({
+ name: entry.name,
+ kind: entry.kind
+ });
+ }
+ setFiles(files);
+ }
+ }
+ });
+ let contents = <>Paste directory here>;
+ if (files) {
+ contents = (
+
+ {files.map(f => (
+
+ {f.kind === 'directory' ? : }
+ {f.name}
+
+ ))}
+
+ );
+ }
+ return (
+
+ {contents}
+
+ );
+}
+```
+## Disabling copy and paste
+If you need to temporarily disable copying and pasting, you can pass the `isDisabled` option to `useClipboard`. This will prevent copying and pasting on the element until it is re-enabled.
+```tsx render
+'use client';
+import React from 'react';
+import type {TextDropItem} from '@react-aria/dnd';
+import {useClipboard} from '@react-aria/dnd';
+
+function Copyable() {
+ let {clipboardProps} = useClipboard({
+ getItems() {
+ return [{
+ 'text/plain': 'Hello world'
+ }];
+ },
+ /*- begin highlight -*/
+ isDisabled: true
+ /*- end highlight -*/
+ });
+ return (
+
+```
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/useClipboardExample.css b/packages/dev/s2-docs/pages/react-aria/useClipboardExample.css
new file mode 100644
index 00000000000..e4412a91ecf
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useClipboardExample.css
@@ -0,0 +1,29 @@
+[role=textbox] {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--background-color);
+ border: 1px solid var(--border-color);
+ padding: 10px;
+ margin-right: 20px;
+ border-radius: 8px;
+ color: var(--color-white);
+}
+
+[role=textbox]:focus {
+ outline: none;
+ border-color: var(--focus-ring-color);
+ box-shadow: 0 0 0 1px var(--focus-ring-color);
+}
+
+[role=textbox] kbd {
+ display: inline-block;
+ margin-left: 10px;
+ padding: 0 4px;
+ background: var(--background-color);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ font-size: small;
+ letter-spacing: .2em;
+ color: var(--color-white);
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/useClipboardGrid.css b/packages/dev/s2-docs/pages/react-aria/useClipboardGrid.css
new file mode 100644
index 00000000000..9d8a2e594ab
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useClipboardGrid.css
@@ -0,0 +1,33 @@
+.grid {
+ display: block;
+ width: auto;
+ height: auto;
+ min-height: 80px;
+}
+
+.grid ul {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, 100px);
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ gap: 20px;
+}
+
+.grid li {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.grid li svg {
+ flex: 0 0 auto;
+}
+
+.grid li span {
+ flex: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
diff --git a/packages/dev/s2-docs/pages/react-aria/useCollator.mdx b/packages/dev/s2-docs/pages/react-aria/useCollator.mdx
new file mode 100644
index 00000000000..45d63d6cfd1
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useCollator.mdx
@@ -0,0 +1,74 @@
+{/* 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';
+
+
+# useCollator
+
+## Introduction
+
+`useCollator` wraps a builtin browser [Intl.Collator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator)
+object to provide a React Hook that integrates with the i18n system in React Aria. It handles string comparison according to the current locale,
+updating when the locale changes, and caching of collators for performance. See the
+[Intl.Collator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator) docs for
+information.
+
+## API
+
+
+
+## Example
+
+This example includes two textfields and compares the values of the two fields using a collator according to the current locale.
+
+```tsx render
+'use client';
+import React from 'react';
+import {useCollator} from '@react-aria/i18n';
+
+function Example() {
+ let [first, setFirst] = React.useState('');
+ let [second, setSecond] = React.useState('');
+
+ let collator = useCollator();
+ let result = collator.compare(first, second);
+
+ return (
+ <>
+
+ {result === 0
+ ? 'The strings are the same'
+ : result < 0
+ ? 'First comes before second'
+ : 'Second comes before first'
+ }
+
+ >
+ );
+}
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/useDateFormatter.mdx b/packages/dev/s2-docs/pages/react-aria/useDateFormatter.mdx
new file mode 100644
index 00000000000..2f77d300aed
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useDateFormatter.mdx
@@ -0,0 +1,57 @@
+{/* 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';
+
+# useDateFormatter
+
+## Introduction
+
+`useDateFormatter` wraps a builtin browser [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)
+object to provide a React Hook that integrates with the i18n system in React Aria. It handles formatting dates for the current locale,
+updating when the locale changes, and caching of date formatters for performance. See the
+[Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) docs for
+information on formatting options.
+
+## API
+
+
+
+## Example
+
+This example displays the current date for two locales: USA, and Russia. Two instances of the `CurrentDate` component are rendered,
+using the [I18nProvider](I18nProvider.html) to specify the locale to display.
+
+```tsx render
+'use client';
+import {I18nProvider, useDateFormatter} from '@react-aria/i18n';
+
+function CurrentDate() {
+ let formatter = useDateFormatter();
+
+ return (
+
{formatter.format(new Date())}
+ );
+}
+
+<>
+
+
+
+
+
+
+>
+```
diff --git a/packages/dev/s2-docs/pages/react-aria/useDrag.mdx b/packages/dev/s2-docs/pages/react-aria/useDrag.mdx
new file mode 100644
index 00000000000..7f028799fa3
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useDrag.mdx
@@ -0,0 +1,307 @@
+{/* 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/dnd';
+import sharedDocs from 'docs:@react-types/shared/src/dnd.d.ts';
+export const section = 'Drag and Drop';
+
+# useDrag
+
+{docs.exports.useDrag.description}
+
+## API
+
+
+
+## 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.
+
+React Aria supports traditional mouse and touch based drag and drop, but also implements keyboard and screen reader friendly interactions. Users can press Enter on a draggable element to enter drag and drop mode. Then, they can press Tab to navigate between drop targets, and Enter to drop or Escape to cancel. Touch screen reader users can also drag by double tapping to activate drag and drop mode, swiping between drop targets, and double tapping again to drop.
+
+See the [drag and drop introduction](dnd.html) to learn more.
+
+## Example
+
+This example shows how to make a simple draggable element that provides data as plain text. In order to support keyboard and screen reader drag interactions, the element must be focusable and have an ARIA role (in this case, `button`). While it is being dragged, it is displayed with a dimmed appearance by applying an additional CSS class.
+
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/DropTarget.tsx", "packages/dev/s2-docs/pages/react-aria/useDragExample.css"]}
+"use client";
+import {useDrag} from '@react-aria/dnd';
+import {DropTarget} from './DropTarget.tsx';
+import './useDragExample.css';
+
+function Draggable() {
+ let {dragProps, isDragging} = useDrag({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ }
+ });
+
+ return (
+
+ Drag me
+
+ );
+}
+
+
+
+
+
+```
+## Drag data
+Data for a draggable element can be provided in multiple formats at once. This allows drop targets to choose data in a format that they understand. For example, you could serialize a complex object as JSON in a custom format for use within your own application, and also provide plain text and/or rich HTML fallbacks that can be used when a user drops data in an external application (e.g. an email message).
+This can be done by returning multiple keys for an item from the `getItems` function. Types can either be a standard [mime type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) for interoperability with external applications, or a custom string for use within your own app.
+In addition to providing items in multiple formats, you can also return multiple drag items from `getItems` to transfer multiple objects in a single drag operation.
+This example drags two items, each of which contains representations as plain text, HTML, and a custom app-specific data format. Dropping on the drop targets in this page will use the custom data format to render formatted items. If you drop in an external application supporting rich text, the HTML representation will be used. Dropping in a text editor will use the plain text format.
+
+```tsx render
+"use client";
+import {useDrag} from '@react-aria/dnd';
+import {DropTarget} from './DropTarget.tsx';
+
+function Draggable() {
+ let {dragProps, isDragging} = useDrag({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world',
+ 'text/html': 'hello world',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'hello world',
+ style: 'bold'
+ })
+ }, {
+ 'text/plain': 'foo bar',
+ 'text/html': 'foo bar',
+ 'my-app-custom-type': JSON.stringify({
+ message: 'foo bar',
+ style: 'italic'
+ })
+ }];
+ }
+ });
+ ///- begin collapse -///
+ return (
+
+ Drag me
+
+ );
+ ///- end collapse -///
+}
+///- begin collapse -///
+
+
+
+
+///- end collapse -///
+```
+
+## Drag previews
+By default, the drag preview shown under the user's pointer or finger is a copy of the original element that started the drag. A custom preview can be rendered using the `` component. This accepts a function as a child which receives the dragged data that was returned by `getItems`, and returns a rendered preview for those items. The `DragPreview` is linked with `useDrag` via a ref, passed to the `preview` property. The `DragPreview` should be placed in the component hierarchy appropriately, so that it receives any React context or inherited styles that it needs to render correctly.
+This example renders a custom drag preview which shows the text of the first drag item.
+
+```tsx render
+"use client";
+import React from 'react';
+import {useDrag} from '@react-aria/dnd';
+import {DropTarget} from './DropTarget.tsx';
+import {DragPreview} from '@react-aria/dnd';
+
+function Draggable() {
+ let preview = React.useRef(null);
+ let {dragProps, isDragging} = useDrag({
+ preview,
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ }
+ });
+ return (
+ <>
+
+ Drag me
+
+ {/*- begin highlight -*/}
+
+ {items =>
{items[0]['text/plain']}
}
+
+ {/*- end highlight -*/}
+ >
+ );
+}
+
+
+
+
+```
+
+## Drop operations
+A is an indication of what will happen when dragged data is dropped on a particular drop target. These are:
+* `move` – indicates that the dragged data will be moved from its source location to the target location.
+* `copy` – indicates that the dragged data will be copied to the target destination.
+* `link` – indicates that there will be a relationship established between the source and target locations.
+* `cancel` – indicates that the drag and drop operation will be canceled, resulting in no changes made to the source or target.
+Many operating systems display these in the form of a cursor change, e.g. a plus sign to indicate a copy operation. The user may also be able to use a modifier key to choose which drop operation to perform, such as Option or Alt to switch from move to copy.
+The `onDragEnd` event allows the drag source to respond when a drag that it initiated ends, either because it was dropped or because it was canceled by the user. The `dropOperation` property of the event object indicates the operation that was performed. For example, when data is moved, the UI could be updated to reflect this change by removing the original dragged element.
+This example removes the draggable element from the UI when a move operation is completed. Try holding the Option or Alt keys to change the operation to copy, and see how the behavior changes.
+```tsx render
+"use client"
+import React from 'react';
+import {useDrag} from '@react-aria/dnd';
+import {DropTarget} from './DropTarget.tsx';
+
+function Draggable() {
+ let [moved, setMoved] = React.useState(false);
+ let {dragProps, isDragging} = useDrag({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ },
+ /*- begin highlight -*/
+ onDragEnd(e) {
+ if (e.dropOperation === 'move') {
+ setMoved(true);
+ }
+ }
+ /*- end highlight -*/
+ });
+ if (moved) {
+ return null;
+ }
+ // ...
+ ///- begin collapse -///
+ return (
+
+ Drag me
+
+ );
+ ///- end collapse -///
+}
+///- begin collapse -///
+
+
+
+
+///- end collapse -///
+```
+
+The drag source can also control which drop operations are allowed for the data. For example, if moving data is not allowed, and only copying is supported, the `getAllowedDropOperations` function could be implemented to indicate this. When you drag the element below, the cursor now shows the copy affordance by default, and pressing a modifier to switch drop operations results in the drop being canceled.
+
+```tsx render
+"use client";
+import {useDrag} from '@react-aria/dnd';
+import {DropTarget} from './DropTarget.tsx';
+
+function Draggable() {
+ let {dragProps, isDragging} = useDrag({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ },
+ /*- begin highlight -*/
+ getAllowedDropOperations() {
+ return ['copy'];
+ }
+ /*- end highlight -*/
+ });
+ // ...
+ ///- begin collapse -///
+ return (
+
+ Drag me
+
+ );
+ ///- end collapse -///
+}
+///- begin collapse -///
+
+
+
+
+///- end collapse -///
+```
+
+## Drag button
+
+In cases where a draggable element has other interactions that conflict with accessible drag and drop (e.g. Enter key), or if the element is not focusable, an explicit drag affordance can be added. This acts as a button that keyboard and screen reader users can use to activate drag and drop.
+When the `hasDragButton` option is enabled, the keyboard interactions are moved from the returned `dragProps` to the `dragButtonProps` so that they can be applied to a separate element, while the mouse and touch dragging interactions remain in `dragProps`.
+
+```tsx render
+"use client";
+import React from 'react';
+import {useDrag} from '@react-aria/dnd';
+import {useButton} from '@react-aria/button';
+import {DropTarget} from './DropTarget.tsx';
+
+function Draggable() {
+ let {dragProps, dragButtonProps, isDragging} = useDrag({
+ /*- begin highlight -*/
+ hasDragButton: true,
+ /*- end highlight -*/
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ }
+ });
+ /*- begin highlight -*/
+ let ref = React.useRef(null);
+ let {buttonProps} = useButton({...dragButtonProps, elementType: 'div'}, ref);
+ /*- end highlight -*/
+ return (
+
+ {/*- begin highlight -*/}
+ ≡
+ {/*- end highlight -*/}
+ Some text
+
+
+ );
+}
+
+
+
+
+
+```
+## Disabling dragging
+If you need to temporarily disable dragging, you can pass the `isDisabled` option to `useDrag`. This will prevent dragging an element until it is re-enabled.
+
+```tsx render
+"use client";
+import {useDrag} from '@react-aria/dnd';
+function Draggable() {
+ let {dragProps, isDragging} = useDrag({
+ getItems() {
+ return [{
+ 'text/plain': 'hello world'
+ }];
+ },
+ /*- begin highlight -*/
+ isDisabled: true
+ /*- end highlight -*/
+ });
+ return (
+
+ Drag me
+
+ );
+}
+
+```
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/useDragExample.css b/packages/dev/s2-docs/pages/react-aria/useDragExample.css
new file mode 100644
index 00000000000..9a546076f26
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useDragExample.css
@@ -0,0 +1,25 @@
+.draggable {
+ display: inline-block;
+ vertical-align: top;
+ border: 1px solid gray;
+ padding: 10px;
+}
+
+.draggable.dragging {
+ opacity: 0.5;
+}
+
+.droppable {
+ width: 100px;
+ height: 80px;
+ border-radius: 6px;
+ display: inline-block;
+ padding: 20px;
+ margin-left: 20px;
+ border: 2px dotted gray;
+ white-space: pre-wrap;
+}
+
+.droppable.target {
+ border: 2px solid var(--blue);
+}
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/useDrop.mdx b/packages/dev/s2-docs/pages/react-aria/useDrop.mdx
new file mode 100644
index 00000000000..1f7e1c93c53
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useDrop.mdx
@@ -0,0 +1,360 @@
+{/* 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 {InterfaceType} from '../../src/types';
+import {FunctionAPI} from '../../src/FunctionAPI';
+import docs from 'docs:@react-aria/dnd';
+import sharedDocs from 'docs:@react-types/shared/src/dnd.d.ts';
+import typesDocs from 'docs:@react-types/shared/src/events.d.ts';
+export const section = 'Drag and Drop';
+
+# useDrop
+
+{docs.exports.useDrop.description}
+
+## API
+
+
+
+## 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.
+
+React Aria supports traditional mouse and touch based drag and drop, but also implements keyboard and screen reader friendly interactions. Users can press Enter on a draggable element to enter drag and drop mode. Then, they can press Tab to navigate between drop targets, and Enter to drop or Escape to cancel. Touch screen reader users can also drag by double tapping to activate drag and drop mode, swiping between drop targets, and double tapping again to drop.
+
+See the [drag and drop introduction](dnd.html) to learn more.
+
+## Example
+
+This example shows how to make a simple drop target that accepts plain text data. In order to support keyboard and screen reader drag interactions, the element must be focusable and have an ARIA role (in this case, `button`). While a drag is hovered over it, a blue outline is rendered by applying an additional CSS class.
+
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/Draggable.tsx", "packages/dev/s2-docs/pages/react-aria/useDragExample.css"]}
+'use client';
+import React from 'react';
+import type {TextDropItem} from '@react-aria/dnd';
+import {useDrop} from '@react-aria/dnd';
+import {Draggable} from './Draggable.tsx';
+import './useDragExample.css';
+
+function DropTarget() {
+ let [dropped, setDropped] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ async onDrop(e) {
+ let items = await Promise.all(
+ e.items
+ .filter(item => item.kind === 'text' && item.types.has('text/plain'))
+ .map((item: TextDropItem) => item.getText('text/plain'))
+ );
+ setDropped(items.join('\n'));
+ }
+ });
+
+ return (
+
+ {dropped || 'Drop here'}
+
+ );
+}
+
+
+
+
+
+```
+## Drop data
+`useDrop` allows users to drop one or more **drag items**, each of which contains data to be transferred from the drag source to drop target. There are three kinds of drag items:
+* `text` – represents data inline as a string in one or more formats
+* `file` – references a file on the user's device
+* `directory` – references the contents of a directory
+### Text
+A represents textual data in one or more different formats. These may be either standard [mime types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) or custom app-specific formats. Representing data in multiple formats allows drop targets both within and outside an application to choose data in a format that they understand. For example, a complex object may be serialized in a custom format for use within an application, with fallbacks in plain text and/or rich HTML that can be used when a user drops data from an external application.
+The example below finds the first available item that includes a custom app-specific type. The same draggable component as used in the above example is used here, but rather than displaying the plain text representation, the custom format is used instead.
+
+```tsx render
+'use client';
+import React from 'react';
+import {useDrop} from '@react-aria/dnd';
+import {Draggable} from './Draggable.tsx';
+
+function DropTarget() {
+ let [dropped, setDropped] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ /*- begin highlight -*/
+ async onDrop(e) {
+ let item = e.items.find(item => item.kind === 'text' && item.types.has('my-app-custom-type')) as TextDropItem;
+ if (item) {
+ setDropped(await item.getText('my-app-custom-type'));
+ }
+ }
+ /*- end highlight -*/
+ });
+ // ...
+ ///- begin collapse -///
+ return (
+
+ {dropped || 'Drop here'}
+
+ );
+ ///- end collapse -///
+}
+///- begin collapse -///
+
+
+
+
+///- end collapse -///
+```
+### Files
+A references a file on the user's device. It includes the name and mime type of the file, and methods to read the contents as plain text, or retrieve a native [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object which can be attached to form data for uploading.
+This example accepts JPEG and PNG image files, and renders them by creating a local [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL).
+
+```tsx render
+'use client';
+import React from 'react';
+import type {FileDropItem} from '@react-aria/dnd';
+import {useDrop} from '@react-aria/dnd';
+function DropTarget() {
+ let [file, setFile] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ /*- begin highlight -*/
+ async onDrop(e) {
+ let item = e.items.find(item => item.kind === 'file' && (item.type === 'image/jpeg' || item.type === 'image/png')) as FileDropItem;
+ if (item) {
+ setFile(URL.createObjectURL(await item.getFile()));
+ }
+ }
+ /*- end highlight -*/
+ });
+ return (
+
+ {file ? : 'Drop image here'}
+
+ );
+}
+```
+### Directories
+A references the contents of a directory on the user's device. It includes the name of the directory, as well as a method to iterate through the files and folders within the directory. The contents of any folders within the directory can be accessed recursively.
+The `getEntries` method returns an [async iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) object, which can be used in a `for await...of` loop. This provides each item in the directory as either a or , and you can access the contents of each file as discussed above.
+
+This example renders the file names within a dropped directory in a grid.
+
+```tsx render files={["packages/dev/s2-docs/pages/react-aria/useClipboardGrid.css"]}
+'use client';
+import React from 'react';
+import type {DirectoryDropItem} from '@react-aria/dnd';
+import File from '@react-spectrum/s2/icons/File';
+import Folder from '@react-spectrum/s2/icons/Folder';
+import {useDrop} from '@react-aria/dnd';
+import './useClipboardGrid.css';
+
+function DropTarget() {
+ let [files, setFiles] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ /*- begin highlight -*/
+ async onDrop(e) {
+ // Find the first dropped item that is a directory.
+ let dir = e.items.find(item => item.kind === 'directory') as DirectoryDropItem;
+ if (dir) {
+ // Read entries in directory and update state with relevant info.
+ let files = [];
+ for await (let entry of dir.getEntries()) {
+ files.push({
+ name: entry.name,
+ kind: entry.kind
+ });
+ }
+ setFiles(files);
+ }
+ }
+ /*- end highlight -*/
+ });
+ let contents = <>Drop directory here>;
+ if (files) {
+ contents = (
+
+ {files.map(f => (
+
+ {f.kind === 'directory' ? : }
+ {f.name}
+
+ ))}
+
+ );
+ }
+ return (
+
+ {contents}
+
+ );
+}
+```
+
+## Drop operations
+
+A is an indication of what will happen when dragged data is dropped on a particular drop target. These are:
+* `move` – indicates that the dragged data will be moved from its source location to the target location.
+* `copy` – indicates that the dragged data will be copied to the target destination.
+* `link` – indicates that there will be a relationship established between the source and target locations.
+* `cancel` – indicates that the drag and drop operation will be canceled, resulting in no changes made to the source or target.
+Many operating systems display these in the form of a cursor change, e.g. a plus sign to indicate a copy operation. The user may also be able to use a modifier key to choose which drop operation to perform, such as Option or Alt to switch from move to copy.
+The drag source can specify which drop operations are allowed for the dragged data (see the [useDrag docs](useDrag.html) for how to customize this). By default, the first allowed operation is allowed by drop targets, meaning that the drop target accepts data of any type and operation.
+
+### getDropOperation
+
+The `getDropOperation` function passed to `useDrop` can be used to provide appropriate feedback to the user when a drag hovers over the drop target. If a drop target only supports data of specific types (e.g. images, videos, text, etc.), then it should implement `getDropOperation` 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.
+When the data is supported, either return one of the drop operations in `allowedOperation` or a specific drop operation if only that drop operation is supported. If the returned operation is not in `allowedOperations`, then the drop target will act as if `'cancel'` was returned.
+
+In the below example, the drop target only supports dropping PNG images. If a PNG is dragged over the target, it will be highlighted and the operating system displays a copy cursor. If another type is dragged over the target, then there is no visual feedback, indicating that a drop is not accepted there. If the user holds a modifier key such as Control while dragging over the drop target in order to change the drop operation, then the drop target does not accept the drop.
+
+```tsx render
+'use client';
+import React from 'react';
+import {useDrop} from '@react-aria/dnd';
+function DropTarget() {
+ let [file, setFile] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ /*- begin highlight -*/
+ getDropOperation(types, allowedOperations) {
+ return types.has('image/png') ? 'copy' : 'cancel';
+ },
+ /*- end highlight -*/
+ async onDrop(e) {
+ let item = e.items.find(item => item.kind === 'file' && item.type === 'image/png') as FileDropItem;
+ if (item) {
+ setFile(URL.createObjectURL(await item.getFile()));
+ }
+ }
+ });
+ // ...
+///- begin collapse -///
+ return (
+
+ {file ? : 'Drop image here'}
+
+ );
+///- end collapse -///
+}
+```
+### onDrop
+The `onDrop` event also includes the `dropOperation`. This can be used to perform different actions accordingly, for example, when communicating with a backend API.
+```tsx
+function DropTarget(props) {
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ async onDrop(e) {
+ let item = e.items.find(item => item.kind === 'text' && item.types.has('my-app-file')) as TextDropItem;
+ if (!item) {
+ return;
+ }
+ let data = JSON.parse(await item.getText('my-app-file'));
+ /*- begin highlight -*/
+ switch (e.dropOperation) {
+ case 'move':
+ MyAppFileService.move(data.filePath, props.filePath);
+ break;
+ case 'copy':
+ MyAppFileService.copy(data.filePath, props.filePath);
+ break;
+ case 'link':
+ MyAppFileService.link(data.filePath, props.filePath);
+ break;
+ }
+ /*- end highlight -*/
+ }
+ });
+ // ...
+}
+```
+## Events
+
+Drop targets receive a number of events during a drag session. These are:
+
+
+This example logs all events that occur within the drop target:
+
+```tsx render
+'use client';
+import React from 'react';
+import {useDrop} from '@react-aria/dnd';
+import {Draggable} from './Draggable.tsx';
+
+function DropTarget() {
+ let [events, setEvents] = React.useState([]);
+ let onEvent = e => setEvents(events => [JSON.stringify(e), ...events]);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ onDropEnter: onEvent,
+ onDropMove: onEvent,
+ onDropExit: onEvent,
+ onDrop: onEvent
+ });
+ return (
+
+ {events.map((e, i) =>
{e}
)}
+
+ );
+}
+
+
+
+
+```
+## Disabling dropping
+
+If you need to temporarily disable dropping, you can pass the `isDisabled` option to `useDrop`. This will prevent the drop target from accepting any drops until it is re-enabled.
+
+```tsx render
+'use client';
+import React from 'react';
+import type {TextDropItem} from '@react-aria/dnd';
+import {useDrop} from '@react-aria/dnd';
+import {Draggable} from './Draggable.tsx';
+
+function DropTarget() {
+ let [dropped, setDropped] = React.useState(null);
+ let ref = React.useRef(null);
+ let {dropProps, isDropTarget} = useDrop({
+ ref,
+ async onDrop(e) {
+ let items = await Promise.all(
+ e.items
+ .filter(item => item.kind === 'text' && item.types.has('text/plain'))
+ .map((item: TextDropItem) => item.getText('text/plain'))
+ );
+ setDropped(items.join('\n'));
+ },
+ /*- begin highlight -*/
+ isDisabled: true
+ /*- end highlight -*/
+ });
+ return (
+
+ {dropped || 'Drop here'}
+
+ );
+}
+
+
+
+
+```
\ No newline at end of file
diff --git a/packages/dev/s2-docs/pages/react-aria/useField.mdx b/packages/dev/s2-docs/pages/react-aria/useField.mdx
new file mode 100644
index 00000000000..41125ea5648
--- /dev/null
+++ b/packages/dev/s2-docs/pages/react-aria/useField.mdx
@@ -0,0 +1,68 @@
+{/* 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 docs from 'docs:@react-aria/label';
+import {FunctionAPI} from '../../src/FunctionAPI';
+
+export const section = 'Utilities';
+
+# useField
+
+{docs.exports.useField.description}
+
+## API
+
+
+
+## Example
+
+The `useField` hook associates a form control with a label, and an optional description and/or error message. This is useful for providing context about how users should fill in a field, or a validation message. `useField` takes care of creating ids for each element and associating them with the correct ARIA attributes (`aria-labelledby` and `aria-describedby`).
+
+By default, `useField` assumes that the label is a native HTML `