Skip to content

feat: Add prose macro#10161

Open
devongovett wants to merge 23 commits into
mainfrom
prose
Open

feat: Add prose macro#10161
devongovett wants to merge 23 commits into
mainfrom
prose

Conversation

@devongovett

@devongovett devongovett commented Jun 5, 2026

Copy link
Copy Markdown
Member

Adds a prose() macro to S2 that styles semantic HTML elements within it, e.g. headings, paragraphs, code, etc. Useful for displaying markdown and other article content.

It's in a layer that is before the style macro, so regardless of its specificity, the style macro can override it.

I was unable to make use of @scope, it's not available in FF until 146 and Chromatic is still at 141, so I figured it was a bad idea to push it in right now.
I think it's probably ok to leave support out for now, scope worked really well when i used it. Creating a fallback for it would have increased the size of the css. I thought about adding a :not or using revert-layer

@github-actions github-actions Bot added the S2 label Jun 5, 2026
@rspbot

rspbot commented Jun 5, 2026

Copy link
Copy Markdown

textDecoration: 'underline',
transition: 'color 200ms'
},
':is(h1, h2, h3, h4, h5, h6, hr) + *': {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

gap between headings and following paragraphs should collapse to the smaller of the two (heading)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

don't css margins collapse already when siblings? I guess they collapse to the larger of the two, not the smaller... so do we want to have a different behaviour?

from looking at tailwind, I guess they are doing the same thing, so it's probably ok

@rspbot

rspbot commented Jun 5, 2026

Copy link
Copy Markdown

textDecoration: 'underline',
transition: 'color 200ms'
},
':is(h1, h2, h3, h4, h5, h6, hr) + *': {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

don't css margins collapse already when siblings? I guess they collapse to the larger of the two, not the smaller... so do we want to have a different behaviour?

from looking at tailwind, I guess they are doing the same thing, so it's probably ok

ol: {
listStyleType: 'decimal'
},
'li > p:last-child:not(:first-child)': {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is going to have a higher specificity than the others in this file, instead of 1 element or 0 0 1, this would be 0 2 2
(I am intentionally ignoring the leading classname "prose" for this, technically everything is one classname 0 1 0 higher than normal classes in our style macro)

again I see the tailwind prose has a bunch of selectors that violate that, so it's probably ok


let css = '';
for (let key in rules) {
let selector = key === '.prose' ? '.prose' : `.prose ${key}`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

how will prose work through mergeStyles? and will it also get a version appended to it?

return 'prose';
}

function font(value: keyof typeof fontSize) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

anything we need to do to keep this in sync with the spectrum-theme shorthand?
looks like the addition of --fs is really all that differs


const fontWeightBase = {
normal: '400',
normal: {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why do you have to provide a default key in an object for these?

} as const;

const i18nFonts = {
export const i18nFonts = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

doesn't look like anything is using this?

export default meta;

export const Example = () => (
<article className={`${prose()} ${style({maxWidth: 800, marginX: 'auto'})}`}>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

so if someone does one of these? Since prose already attaches font('body') to itself

<article className={`${mergeStyles(prose(), style({maxWidth: 800, marginX: 'auto'}))`}>
<article className={`${prose()} ${style({maxWidth: 800, marginX: 'auto', font: 'title'})}`}>

@devongovett

Copy link
Copy Markdown
Member Author

You don't need to review wips @snowystinger 😉

@snowystinger

Copy link
Copy Markdown
Member

I know, but it's a good idea and I was just writing down any questions I had. Feel free to ignore.

@rspbot

rspbot commented Jun 18, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jun 18, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jun 18, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jun 18, 2026

Copy link
Copy Markdown

export function prose(this: MacroContext | void) {
let rules = {
'.prose': font('body'),
h1: {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Notes for the redline work:

use token name for font instead of h1
use token name for margin instead of em size

any other call outs for special cases?

put this into context in our Thread/Chat component
maybe in a Dialog with Chat as well?

@rspbot

rspbot commented Jul 8, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jul 8, 2026

Copy link
Copy Markdown

@snowystinger snowystinger changed the title wip: Add prose macro feat: Add prose macro Jul 15, 2026
@rspbot

rspbot commented Jul 15, 2026

Copy link
Copy Markdown

@snowystinger
snowystinger marked this pull request as ready for review July 15, 2026 05:19
@rspbot

rspbot commented Jul 17, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jul 17, 2026

Copy link
Copy Markdown

# Conflicts:
#	packages/react-aria/src/tokenfield/useTokenField.ts
@rspbot

rspbot commented Jul 20, 2026

Copy link
Copy Markdown

Comment thread packages/@react-spectrum/s2/style/style-macro.ts Outdated
Comment thread packages/@react-spectrum/ai/src/style/prose.ts Outdated
Comment thread packages/@react-spectrum/ai/src/style/prose.ts Outdated
Comment thread packages/@react-spectrum/ai/src/style/spectrum-theme.ts Outdated

// A Chat rendered inside an S2 Popover, where the system response is prose
// (markdown) styled with the `prose` macro.
export function ChatPopover() {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

why is it in a popover?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Design wanted this as an example they could try out 🤷🏻

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

hmm a chat in a popover is strange example. maybe they meant a Dialog? but either way would be nice to have prose in the other examples not in there as well

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

re-watched sync, they said Dialog, i'll update that

@rspbot

rspbot commented Jul 21, 2026

Copy link
Copy Markdown


// A Chat rendered inside an S2 Popover, where the system response is prose
// (markdown) styled with the `prose` macro.
export function ChatPopover() {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

hmm a chat in a popover is strange example. maybe they meant a Dialog? but either way would be nice to have prose in the other examples not in there as well

Comment thread packages/@react-spectrum/ai/src/style/spectrum-theme.ts Outdated
Comment thread packages/@react-spectrum/ai/src/style/prose.ts Outdated
@rspbot

rspbot commented Jul 21, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Jul 21, 2026

Copy link
Copy Markdown

Agent Skills Changes

Removed (90)
  • react-aria/skills/react-aria/references/components/Breadcrumbs/useBreadcrumbs.md
  • react-aria/skills/react-aria/references/components/Button/useButton.md
  • react-aria/skills/react-aria/references/components/Calendar/useCalendar.md
  • react-aria/skills/react-aria/references/components/Checkbox/useCheckbox.md
  • react-aria/skills/react-aria/references/components/CheckboxGroup/useCheckboxGroup.md
  • react-aria/skills/react-aria/references/components/ColorArea/useColorArea.md
  • react-aria/skills/react-aria/references/components/ColorField/useColorField.md
  • react-aria/skills/react-aria/references/components/ColorSlider/useColorSlider.md
  • react-aria/skills/react-aria/references/components/ColorSwatch/useColorSwatch.md
  • react-aria/skills/react-aria/references/components/ColorWheel/useColorWheel.md
  • react-aria/skills/react-aria/references/components/ComboBox/useComboBox.md
  • react-aria/skills/react-aria/references/components/DateField/useDateField.md
  • react-aria/skills/react-aria/references/components/DatePicker/useDatePicker.md
  • react-aria/skills/react-aria/references/components/DateRangePicker/useDateRangePicker.md
  • react-aria/skills/react-aria/references/components/Disclosure/useDisclosure.md
  • react-aria/skills/react-aria/references/components/GridList/useGridList.md
  • react-aria/skills/react-aria/references/components/Link/useLink.md
  • react-aria/skills/react-aria/references/components/ListBox/useListBox.md
  • react-aria/skills/react-aria/references/components/Menu/useMenu.md
  • react-aria/skills/react-aria/references/components/Meter/useMeter.md
  • react-aria/skills/react-aria/references/components/Modal/useModalOverlay.md
  • react-aria/skills/react-aria/references/components/NumberField/useNumberField.md
  • react-aria/skills/react-aria/references/components/Popover/usePopover.md
  • react-aria/skills/react-aria/references/components/ProgressBar/useProgressBar.md
  • react-aria/skills/react-aria/references/components/RadioGroup/useRadioGroup.md
  • react-aria/skills/react-aria/references/components/RangeCalendar/useRangeCalendar.md
  • react-aria/skills/react-aria/references/components/SearchField/useSearchField.md
  • react-aria/skills/react-aria/references/components/Select/useSelect.md
  • react-aria/skills/react-aria/references/components/Separator/useSeparator.md
  • react-aria/skills/react-aria/references/components/Slider/useSlider.md
  • react-aria/skills/react-aria/references/components/Switch/useSwitch.md
  • react-aria/skills/react-aria/references/components/Table/useTable.md
  • react-aria/skills/react-aria/references/components/Tabs/useTabList.md
  • react-aria/skills/react-aria/references/components/TagGroup/useTagGroup.md
  • react-aria/skills/react-aria/references/components/TextField/useTextField.md
  • react-aria/skills/react-aria/references/components/TimeField/useTimeField.md
  • react-aria/skills/react-aria/references/components/Toast/useToast.md
  • react-aria/skills/react-aria/references/components/ToggleButton/useToggleButton.md
  • react-aria/skills/react-aria/references/components/ToggleButtonGroup/useToggleButtonGroup.md
  • react-aria/skills/react-aria/references/components/Toolbar/useToolbar.md
  • react-aria/skills/react-aria/references/components/Tooltip/useTooltipTrigger.md
  • react-aria/skills/react-aria/references/guides/hooks.md
  • react-aria/skills/react-aria/references/interactions/useDraggableCollection.md
  • react-aria/skills/react-aria/references/interactions/useDroppableCollection.md
  • react-aria/skills/react-aria/references/utilities/useListFormatter.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Breadcrumbs/useBreadcrumbs.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Button/useButton.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Calendar/useCalendar.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Checkbox/useCheckbox.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/CheckboxGroup/useCheckboxGroup.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ColorArea/useColorArea.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ColorField/useColorField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ColorSlider/useColorSlider.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ColorSwatch/useColorSwatch.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ColorWheel/useColorWheel.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ComboBox/useComboBox.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/DateField/useDateField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/DatePicker/useDatePicker.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/DateRangePicker/useDateRangePicker.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Disclosure/useDisclosure.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/GridList/useGridList.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Link/useLink.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ListBox/useListBox.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Menu/useMenu.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Meter/useMeter.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Modal/useModalOverlay.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/NumberField/useNumberField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Popover/usePopover.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ProgressBar/useProgressBar.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/RadioGroup/useRadioGroup.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/RangeCalendar/useRangeCalendar.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/SearchField/useSearchField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Select/useSelect.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Separator/useSeparator.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Slider/useSlider.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Switch/useSwitch.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Table/useTable.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Tabs/useTabList.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/TagGroup/useTagGroup.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/TextField/useTextField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/TimeField/useTimeField.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Toast/useToast.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ToggleButton/useToggleButton.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/ToggleButtonGroup/useToggleButtonGroup.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Toolbar/useToolbar.md
  • s2/skills/react-spectrum-s2/references/react-aria/components/Tooltip/useTooltipTrigger.md
  • s2/skills/react-spectrum-s2/references/react-aria/guides/hooks.md
  • s2/skills/react-spectrum-s2/references/react-aria/interactions/useDraggableCollection.md
  • s2/skills/react-spectrum-s2/references/react-aria/interactions/useDroppableCollection.md
  • s2/skills/react-spectrum-s2/references/react-aria/utilities/useListFormatter.md
Modified (33)
Install

React Spectrum S2:

npx skills add https://d1pzu54gtk2aed.cloudfront.net/pr/980c983ef8d70ad35507748f8f021512d5b4a7c8/

React Aria:

npx skills add https://d5iwopk28bdhl.cloudfront.net/pr/980c983ef8d70ad35507748f8f021512d5b4a7c8/

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants