Skip to content

Conversation

@LFDanLu
Copy link
Member

@LFDanLu LFDanLu commented Oct 23, 2025

Closes

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

RSP

@rspbot
Copy link

rspbot commented Oct 24, 2025

Comment on lines +430 to +431
- The [atomic-css-devtools](https://github.com/astahmer/atomic-css-devtools) extension presents an inspected element's atomic CSS rules
in a non-atomic format, making it easier to scan.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: replace with the new devtool extension @snowystinger is making

Comment on lines +443 to +445
This indicates that your `style` macro has a condition that isn't evaluable at build time. This can happen for a variety of reasons such
as if you've referenced non-constant variables within your `style` macro or if you've called non-macro functions within your `style` macro.
If you are using Typescript, it can be as simple as forgetting to add `as const` to your own defined reusable macro.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add an example of a macro that would cause this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel like there's several ways you could encounter this error (based on vibes) so a single example wouldn't be enough and might cause confusion for some people if their code doesn't match the example.

maybe would be good to find the most common ways you can encounter this error and offer a couple of possible solutions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, its just been kinda hard finding which ways are the common ways people encounter this. I tried to allude to those fixes above but didn't want to fully document each since it might take too much room

Comment on lines +451 to +454
> I tried to pass my `style` macro to `UNSAFE_className` but it doesn't work.
The `style` macro is not meant to be used with `UNSAFE_className`. Overrides to the Spectrum styles is highly discouraged,
consider styling an equivalent React Aria Component instead.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already mentioned in the UNSAFE style overrides section but felt it was worth adding here anyways

Comment on lines +40 to +46
<InlineAlert variant="informative">
<Heading>Important Note</Heading>
<Content>
Due to the atomic nature of the generated CSS rules, it is strongly recommended that you follow the best practices listed [below](#css-optimization).
Failure to do so can result in large number of duplicate rules and obtuse styling bugs.
</Content>
</InlineAlert>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe overkill, but it felt like it was important to mention this up front so people realize that this is important

Comment on lines 338 to 343
## Creating custom components

In-depth examples are coming soon!

`mergeStyles` can be used to merge the style strings from multiple macros together, with the latter styles taking precedence similar to object spreading.
This behavior can be leveraged to create a component API that allows an end user to only override specific styles conditionally.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed previously that for this first pass that we want to stick with just modifying this page and create examples of style macros with RAC after the release of the docs. I've opted to keep this section and the once above it for now just to let people know about the existence of mergeStyles/iconStyle/and setting CSS variables with macros, but ideally these would move into an "Advanced" page or something similar to cut down on length here. Will comment on the file as to what I'm thinking the final division should look like

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My imagined ideal end state for these style macro docs is as follows:

This page aka "Styling"
Contains the following top level sections:

  • Style macro
  • Spectrum components
  • Values
  • CSS optimization
  • CSS Resets
  • Developing with style macros
  • FAQ

An "Advanced" page, maybe named Styling: Advanced? Or maybe a subpage where it is available in the ToC but not the sidebar?
Contains the following content:

  • Conditional styles
  • Reusing styles (maybe should be in Styling)?
  • Setting CSS variables
  • Creating custom components (examples of RAC with style macros. Documentation of size, space, fontRelative? Or do those belong at the Styling level?)

A Reference page
Contains a listing of every value supported by the style macro. Basically what we have for Colors/etc but including a mapping perhaps for things like spacing/sizing/etc

- If you are using Cursor, we offer a set of [Cursor rules](https://github.com/adobe/react-spectrum/blob/main/rules/style-macro.mdc) to use when developing with style macros. Additionally,
we have MCP servers for [React Aria](#TODO) and [React Spectrum](https://www.npmjs.com/package/@react-spectrum/mcp) respectively that interface with the docs.

## FAQ
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we make use of disclosures here? (but maybe a follow-up if it takes too long to style and what not)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats a good suggestion, I was a bit torn on if the current style was better or now (inspired by our own FAQ in github) but I've definitely seen both styles on other sites like MUI and Untitled UI. I'll bring this up with the rest of the team and see what people like

Comment on lines +443 to +445
This indicates that your `style` macro has a condition that isn't evaluable at build time. This can happen for a variety of reasons such
as if you've referenced non-constant variables within your `style` macro or if you've called non-macro functions within your `style` macro.
If you are using Typescript, it can be as simple as forgetting to add `as const` to your own defined reusable macro.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel like there's several ways you could encounter this error (based on vibes) so a single example wouldn't be enough and might cause confusion for some people if their code doesn't match the example.

maybe would be good to find the most common ways you can encounter this error and offer a couple of possible solutions


## Text

Spectrum 2 typography can be applied via the `font` [shorthand](#shorthand), which sets `fontFamily`, `fontSize`, `fontWeight`, `lineHeight`, and `color`. You can override any of these individually.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this repeat the content under Typography for the most part?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats right, the content here is the same. Open to opinions if it should stay like that, I felt like some people might jump to this page on its own since it is a reference and therefore it would be useful to have the additional context/explanation

@rspbot
Copy link

rspbot commented Oct 31, 2025

@rspbot
Copy link

rspbot commented Oct 31, 2025

## API Changes

@react-spectrum/s2

/@react-spectrum/s2:Calendar

 Calendar <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean = false
+  children?: ChildrenOrFunction<CalendarRenderProps>
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultFocusedValue?: DateValue | null
   defaultValue?: DateValue | null
   errorMessage?: ReactNode
   focusedValue?: DateValue | null
   id?: string
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean = false
   isInvalid?: boolean
   isReadOnly?: boolean = false
   maxValue?: DateValue | null
   minValue?: DateValue | null
   onChange?: (MappedDateValue<DateValue>) => void
   onFocusChange?: (CalendarDate) => void
   pageBehavior?: PageBehavior = visible
   selectionAlignment?: 'start' | 'center' | 'end' = 'center'
   slot?: string | null
   styles?: StylesProp
   value?: DateValue | null
   visibleMonths?: number = 1
 }

/@react-spectrum/s2:MenuSection

 MenuSection <T extends {}> {
   aria-label?: string
-  children?: ReactNode
+  children?: ReactNode | (T) => ReactElement
+  className?: string = 'react-aria-MenuSection'
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   id?: Key
   items?: Iterable<T>
   onSelectionChange?: (Selection) => void
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
+  style?: CSSProperties
   value?: T
 }

/@react-spectrum/s2:Popover

 Popover {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
-  children?: ReactNode
+  children?: ChildrenOrFunction<PopoverRenderProps>
   containerPadding?: number = 12
   crossOffset?: number = 0
   hideArrow?: boolean = false
   id?: string
   offset?: number = 8
   onOpenChange?: (boolean) => void
   padding?: 'default' | 'none' = 'default'
   placement?: Placement = 'bottom'
   role?: 'dialog' | 'alertdialog' = 'dialog'
   shouldFlip?: boolean = true
   size?: 'S' | 'M' | 'L'
   slot?: string | null
   styles?: PopoverStylesProp
   triggerRef?: RefObject<Element | null>
 }

/@react-spectrum/s2:RangeCalendar

 RangeCalendar <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   allowsNonContiguousRanges?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean = false
+  children?: ChildrenOrFunction<RangeCalendarRenderProps>
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultFocusedValue?: DateValue | null
   defaultValue?: RangeValue<DateValue> | null
   errorMessage?: ReactNode
   focusedValue?: DateValue | null
   id?: string
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean = false
   isInvalid?: boolean
   isReadOnly?: boolean = false
   maxValue?: DateValue | null
   minValue?: DateValue | null
   onChange?: (RangeValue<MappedDateValue<DateValue>>) => void
   onFocusChange?: (CalendarDate) => void
   pageBehavior?: PageBehavior = visible
   selectionAlignment?: 'start' | 'center' | 'end' = 'center'
   slot?: string | null
   styles?: StylesProp
   value?: RangeValue<DateValue> | null
   visibleMonths?: number = 1
 }

/@react-spectrum/s2:Cell

 Cell {
   align?: 'start' | 'center' | 'end' = 'start'
   children: ReactNode
+  className?: ClassNameOrFunction<CellRenderProps> = 'react-aria-Cell'
   colSpan?: number
   id?: Key
   showDivider?: boolean
+  style?: StyleOrFunction<CellRenderProps>
   textValue?: string
 }

/@react-spectrum/s2:Column

 Column {
   align?: 'start' | 'center' | 'end' = 'start'
   allowsResizing?: boolean
   allowsSorting?: boolean
   children: ReactNode
+  className?: ClassNameOrFunction<ColumnRenderProps> = 'react-aria-Column'
   defaultWidth?: ColumnSize | null
   id?: Key
   isRowHeader?: boolean
   maxWidth?: ColumnStaticSize | null
   menuItems?: ReactNode
   minWidth?: ColumnStaticSize | null
   showDivider?: boolean
+  style?: StyleOrFunction<ColumnRenderProps>
   textValue?: string
   width?: ColumnSize | null
 }

/@react-spectrum/s2:EditableCell

 EditableCell {
   align?: 'start' | 'center' | 'end' = 'start'
   children: ReactNode
+  className?: ClassNameOrFunction<CellRenderProps> = 'react-aria-Cell'
   colSpan?: number
   id?: Key
   isSaving?: boolean
   onSubmit: () => void
   renderEditing: () => ReactNode
   showDivider?: boolean
+  style?: StyleOrFunction<CellRenderProps>
   textValue?: string
 }

/@react-spectrum/s2:UNSTABLE_ToastContainer

 UNSTABLE_ToastContainer {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string = "Notifications"
   aria-labelledby?: string
+  className?: ClassNameOrFunction<ToastRegionRenderProps<T>> = 'react-aria-ToastRegion'
   placement?: ToastPlacement = "bottom"
+  style?: StyleOrFunction<ToastRegionRenderProps<T>>
 }

/@react-spectrum/s2:CalendarProps

 CalendarProps <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean = false
+  children?: ChildrenOrFunction<CalendarRenderProps>
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultFocusedValue?: DateValue | null
   defaultValue?: DateValue | null
   errorMessage?: ReactNode
   focusedValue?: DateValue | null
   id?: string
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean = false
   isInvalid?: boolean
   isReadOnly?: boolean = false
   maxValue?: DateValue | null
   minValue?: DateValue | null
   onChange?: (MappedDateValue<DateValue>) => void
   onFocusChange?: (CalendarDate) => void
   pageBehavior?: PageBehavior = visible
   selectionAlignment?: 'start' | 'center' | 'end' = 'center'
   slot?: string | null
   styles?: StylesProp
   value?: DateValue | null
   visibleMonths?: number = 1
 }

/@react-spectrum/s2:MenuSectionProps

 MenuSectionProps <T extends {}> {
   aria-label?: string
-  children?: ReactNode
+  children?: ReactNode | (T) => ReactElement
+  className?: string = 'react-aria-MenuSection'
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   id?: Key
   items?: Iterable<T>
   onSelectionChange?: (Selection) => void
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
+  style?: CSSProperties
   value?: T
 }

/@react-spectrum/s2:PopoverProps

 PopoverProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   arrowRef?: RefObject<Element | null>
   boundaryElement?: Element = document.body
   children?: ChildrenOrFunction<PopoverRenderProps>
+  className?: ClassNameOrFunction<PopoverRenderProps> = 'react-aria-Popover'
   containerPadding?: number = 12
   crossOffset?: number = 0
   defaultOpen?: boolean
   hideArrow?: boolean = false
   isEntering?: boolean
   isExiting?: boolean
   isOpen?: boolean
   maxHeight?: number
   offset?: number = 8
   onOpenChange?: (boolean) => void
   placement?: Placement = 'bottom'
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldFlip?: boolean = true
   size?: 'S' | 'M' | 'L'
   slot?: string | null
+  style?: StyleOrFunction<PopoverRenderProps>
   styles?: StyleString
   trigger?: string
   triggerRef?: RefObject<Element | null>
 }

/@react-spectrum/s2:RangeCalendarProps

 RangeCalendarProps <T extends DateValue> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   allowsNonContiguousRanges?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean = false
+  children?: ChildrenOrFunction<RangeCalendarRenderProps>
   createCalendar?: (CalendarIdentifier) => Calendar
   defaultFocusedValue?: DateValue | null
   defaultValue?: RangeValue<DateValue> | null
   errorMessage?: ReactNode
   focusedValue?: DateValue | null
   id?: string
   isDateUnavailable?: (DateValue) => boolean
   isDisabled?: boolean = false
   isInvalid?: boolean
   isReadOnly?: boolean = false
   maxValue?: DateValue | null
   minValue?: DateValue | null
   onChange?: (RangeValue<MappedDateValue<DateValue>>) => void
   onFocusChange?: (CalendarDate) => void
   pageBehavior?: PageBehavior = visible
   selectionAlignment?: 'start' | 'center' | 'end' = 'center'
   slot?: string | null
   styles?: StylesProp
   value?: RangeValue<DateValue> | null
   visibleMonths?: number = 1
 }

/@react-spectrum/s2:CellProps

 CellProps {
   align?: 'start' | 'center' | 'end' = 'start'
   children: ReactNode
+  className?: ClassNameOrFunction<CellRenderProps> = 'react-aria-Cell'
   colSpan?: number
   id?: Key
   showDivider?: boolean
+  style?: StyleOrFunction<CellRenderProps>
   textValue?: string
 }

/@react-spectrum/s2:ColumnProps

 ColumnProps {
   align?: 'start' | 'center' | 'end' = 'start'
   allowsResizing?: boolean
   allowsSorting?: boolean
   children: ReactNode
+  className?: ClassNameOrFunction<ColumnRenderProps> = 'react-aria-Column'
   defaultWidth?: ColumnSize | null
   id?: Key
   isRowHeader?: boolean
   maxWidth?: ColumnStaticSize | null
   menuItems?: ReactNode
   minWidth?: ColumnStaticSize | null
   showDivider?: boolean
+  style?: StyleOrFunction<ColumnRenderProps>
   textValue?: string
   width?: ColumnSize | null
 }

/@react-spectrum/s2:ToastContainerProps

 ToastContainerProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string = "Notifications"
   aria-labelledby?: string
+  className?: ClassNameOrFunction<ToastRegionRenderProps<T>> = 'react-aria-ToastRegion'
   placement?: ToastPlacement = "bottom"
+  style?: StyleOrFunction<ToastRegionRenderProps<T>>
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants