- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.3k
docs: (WIP) Style macro docs #9090
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| Build successful! 🎉 | 
| - 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. | 
There was a problem hiding this comment.
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
| 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. | 
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
| > 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. | 
There was a problem hiding this comment.
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
| <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> | 
There was a problem hiding this comment.
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
| ## 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. | 
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
…ack to the visual
| - 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 | 
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
| 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. | 
There was a problem hiding this comment.
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. | 
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
| Build successful! 🎉 | 
| ## 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>>
 } | 
Closes
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project:
RSP