-
Notifications
You must be signed in to change notification settings - Fork 1.3k
docs: 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?
docs: Style macro docs #9090
Changes from 14 commits
edeaa2f
8a1f97e
28eb788
457c59a
a15c24f
819c076
3b991ea
42b0406
36f1a6f
e2b29c9
4c94cd0
83262ef
5d2b172
980d3d6
59e9400
a414886
0b2751d
4ef4996
b04b7af
807beb0
0c6ac3f
a3d57a9
30bab22
44b0d8d
5084b6b
34ad8cc
6bf1724
6e508f2
4b38f98
2e13868
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import {Layout} from '../../src/Layout'; | ||
| import {InlineAlert, Heading, Content, Link} from '@react-spectrum/s2'; | ||
| import {S2Colors} from '../../src/S2Colors'; | ||
| import {S2Typography} from '../../src/S2Typography'; | ||
| import {StyleMacroProperties} from '../../src/types'; | ||
| import {getPropertyDefinitions, getShorthandDefinitions} from '../../src/styleProperties'; | ||
| export default Layout; | ||
|
|
||
| export const section = 'Guides'; | ||
| export const tags = ['style', 'macro', 'spectrum', 'custom', 'values', 'reference']; | ||
| export const description = 'Reference table for the `style` macro'; | ||
|
|
||
| # Style Macro Reference | ||
|
|
||
| Reference for the properties and values supported by React Spectrum `style` macro. | ||
|
|
||
| ## Colors | ||
|
|
||
| All Spectrum 2 color tokens are available across color properties (e.g., `backgroundColor`, `color`, `borderColor`). | ||
|
|
||
| <S2Colors /> | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('color')} /> | ||
|
|
||
| ## Dimensions | ||
|
|
||
| Spacing props like `margin` and `padding` accept values on a **4px grid**. These are specified in `px` and get converted to `rem`. In addition to numbers, these named options are available: | ||
|
|
||
| - `edge-to-text` – default spacing between the edge of a control and its text. Relative to control height. | ||
| - `pill` – default spacing between the edge of a pill-shaped control and its text. Relative to control height. | ||
| - `text-to-control` – default spacing between text and a control (e.g., label and input). Scales with font size. | ||
| - `text-to-visual` – default spacing between text and a visual element (e.g., icon). Scales with font size. | ||
|
|
||
| Size props like `width` and `height` accept arbitrary pixel values. Values are converted to `rem` and multiplied by 1.25x on touch devices to increase hit targets. | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('dimensions')} /> | ||
|
|
||
| ## 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. | ||
|
|
||
| ```tsx | ||
| <main> | ||
| <h1 className={style({font: 'heading-xl'})}>Heading</h1> | ||
| <p className={style({font: 'body'})}>Body</p> | ||
| <ul className={style({font: 'body-sm', fontWeight: 'bold'})}> | ||
| <li>List item</li> | ||
| </ul> | ||
| </main> | ||
| ``` | ||
|
|
||
| Type scales include: UI, Body, Heading, Title, Detail, and Code. Each scale has a default and additional t-shirt sizes (e.g., `ui-sm`, `heading-2xl`, `code-xl`). | ||
|
|
||
| <S2Typography /> | ||
|
|
||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('text')} /> | ||
|
|
||
|
|
||
| ## Effects | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('effects')} /> | ||
|
|
||
| ## Layout | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('layout')} /> | ||
|
|
||
| ## Misc | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('misc')} /> | ||
|
|
||
| ## Shorthands | ||
|
|
||
| Shorthands apply their provided value to commonly grouped properties. | ||
|
|
||
| <StyleMacroProperties properties={getShorthandDefinitions('shorthand')} /> | ||
|
|
||
| ## Conditions | ||
|
|
||
| <StyleMacroProperties properties={getPropertyDefinitions('conditions')} /> |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For those reviewing this page, compare the current experience with the old: https://reactspectrum.blob.core.windows.net/reactspectrum/5084b6bfa7066fbe90e520c9575422bf0df27dd0/s2-docs/s2/styling.html In particular the organization/existence of subpage/contents, open to opinions as to which is preferred |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ export const description = 'Styling in React Spectrum'; | |
|
|
||
| # Styling | ||
|
|
||
| React Spectrum includes a build-time style macro that generates atomic CSS and lets you apply Spectrum tokens directly in your components with type-safe autocompletion. | ||
| React Spectrum includes a build-time `style` macro that generates atomic CSS and lets you apply Spectrum tokens directly in your components with type-safe autocompletion. | ||
|
|
||
| ## Style macro | ||
|
|
||
|
|
@@ -37,6 +37,14 @@ Colocating styles with your component code means: | |
| - Develop more efficiently – no switching files or writing selectors. | ||
| - Refactor with confidence – changes are isolated; deleting a component removes its styles. | ||
|
|
||
| <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> | ||
|
Comment on lines
41
to
47
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| ## Spectrum components | ||
|
|
||
| The `styles` prop accepts a limited set of CSS properties, including layout, spacing, sizing, and positioning. Other styles such as colors and internal padding cannot be customized within Spectrum components. | ||
|
|
@@ -88,7 +96,7 @@ import {Button} from '@react-spectrum/s2'; | |
|
|
||
| ### UNSAFE Style Overrides | ||
snowystinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| We highly discourage overriding the styles of React Spectrum components because it may break at any time when we change our implementation, making it difficult for you to update in the future. Consider using [React Aria Components](https://react-spectrum.adobe.com/react-aria/) with our style macro to build a custom component with Spectrum styles instead. | ||
| We highly discourage overriding the styles of React Spectrum components because it may break at any time when we change our implementation, making it difficult for you to update in the future. Consider using [React Aria Components](https://react-spectrum.adobe.com/react-aria/) with our `style` macro to build a custom component with Spectrum styles instead. | ||
|
|
||
| With that being said, the `UNSAFE_className` and `UNSAFE_style` props are supported on Spectrum 2 components as last-resort escape hatches. | ||
|
|
||
|
|
@@ -153,7 +161,7 @@ Type scales include: UI, Body, Heading, Title, Detail, and Code. Each scale has | |
| <InlineAlert variant="notice"> | ||
| <Heading>Important Note</Heading> | ||
| <Content> | ||
| Only use `<Heading>` and `<Text>` inside Spectrum components with predefined styles (e.g., `<Dialog>`, `<MenuItem>`). They are unstyled by default and should not be used standalone. Use HTML elements with the style macro instead. | ||
| Only use `<Heading>` and `<Text>` inside Spectrum components with predefined styles (e.g., `<Dialog>`, `<MenuItem>`). They are unstyled by default and should not be used standalone. Use HTML elements with the `style` macro instead. | ||
|
||
| </Content> | ||
| </InlineAlert> | ||
|
|
||
|
|
@@ -195,13 +203,14 @@ function MyComponent({variant}: {variant: 'primary' | 'secondary'}) { | |
| } | ||
| ``` | ||
|
|
||
| Boolean conditions starting with `is` can be used directly without nesting: | ||
| Boolean conditions starting with `is` or `allows` can be used directly without nesting: | ||
|
|
||
| ```tsx | ||
| const styles = style({ | ||
| backgroundColor: { | ||
| default: 'gray-100', | ||
| isSelected: 'gray-900' | ||
| isSelected: 'gray-900', | ||
| allowsRemoving: 'gray-400' | ||
| } | ||
| }); | ||
|
|
||
|
|
@@ -222,7 +231,7 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; | |
| isSelected: 'gray-900' | ||
| } | ||
| })} | ||
| /> | ||
| /> | ||
| ``` | ||
|
|
||
| ### Nesting conditions | ||
|
|
@@ -308,9 +317,58 @@ const buttonStyle = style({ | |
| <Button styles={buttonStyle}>Press me</Button> | ||
| ``` | ||
|
|
||
| ## Setting CSS variables | ||
|
|
||
| CSS variables can be directly defined in a `style` macro, allowing child elements to then access them in their own styles. | ||
| A `type` should be provided to specify the CSS property type the `value` represents. | ||
|
|
||
| ```tsx | ||
| const parentStyle = style({ | ||
| '--rowBackgroundColor': { | ||
| type: 'backgroundColor', | ||
| value: 'gray-400' | ||
| } | ||
| }); | ||
|
|
||
| const childStyle = style({ | ||
| backgroundColor: '--rowBackgroundColor' | ||
| }); | ||
| ``` | ||
|
|
||
| ## 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. | ||
|
Comment on lines
+281
to
+286
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we export mergeStyles yet? I don't see it in our exports? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not yet, but there was mention of doing so a while back in the beta slack channel. I've put it in the S2 1.0 canvas so we can track that |
||
|
|
||
| ```tsx | ||
| // User can override the component's background color ONLY if it isn't "quiet" | ||
| const baselineStyles = style({backgroundColor: 'gray-100'}, ['backgroundColor']); | ||
| const quietStyles = style({backgroundColor: 'transparent'}); | ||
| const userStyles = style({backgroundColor: 'celery-600'}); | ||
|
|
||
| function MyComponent({isQuiet, styles}: {isQuiet?: boolean, styles?: StyleString}) { | ||
| let result = mergeStyles( | ||
| baselineStyles(null, styles), | ||
| isQuiet ? quietStyles : null | ||
| ); | ||
|
|
||
| return <div className={result}>My component</div> | ||
| } | ||
|
|
||
| // Displays quiet styles | ||
| <MyComponent isQuiet styles={userStyles} /> | ||
|
|
||
| // Displays user overrides | ||
| <MyComponent styles={userStyles} /> | ||
| ``` | ||
|
|
||
| The `iconStyle` macro should be used when styling Icons, see the [docs]((icons.html#iconstyle)) for more information. | ||
|
|
||
| ## CSS optimization | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optimization sounds so optional maybe it'd be better to structure all bundler setups into their own page which includes how the optimization setup works, but then it all sounds much more mandatory There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. happy for the team to weigh in here then, especially since it would fall within the changes made in #9126 |
||
|
|
||
| The style macro relies on CSS bundling and minification for optimal output. Follow these best practices: | ||
| The `style` macro relies on CSS bundling and minification for optimal output. Follow these best practices: | ||
|
|
||
| - Ensure styles are extracted into a CSS bundle; do not inject at runtime with `<style>` tags. | ||
| - Use a CSS minifier like `lightningcss` to deduplicate common rules (consider in dev for easier debugging). | ||
|
|
@@ -362,4 +420,39 @@ CSS resets are strongly discouraged. Global CSS selectors can unintentionally af | |
| /* App.css */ | ||
| @layer reset, _; | ||
| @import "reset.css" layer(reset); | ||
| ``` | ||
| ``` | ||
|
|
||
| ## Developing with style macros | ||
|
|
||
| Since `style` macros are quite different from using `className`/`style` directly, many may find it initially challenging to debug and develop against. | ||
| Below are some useful tools that may benefit your developer experience: | ||
|
|
||
| - 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. | ||
|
Comment on lines
+375
to
+376
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. todo: replace with the new devtool extension @snowystinger is making |
||
|
|
||
| - This [sandbox](https://codesandbox.io/p/devbox/react-spectrum-s2-style-macro-template-h6fpsq) is preconfigured to support React Spectrum S2, React Aria Components, and | ||
snowystinger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| the `style` macros for quick prototyping. | ||
|
|
||
| - 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 commentThe 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 commentThe 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 |
||
|
|
||
| > I'm getting a "Could not statically evaluate macro argument" error. | ||
|
|
||
| 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. | ||
|
||
|
|
||
| > I'm seeing a ton of duplicate rules being generated and/or my dev tools are very slow. | ||
|
|
||
| Please make sure you've followed the [best practices listed above](#css-optimization). | ||
|
|
||
| > 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. | ||
|
||
|
|
||
| > I'm coming from S1, but where are Flex/Grid/etc? | ||
|
|
||
| These no longer exist. Please style `<div>`, `<span>`, and other standard HTML elements with the `style` macro instead. | ||
Uh oh!
There was an error while loading. Please reload this page.