-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
core: add Stack and Separator component #97052
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d6a5b79
core: add separator component
JonasBa fea52e6
core: fix test
JonasBa 580d7da
core: add responsiveValueProp tests
JonasBa e3f740f
core: isolate useActiveBreakpoint
JonasBa 43d75f3
remove unused export
JonasBa fd4b4f8
ref: use AbortController and sync external store
JonasBa c43acae
Merge branch 'master' into jb/core/divider
JonasBa 2f51328
test: fix abortcontroller test
JonasBa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export {Container} from './container'; | ||
export {Flex} from './flex'; | ||
export {Grid} from './grid'; | ||
export {Stack} from './stack'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
--- | ||
title: Stack | ||
description: A simplified layout component built on Flex that provides easy vertical stacking with responsive props and spacing controls. | ||
source: 'sentry/components/core/layout/stack' | ||
resources: | ||
js: https://github.com/getsentry/sentry/blob/master/static/app/components/core/layout/stack.tsx | ||
--- | ||
|
||
import {Container, Stack} from 'sentry/components/core/layout'; | ||
import * as Storybook from 'sentry/stories'; | ||
|
||
import APIReference from '!!type-loader!sentry/components/core/layout/stack'; | ||
|
||
export const types = {Stack: APIReference.Stack}; | ||
|
||
export function CustomComponent(props) { | ||
return <div {...props} />; | ||
} | ||
|
||
The `Stack` component is a simplified layout component built on top of the `Flex` component. It provides a focused API for common stacking layouts with only the essential props: `direction`, `align`, `justify`, and `gap`. By default, Stack uses column direction making it perfect for vertical layouts. | ||
|
||
## Basic Usage | ||
|
||
To create a basic vertical stack, wrap elements in `<Stack>` and they will be laid out vertically using flexbox. | ||
|
||
```jsx | ||
<Stack> | ||
<div>Item 1</div> | ||
<div>Item 2</div> | ||
<div>Item 3</div> | ||
</Stack> | ||
``` | ||
|
||
### When to Use Stack vs Flex | ||
|
||
Use `Stack` when you need a simple, focused layout component for common stacking patterns. It's perfect for: | ||
|
||
- Vertical lists or forms | ||
- Simple horizontal arrangements | ||
- Basic responsive layouts | ||
|
||
Use `Flex` when you need the full power of flexbox with properties like `wrap`, `flex`, `inline`, or complex alignment scenarios. | ||
|
||
### Composition | ||
|
||
The `Stack` implements composition via <a href="/stories/layout/composition">render prop</a> pattern. | ||
|
||
<Storybook.Demo> | ||
<Stack | ||
border="primary" | ||
radius="md" | ||
padding="md" | ||
justify="between" | ||
background="primary" | ||
width="80%" | ||
gap="md" | ||
> | ||
{props => ( | ||
<CustomComponent {...props}> | ||
<Container padding="sm" border="primary" radius="sm" background="surface"> | ||
First Item | ||
</Container> | ||
<Container padding="sm" border="primary" radius="sm" background="surface"> | ||
Second Item | ||
</Container> | ||
<Container padding="sm" border="primary" radius="sm" background="surface"> | ||
Third Item | ||
</Container> | ||
</CustomComponent> | ||
)} | ||
</Stack> | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack width="80%" justify="between" gap="md"> | ||
{props => ( | ||
<CustomComponent {...props}> | ||
<div>First Item</div> | ||
<div>Second Item</div> | ||
<div>Third Item</div> | ||
</CustomComponent> | ||
)} | ||
</Stack> | ||
``` | ||
|
||
### Specifying the DOM Node via `as` prop | ||
|
||
The `Stack` component renders a `div` element by default, but you can specify the DOM node to render by passing a `as` prop. | ||
|
||
```tsx | ||
<Stack as="section" padding="md" background="primary"> | ||
Basic stack content | ||
</Stack> | ||
``` | ||
|
||
### Stack Properties | ||
|
||
Stack provides a focused set of layout properties: `direction` (defaults to 'column'), `gap`, `justify`, and `align`. These properties influence the layout of its children while maintaining simplicity. | ||
|
||
Like other layout components, `Stack` inherits all spacing props like `m`, `p`, `mt`, `mb`, `ml`, `mr`, `pt`, `pb`, `pl`, `pr` and implements responsive props so that the layout can be changed per breakpoint. | ||
|
||
#### Column Direction (Default) | ||
|
||
<Storybook.Demo> | ||
<Stack gap="md" justify="center" align="center" padding="md"> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 1 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 2 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 3 | ||
</Container> | ||
</Stack> | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack gap="md" justify="center" align="center" padding="md"> | ||
<div>Item 1</div> | ||
<div>Item 2</div> | ||
<div>Item 3</div> | ||
</Stack> | ||
``` | ||
|
||
#### Row Direction | ||
|
||
<Storybook.Demo> | ||
<Stack direction="row" gap="md" justify="between" align="center" padding="md"> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 1 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 2 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 3 | ||
</Container> | ||
</Stack> | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack direction="row" gap="md" justify="between" align="center" padding="md"> | ||
<div>Item 1</div> | ||
<div>Item 2</div> | ||
<div>Item 3</div> | ||
</Stack> | ||
``` | ||
|
||
#### Spacing | ||
|
||
The `Stack` `gap` property follows the same spacing system as other layout components. | ||
|
||
<Storybook.Demo> | ||
{['xs', 'sm', 'md', 'lg', 'xl', '2xl'].map(size => ( | ||
<Stack direction="column" gap="sm" key={size}> | ||
<strong>{size} gap</strong> | ||
<Stack m="md" gap={size} align="center"> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 1 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 2 | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Item 3 | ||
</Container> | ||
</Stack> | ||
</Stack> | ||
))} | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack m="md" gap="xs"> | ||
<div>Item 1</div> | ||
<div>Item 2</div> | ||
<div>Item 3</div> | ||
</Stack> | ||
``` | ||
|
||
#### Responsive Props | ||
|
||
All props support responsive values using breakpoint objects. Breakpoints are: `xs`, `sm`, `md`, `lg`, `xl`, `2xl`. | ||
|
||
Example of a responsive stack that uses a static gap, but changes direction based on the breakpoint. | ||
|
||
<Storybook.Demo> | ||
<Stack direction={{xs: 'column', sm: 'row', md: 'column'}} gap="md" p="md"> | ||
JonasBa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Responsive | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Stack | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Layout | ||
</Container> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
🔥 | ||
</Container> | ||
</Stack> | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack | ||
// Direction = column on xs, row on sm, column on md | ||
direction={{xs: 'column', sm: 'row', md: 'column'}} | ||
// Gap = md on all sizes | ||
gap="md" | ||
> | ||
<div>Responsive</div> | ||
<div>Stack</div> | ||
<div>Layout</div> | ||
<div>🔥</div> | ||
</Stack> | ||
``` | ||
|
||
If a prop is not specified for a breakpoint, the value will **not** be inherited from the previous breakpoint. | ||
|
||
### Stack Separator | ||
|
||
The `Stack` component provides a `Stack.Separator` subcomponent that can be used to add visual separators between stack items. The `Stack.Separator` automatically inherits the orientation from its parent Stack component through React context: | ||
|
||
- When Stack `direction` is `row` or `row-reverse` → Separator orientation becomes `horizontal` | ||
- When Stack `direction` is `column` or `column-reverse` → Separator orientation becomes `vertical` | ||
|
||
This automatic orientation inheritance means separators adapt seamlessly to responsive direction changes without requiring manual orientation props. The separator uses the `border` prop (defaults to `'primary'`) and automatically applies the correct styling based on the inherited orientation. | ||
|
||
<Storybook.Demo> | ||
<Stack gap="md" direction={{sm: 'column', md: 'row'}}> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
First Item | ||
</Container> | ||
<Stack.Separator border="primary" /> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Second Item | ||
</Container> | ||
<Stack.Separator border="primary" /> | ||
<Container padding="md" border="primary" radius="md" background="primary"> | ||
Third Item | ||
</Container> | ||
</Stack> | ||
</Storybook.Demo> | ||
```jsx | ||
<Stack gap="md" direction={{sm: 'column', md: 'row'}}> | ||
<div>First Item</div> | ||
<Stack.Separator border="primary" /> | ||
<div>Second Item</div> | ||
<Stack.Separator border="primary" /> | ||
<div>Third Item</div> | ||
</Stack> | ||
``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.