Skip to content

feat(scroll-area): add contentProps to ScrollArea.ViewportFeat/scroll area content props#3810

Open
resdust wants to merge 4 commits intoradix-ui:mainfrom
resdust:feat/scroll-area-content-props
Open

feat(scroll-area): add contentProps to ScrollArea.ViewportFeat/scroll area content props#3810
resdust wants to merge 4 commits intoradix-ui:mainfrom
resdust:feat/scroll-area-content-props

Conversation

@resdust
Copy link
Copy Markdown

@resdust resdust commented Feb 11, 2026

Description

ScrollArea.Viewport renders an internal <div> wrapper around its children with an inline style of display: table; min-width: 100%. This is intentional — the table layout ensures accurate content size measurement for scrollbar thumb sizing.

However, this forces a table layout on all consumers, which conflicts with common patterns like flex or grid layouts. Today the only workaround is !important in CSS, which is fragile and goes against styling best practices.

This PR adds a contentProps prop to ScrollArea.Viewport that forwards attributes to the internal content wrapper <div>, allowing consumers to override display (and other props) cleanly:

<ScrollArea.Viewport
contentProps={{
style: { display: 'flex', flexDirection: 'column' },
className: 'my-content',
}}

{children}
</ScrollArea.Viewport>

Style merging strategy: base styles (minWidth: 100%, display: table) are applied first, then contentProps.style spreads on top — so consumers can selectively override only what they need while the rest is preserved.

Checklist

[x] Code change in packages/react/scroll-area/src/scroll-area.tsx
[x] Tests added in packages/react/scroll-area/src/scroll-area.test.tsx (8 tests, all passing)
[x] Storybook example added (ContentProps story) comparing default vs overridden layout
[x] JSDoc with usage notes and caveats on the new prop
[x] No breaking changes — contentProps is optional, defaults to undefined

Test plan

pnpm test — 8 new tests covering:

  • Default behavior: content wrapper has display: table and minWidth: 100%
  • contentProps.style overrides display while preserving minWidth
  • contentProps.style overrides minWidth while preserving display
  • contentProps.className forwarded to content wrapper
  • contentProps data attributes forwarded
  • Children render correctly with contentProps
    pnpm dev — Storybook ContentProps story shows side-by-side comparison

瑭瑾 and others added 3 commits February 11, 2026 15:18
Add a `contentProps` prop to `ScrollAreaViewport` that allows consumers
to pass attributes (including style overrides) to the internal content
wrapper `div`.

The content wrapper uses `display: table` by default to ensure accurate
scroll width/height measurement for thumb sizing. However, this can
conflict with common layout patterns (e.g. flex columns in chat lists,
vertical-only scroll containers) where `display: table` causes children
to overflow their container width.

With `contentProps`, consumers can now override the display mode without
resorting to `!important` in CSS:

```tsx
<ScrollArea.Viewport
  contentProps={{ style: { display: 'flex', flexDirection: 'column' } }}
>
  {children}
</ScrollArea.Viewport>
```

The default styles (`minWidth: '100%'`, `display: 'table'`) are preserved
as base values and can be selectively overridden via `contentProps.style`.
Verify that the new contentProps prop correctly forwards attributes
(style, className, data-*) to the internal content wrapper div,
and that base styles (minWidth, display) are preserved or overridable.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 11, 2026

🦋 Changeset detected

Latest commit: 9a0051f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@radix-ui/react-scroll-area Minor
radix-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant