From f1aafc6ce79448821af41632467b9837f2e35a10 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Tue, 4 Nov 2025 18:39:57 -0800 Subject: [PATCH] docs: Add Forms and Customization guides (#9141) * docs: Add Forms and Customization guides * thanks linter, i hate it --- .../pages/react-aria/customization.mdx | 352 ++++++++++++ .../dev/s2-docs/pages/react-aria/forms.mdx | 499 ++++++++++++++++++ .../dev/s2-docs/pages/react-aria/styling.mdx | 28 +- packages/dev/s2-docs/pages/s2/forms.mdx | 214 ++++---- packages/dev/s2-docs/src/ComponentCard.tsx | 1 + 5 files changed, 974 insertions(+), 120 deletions(-) create mode 100644 packages/dev/s2-docs/pages/react-aria/customization.mdx create mode 100644 packages/dev/s2-docs/pages/react-aria/forms.mdx diff --git a/packages/dev/s2-docs/pages/react-aria/customization.mdx b/packages/dev/s2-docs/pages/react-aria/customization.mdx new file mode 100644 index 00000000000..e0b5afbe528 --- /dev/null +++ b/packages/dev/s2-docs/pages/react-aria/customization.mdx @@ -0,0 +1,352 @@ +import {Layout} from '../../src/Layout'; +export default Layout; + +import docs from 'docs:react-aria-components'; + +export const section = 'Guides'; +export const description = 'Building custom component patterns'; + +# Customization + +React Aria Components is built using a flexible and composable API that you can extend to build new patterns. If you need even more customizability, drop down to the lower level Hook-based API for even more control over rendering and behavior. Mix and match as needed. + +## Contexts + +The React Aria Components API is designed around composition. Components are reused between patterns to build larger composite components. For example, there is no dedicated `NumberFieldIncrementButton` or `SelectPopover` component. Instead, the standalone [Button](Button.html) and [Popover](Popover.html) components are reused within [NumberField](NumberField.html) and [Select](Select.html). This reduces the amount of duplicate styling code you need to write and maintain, and provides powerful composition capabilities you can use in your own components. + +```tsx + + + + + + + + +``` + +React Aria Components automatically provide behavior to their children by passing event handlers and other attributes via context. For example, the increment and decrement buttons in a `NumberField` receive `onPress` handlers that update the value. Keeping each element of a component separate enables full styling, layout, and DOM structure control, and contexts ensure that accessibility and behavior are taken care of on your behalf. + +This architecture also enables you to reuse React Aria Components in your own custom patterns, or even replace one part of a component with your own custom implementation without rebuilding the whole pattern from scratch. + +### Custom patterns + +Each React Aria Component exports a corresponding context that you can use to build your own compositional APIs similar to the built-in components. These accept the component's props as a value. The local component props are merged with the ones passed via context, with the local props taking precedence (see [mergeProps](mergeProps.html)). + +This example shows a `FieldGroup` component that renders a group of text fields. The entire group can be marked as disabled via the `isDisabled` prop, which is passed to all child text fields via the `TextFieldContext` provider. + +```tsx +import {TextFieldContext} from 'react-aria-components'; + +interface FieldGroupProps { + children?: React.ReactNode, + isDisabled?: boolean +} + +function FieldGroup({children, isDisabled}: FieldGroupProps) { + return ( + /*- begin highlight -*/ + + {/*- end highlight -*/} + {children} + + ); +} +``` + +Any `TextField` component you place inside a `FieldGroup` will automatically receive the `isDisabled` prop from the group, including those that are deeply nested inside other components. + +```tsx + + + + + +``` + +### Slots + +Some patterns include multiple instances of the same component, which are distinguished by the `slot` prop. Slots are named children within a component that have separate behaviors and [styles](styling.html#slots). Separate props can be sent to slots by providing an object with keys for each slot name to the component's context provider. + +This example shows a `Stepper` component with slots for its increment and decrement buttons. + +```tsx +function Stepper({children}) { + let [value, setValue] = React.useState(0); + + return ( + setValue(value + 1) + }, + decrement: { + onPress: () => setValue(value - 1) + } + } + }}> + {children} + + ); +} + + + + + +``` + +#### Default slot + +The default slot is used to provide props to a component without specifying a slot name. This is used by children without a `slot` prop. This example passes a specific class name to a standard button child and to a button child with a slot named "end". + +```tsx +import {Button, ButtonContext, DEFAULT_SLOT} from 'react-aria-components'; + +function MyCustomComponent({children}) { + return ( + + {children} + + ); +} + + + {/* Consumes the props passed to the default slot */} + + {/* Consumes the props passed to the "end" slot */} + + +``` + +### Provider + +The `Provider` component is a utility that makes it easier to provide multiple React contexts without manually nesting them. This can be achieved by passing pairs of contexts and values as an array to the `values` prop. + +```tsx +import {Provider, ButtonContext, InputContext} from 'react-aria-components'; + + + {/* ... */} + +``` + +This is equivalent to: + +```tsx + + + {/* ... */} + + +``` + +### Consuming contexts + +You can also consume from contexts provided by React Aria Components in your own custom components. This allows you to replace a component used as part of a larger pattern with a custom implementation. For example, you could consume from `LabelContext` in a custom label component to make it compatible with React Aria Components. + +#### useContextProps + +The hook merges the local props with the ones provided via context by a parent component. The local props always take precedence over the context values (see [mergeProps](mergeProps.html)). `useContextProps` supports the [slot](#slots) prop to indicate which value to consume from context. + +```tsx +import type {LabelProps} from 'react-aria-components'; +import {LabelContext, useContextProps} from 'react-aria-components'; + +const MyCustomLabel = React.forwardRef( + (props: LabelProps, ref: React.ForwardedRef) => { + // Merge the local props and ref with the ones provided via context. + /*- begin highlight -*/ + let [mergedProps, mergedRef] = useContextProps(props, ref, LabelContext); + /*- end highlight -*/ + + // ... your existing Label component + return