static/app/components/core/slideOverPanel/slideOverPanel.mdx
import * as Storybook from 'sentry/stories';
import { SlideOverPanelPlayground, SlideOverPanelSkeletonPlayground, } from 'sentry/stories/playground/slideOverPanel';
export const documentation = import('!!type-loader!@sentry/scraps/slideOverPanel');
The SlideOverPanel component is a panel that can appear on the right, left, or bottom of the page content to reveal more information. It's commonly used for UIs like the Widget Builder to open panels that provide more details or supplementary UIs.
<Storybook.Demo> <SlideOverPanelPlayground /> </Storybook.Demo>
<Button onClick={() => setIsPanelOpen(true)}>Open Panel</Button>;
{
isPanelOpen && (
<SlideOverPanel position="right">
<Container border="primary" height="100%" padding="md">
<Button onClick={() => setIsPanelOpen(false)}>Close Panel</Button>
</Container>
</SlideOverPanel>
);
}
SlideOverPanel defers rendering its contents. When the panel is rendered, it will open immediately, and its contents will render in a subsequent pass. This means the panel can respond immediately to user input even if the contents of the panel are expensive to render. This is much better UX, and improves INP.
In the example below, you can see that the panel contents take a very long time to render, but the panel opens right away, and can be closed while the content is still rendering.
<Storybook.Demo> <SlideOverPanelSkeletonPlayground /> </Storybook.Demo>
By default, the panel is empty while the contents render. If the contents are very expensive to render, we recommend providing a skeleton UI.
To enable a loading skeleton, pass a render prop as the children to SlideOverPanel, and conditionally render a skeleton based on the isOpening prop.
<Button onClick={() => setIsPanelOpen(true)}>Open Panel</Button>
{isPanelOpen && (
<SlideOverPanel position="right">
{(options: {isOpening: boolean}) => {
return options.isOpening ? (
<SkeletonPanelContents onClick={closePanel} />
) : (
<PanelContents onClick={closePanel} />
);
}}
</SlideOverPanel>
)}
Generally, we recommend not animating the panel on close, and simply removing it from the UI. In cases where you need to animate closing it (e.g., if it's coordinated with another animation), please wrap the panel in <AnimatePresence>.
<Button onClick={() => setIsPanelOpen(true)}>Open Panel</Button>
<AnimatePresence>
{isPanelOpen && (
<SlideOverPanel position="right">
{(options: {isOpening: boolean}) => {
return options.isOpening ? (
<SkeletonPanelContents onClick={closePanel} />
) : (
<PanelContents onClick={closePanel} />
);
}}
</SlideOverPanel>
)}
</AnimatePresence>