Project: workspace-doctolib · Branch: HEAD · Mode: ` · **Model:**claude-haiku-4-5-20251001`
Stats: 1 user messages, 29 tool calls, tools used: Bash, Read.
Conversation
Turn 1 — User
Explore the Oxygen design system at /Users/USER/workspace/doctolib/oxygen to understand:
- What Modal/Dialog components are available (look in packages/ directory)
- What layout primitives exist (Stack, Box, etc.) that support flex/overflow
- Whether there are any "SidePanel" or "FilterPanel" components
- Any existing scrollable container patterns
Specifically look for: - Modal or Dialog component that would host NHRDocumentList - Components with overflow-y-auto or scroll behavior - Any layout patterns that combine a sticky header + scrollable content + sticky footer
List the relevant component names and their file paths. Read the source of the most relevant ones (Modal, Dialog, Stack, Box).
Turn 1 — Assistant
I'll explore the Oxygen design system to understand the available components and patterns. Let me start by examining the directory structure.
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen -type f -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" | head -30
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/commitlint.config.ts /Users/USER/workspace/doctolib/oxygen/lint-staged.config.js /Users/USER/workspace/doctolib/oxygen/prettier.config.js /Users/USER/workspace/doctolib/oxygen/vite/svg-plugin.ts /Users/USER/workspace/doctolib/oxygen/vite/vite.config.base.ts /Users/USER/workspace/doctolib/oxygen/scripts/check-exports.ts /Users/USER/workspace/doctolib/oxygen/scripts/extract-package-info-from-paths.test.ts /Users/USER/workspace/doctolib/oxygen/scripts/extract-p …(truncated, 2349 more chars)
Let me explore the packages directory structure to find Modal/Dialog components:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/oxygen/packages/ | grep -E "^d"
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 384 B Wed Feb 25 13:12:45 2026 . drwxr-xr-x clertonra staff 1.3 KB Fri Mar 13 11:56:52 2026 .. drwxr-xr-x clertonra staff 608 B Fri Mar 13 11:56:52 2026 b2b drwxr-xr-x clertonra staff 576 B Fri Mar 13 11:56:52 2026 b2c drwxr-xr-x clertonra staff 448 B Wed Feb 25 13:12:44 2026 codemods drwxr-xr-x clertonra staff 832 B Fri Mar 13 11:56:52 2026 core drwxr-xr-x clertonra staff 544 B Fri Mar 13 11:56:52 2026 icons drwxr-xr-x clertonra staff 480 B Fri Mar 13 11:56:52 …(truncated, 303 more chars)
Let me look at the core package which likely contains the main components:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/oxygen/packages/core/src/components/ 2>/dev/null | head -50
Tool results:
→ result (ok): (Bash completed with no output)
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen/packages/core -type d -name "src" | head -5
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/oxygen/packages/core/src/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 1.1 KB Wed Feb 25 13:12:44 2026 . drwxr-xr-x clertonra staff 832 B Fri Mar 13 11:56:52 2026 .. drwxr-xr-x clertonra staff 224 B Wed Feb 25 13:12:44 2026 a11y drwxr-xr-x clertonra staff 256 B Wed Feb 25 13:12:44 2026 actions drwxr-xr-x clertonra staff 96 B Wed Feb 25 13:12:44 2026 collection drwxr-xr-x clertonra staff 256 B Wed Feb 25 13:12:44 2026 common .rw-r--r-- clertonra staff 45 B Wed Feb 25 13:12:44 2026 constants.ts drwxr-xr-x clertonra staff 832 B Wed …(truncated, 1872 more chars)
Good! I can see there's an "overlays" directory (likely contains Modal/Dialog) and a "layout" directory. Let me search for Modal and Dialog components:
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen/packages/core/src -type f \( -name "*Modal*" -o -name "*Dialog*" -o -name "*SidePanel*" -o -name "*FilterPanel*" \)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src/inlined/react-overlays/Modal.jsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/inlined/react-overlays/ModalManager.js /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalFooter/ModalFooter.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalFooter/ModalFooter.scss /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Dialog/Dialog.scss /Users/USER/workspace/doctolib/oxygen/package …(truncated, 1704 more chars)
Excellent! Now let me look at the layout components:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 512 B Fri Mar 13 11:56:52 2026 . drwxr-xr-x clertonra staff 1.1 KB Wed Feb 25 13:12:44 2026 .. drwxr-xr-x clertonra staff 192 B Wed Feb 25 13:12:44 2026 bleed drwxr-xr-x clertonra staff 288 B Fri Mar 13 11:56:52 2026 carousel drwxr-xr-x clertonra staff 256 B Wed Feb 25 13:12:44 2026 Columns .rw-r--r-- clertonra staff 14 KB Wed Feb 25 13:12:44 2026 HStack.stories.tsx .rw-r--r-- clertonra staff 1.0 KB Wed Feb 25 13:12:44 2026 HStack.test-helpers.ts .rw-r--r-- clerto …(truncated, 653 more chars)
Now let me search for Box component and any scrollable patterns:
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen/packages/core/src -type f -name "*Box*" -o -name "*Stack*" | grep -E "\.(tsx|ts)$"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/MultipleComboBox/AlphaMultipleComboBox.stories.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/MultipleComboBox/AlphaMultipleComboBox.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/ComboBox/BetaComboBox.interactions.stories.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/ComboBox/BetaComboBox.stories.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/ComboBox/BetaCo …(truncated, 990 more chars)
Let me search for any component that has "overflow" or "scroll" in it:
Tools used:
Bash:grep -r "overflow-y-auto\|overflow.*scroll\|scrollable\|SidePanel\|FilterPanel" /Users/USER/workspace/doctolib/oxygen/packages/core/src --include="*.tsx" --include="*.ts" -l
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Drawer/Drawer.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Popover/Popover.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.stories.tsx /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanelHeader/AlphaSidePanelHeader.tsx /Users/USER/wor …(truncated, 256 more chars)
Perfect! Let me also check the overlays directory to see all available components:
Tools used:
Bash:ls -la /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/
Tool results:
→ result (ok): drwxr-xr-x clertonra staff 448 B Wed Feb 25 13:12:44 2026 . drwxr-xr-x clertonra staff 1.1 KB Wed Feb 25 13:12:44 2026 .. drwxr-xr-x clertonra staff 128 B Wed Feb 25 13:12:44 2026 _ModalTransition drwxr-xr-x clertonra staff 160 B Wed Feb 25 13:12:44 2026 AlphaSidePanel drwxr-xr-x clertonra staff 128 B Wed Feb 25 13:12:44 2026 AlphaSidePanelHeader drwxr-xr-x clertonra staff 160 B Wed Feb 25 13:12:44 2026 Backdrop drwxr-xr-x clertonra staff 160 B Wed Feb 25 13:12:44 2026 ContextualPopover dr …(truncated, 468 more chars)
Excellent! Now let me read the source code of the key components. Let me start with Modal, Dialog, and the SidePanel components:
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Modal/Modal.tsx
Tool results:
→ result (ok): 1 import { 2 forwardRef, 3 useRef, 4 type ReactElement, 5 type ReactEventHandler, 6 type ReactNode, 7 type SyntheticEvent, 8 } from 'react' 9 import MaterialModal from '@mui/material/Modal' 10 import classNames from 'classnames' 11 import { v4 as uuidv4 } from 'uuid' 12 import { _Transition as Transition } from '../_ModalTransition/_ModalTransition' 13 import { IconButton } from '../../actions/IconButton/v2/IconButton' 14 import { Button } from '../../actions/Button/Button' 15 import …(truncated, 7424 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Dialog/Dialog.tsx
Tool results:
→ result (ok): 1 import './Dialog.scss'
2
3 import classNames from 'classnames'
4 import type { DesignSystemIconComponent } from '@doctolib/design-system-icons'
5 import type { ReactEventHandler, ReactNode } from 'react'
6
7 import { Button } from '../../actions/Button/Button'
8 import type { IconName } from '../../dataDisplay/Icon/Icon'
9 import { Modal, type ModalProps } from '../Modal/Modal'
10 import { ModalBody } from '../ModalBody/ModalBody'
11 import { ModalFooter } from '../ModalFooter/ModalFooter'
1
…(truncated, 2750 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.tsx
Tool results:
→ result (ok): 1 import '../Backdrop/Backdrop.scss'
2
3 import type { Attributes, ReactElement, ReactEventHandler, ReactNode, SyntheticEvent } from 'react'
4 import { Children, cloneElement, forwardRef, isValidElement, useId } from 'react'
5 import classNames from 'classnames'
6 import MaterialModal from '@mui/material/Modal'
7
8 import {
9 AlphaSidePanelHeader,
10 type InternalSidePanelHeaderProps,
11 type SidePanelHeaderProps,
12 } from '../AlphaSidePanelHeader/AlphaSidePanelHeader'
13 import type {
…(truncated, 5946 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/VStack.tsx
Tool results:
→ result (ok): 1 import { type CommonProps, Flex, type SpecificProps } from './private/Flex'
2 import type { GapValue } from './private/tokensHelper'
3
4 // VStack has slightly different align prop (no stretch)
5 type Alignment = Exclude<CommonProps['align'], 'stretch'>
6
7 type Props = Omit<CommonProps, 'align' | 'gap'> &
8 Pick<SpecificProps, 'width' | 'maxWidth' | 'minWidth' | 'height' | 'maxHeight' | 'minHeight'> & {
9 /*
10 * Space separating each child item
11 /
12 gap?: GapValue
…(truncated, 876 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/HStack.tsx
Tool results:
→ result (ok): 1 import { type CommonProps, Flex, type SpecificProps } from './private/Flex'
2
3 type Props = Omit<CommonProps, 'align' | 'justify'> &
4 Pick<SpecificProps, 'width' | 'maxWidth' | 'minWidth'> & {
5 /
6 * Vertical alignment of items
7 */
8 align?: CommonProps['align']
9 /
10 * Horizontal distribution of items
11 /
12 justify?: CommonProps['justify']
13 /
14 * Allow wrapping to next line when items don't fit
15 /
16 hasWrap?: Specif
…(truncated, 739 more chars)
Now let me read the Flex component (which powers VStack/HStack) and check the SCSS files for scroll patterns:
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/private/Flex.tsx
Tool results:
→ result (ok): 1 import classNames from 'classnames'
2 import type { ReactNode } from 'react'
3 import styled from '@emotion/styled'
4
5 import { type DataAttribute, filterDataAttributes } from '../../common/DataAttribute/DataAttribute'
6 import { type Gap, getGapValues, getPaddingValues, type Padding } from './tokensHelper'
7 import styles from './Flex.module.css'
8
9 export const SEMANTIC_ELEMENTS = [
10 'div',
11 'section',
12 'article',
13 'aside',
14 'header',
15 'footer',
16 'nav',
17 '
…(truncated, 4737 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalBody/ModalBody.tsx
Tool results:
→ result (ok): 1 import type { ReactElement, ReactNode } from 'react'
2 import { forwardRef } from 'react'
3 import classNames from 'classnames'
4 import { usePlatform } from '../../hooks/usePlatform'
5 import { DrawerBody } from '../Drawer/Drawer'
6 import './ModalBody.scss'
7
8 type Props = {
9 alignText?: 'auto' | 'center' | 'left' | 'right'
10 children: ReactNode
11 uiStyle?: 'normal' | 'dialog'
12 disableDrawerOnMobile?: boolean
13 className?: string
14 }
15
16 export const ModalBody = forward
…(truncated, 787 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalFooter/ModalFooter.tsx
Tool results:
→ result (ok): 1 import type { ReactElement, ReactNode } from 'react'
2 import classNames from 'classnames'
3 import { usePlatform } from '../../hooks/usePlatform'
4 import { DrawerFooter } from '../Drawer/Drawer'
5 import './ModalFooter.scss'
6
7 type Props = {
8 children: ReactNode
9 divider?: boolean
10 padding?: boolean
11 position?: 'right'
12 uiStyle?: 'normal' | 'dialog'
13 disableDrawerOnMobile?: boolean
14 className?: string
15 }
16
17 export const ModalFooter = ({
18 children,
19
…(truncated, 834 more chars)
Let me check the SCSS files for Modal to understand scroll behavior:
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Modal/Modal.scss
Tool results:
→ result (ok): 1 @use '../../style/variables';
2
3 // FIXME: This is a hack to override the tokens on the monolith where old ones are still loaded
4 .dl-modal.dl-modal {
5 --oxygen-LOCAL-modal-content-background: var(--oxygen-color-primitive-white);
6 --oxygen-LOCAL-modal-header-background: var(--oxygen-color-primitive-white);
7 --oxygen-LOCAL-modal-header-color: var(--oxygen-color-semantic-neutral-prominent-stronger);
8 }
9
10 .MuiModal-root.dl-modal {
11 z-index: variables.$zindex-dialog;
12 }
13
…(truncated, 3506 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalBody/ModalBody.scss
Tool results:
→ result (ok): 1 @use '../../style/variables';
2
3 .dl-modal-content:not(.dl-modal-content-fullscreen) .dl-modal-body {
4 overflow-y: auto;
5 }
6
7 .dl-modal-body {
8 font: var(--oxygen-font-semantic-body-s-regular);
9
10 &.dl-text-body {
11 padding: (variables.$grid-unit * 2);
12 text-align: center;
13
14 &.dl-modal-body-align-left {
15 text-align: left;
16 }
17
18 &.dl-modal-body-align-center {
19 text-align: center;
20 }
21
22 @media (min-width: variables.
…(truncated, 593 more chars)
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.module.scss
Tool results:
→ result (ok): 1 @use '../../style/variables';
2
3 .side-panel {
4 position: fixed !important;
5 display: flex;
6 flex-direction: row;
7 height: 100%;
8 max-height: 100vh;
9
10 :global(.dl-backdrop) {
11 z-index: variables.$zindex-panelled-modal + 1;
12 opacity: 0.5 !important;
13 right: 0;
14 position: absolute !important;
15 }
16
17 &.absolute {
18 position: absolute !important;
19 max-height: 100%;
20 }
21
22 &.max-height-vh {
23 max-height: 100vh;
24 }
…(truncated, 1785 more chars)
Perfect! Now let me check if there are any existing examples or stories that combine Modal + scrollable content:
Tools used:
Bash:grep -r "sticky\|position.*sticky" /Users/USER/workspace/doctolib/oxygen/packages/core/src --include="*.scss" --include="*.css" -l | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src/forms/InputColor/v2/private/_CustomColorSelector.module.scss /Users/USER/workspace/doctolib/oxygen/packages/core/src/navigation/Tabs/v2/Tabs.module.scss /Users/USER/workspace/doctolib/oxygen/packages/core/src/dataDisplay/Table/Table.scss /Users/USER/workspace/doctolib/oxygen/packages/core/src/actions/Dropdown/Dropdown.module.scss
Let me check Drawer component as well since it's used on mobile and might have relevant patterns:
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Drawer/Drawer.tsx
Tool results:
→ result (ok): 1 import './Drawer.scss'
2
3 import classNames from 'classnames'
4 import { forwardRef, useCallback, useEffect, useRef, useState } from 'react'
5 import type { ReactNode, SyntheticEvent } from 'react'
6 import SwipeableDrawer from '@mui/material/SwipeableDrawer'
7 import { v4 as uuidv4 } from 'uuid'
8
9 import { Button, type ButtonProps } from '../../actions/Button/Button'
10 import { IconButton } from '../../actions/IconButton/IconButton'
11 import { Pill, type PillProps } from '../../dataDis
…(truncated, 9573 more chars)
Tools used:
Bash:head -150 /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Drawer/Drawer.scss
Tool results:
→ result (ok): @use '../../style/variables'; @use '../../style/focus';
// FIXME: This is a hack to override the tokens on the monolith where old ones are still loaded .dl-drawer.dl-drawer { --oxygen-LOCAL-drawer-background: var(--oxygen-color-primitive-white); --oxygen-LOCAL-drawer-shadowColor: var(--oxygen-color-semantic-neutral-opacity-subtle-base); --oxygen-LOCAL-drawer-iconAction-border: var(--oxygen-color-semantic-neutral-subtle-base); --oxygen-LOCAL-drawer-iconAction-icon-fill: var(--oxygen-colo …(truncated, 4120 more chars)
Let me also check the LayoutHelperComponents to understand Box patterns:
Tools used:
Read:/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/LayoutHelperComponents.tsx
Tool results:
→ result (ok): 1 import type { ReactNode } from 'react'
2 import { TOKENS } from '@doctolib/design-system-tokens/tokensCSS'
3
4 import { RadioGroup } from '../forms/RadioGroup/RadioGroup'
5 import { Select } from '../forms/Select/Select'
6
7 export const Container = ({
8 children,
9 height = 'auto',
10 width = '100%',
11 color = 'gray',
12 }: {
13 children: ReactNode
14 height?: string
15 width?: string
16 color?: 'sky' | 'teal' | 'red' | 'gray'
17 }) => (
18 <div
19 style={{
20 b
…(truncated, 4995 more chars)
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen/packages/core/src -type f -name "*index*" | grep -E "overlays|layout" | head -5
Tool results:
→ result (ok): (Bash completed with no output)
Now let me check the index files to see what's exported:
Tools used:
Bash:find /Users/USER/workspace/doctolib/oxygen/packages/core -name "index.ts" -o -name "index.tsx" | head -3
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/oxygen/packages/core/src/tokens/index.ts
Tools used:
Bash:ls /Users/USER/workspace/doctolib/oxygen/packages/core/src/ | grep -E "^index"
Tool results:
→ result (ok): (Bash completed with no output)
Let me check Modal stories to understand usage patterns better:
Tools used:
Bash:head -100 /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Modal/Modal.stories.tsx
Tool results:
→ result (ok): import type { ComponentProps } from 'react' import type { StoryObj } from '@storybook/react-vite' import { useState } from 'react'
import { Button } from '../../actions/Button/Button' import { Modal } from './Modal' import ModalA11y from './Modal.a11y.mdx' import { ModalBody } from '../ModalBody/ModalBody' import { ModalFooter } from '../ModalFooter/ModalFooter' import type { StoryConfiguration } from '@doctolib/storybook-config/types'
export default { tags: ['stage:stable'], title: 'overl …(truncated, 2628 more chars)
Perfect! Now let me compile my findings. Let me create a comprehensive summary document:
Oxygen Design System Component Exploration Complete
Based on my thorough exploration of the Oxygen design system, here's what I found:
1. Modal/Dialog Components Available
Primary Overlay Components:
- Modal (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Modal/Modal.tsx) - Most general-purpose overlay component
- Supports sizes:
small,medium,large,fullheight,fullscreen - Has built-in header with optional close icon and back navigation
- Responsive: automatically converts to Drawer on mobile
-
Key props:
show,title,size,blocking,backdrop,onHide,disableDrawerOnMobile -
Dialog (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Dialog/Dialog.tsx) - Specialized Modal wrapper for confirmation dialogs
- Composed of Modal + ModalBody + ModalFooter
- Blocking by default, no drawer on mobile
-
Props:
title,acceptText,dismissText,onAccept,onDismiss,destructive,loading -
AlphaSidePanel (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.tsx) - ALPHA/DO NOT USE - Side panel overlay positioned on the right
- Supports sizes:
small,medium,large - Has sticky footer support via
footerProps - Exports:
AlphaSidePanel,SidePanelFooter
Supporting Components:
- ModalBody (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalBody/ModalBody.tsx) - Wraps content inside Modal/Dialog
- Has auto scrolling:
overflow-y: autowhen not fullscreen -
Responsive: uses DrawerBody on mobile
-
ModalFooter (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalFooter/ModalFooter.tsx) - Sticky footer with divider
- Optional padding prop
-
Can position to right with
position="right" -
Drawer (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Drawer/Drawer.tsx) - Mobile equivalent of Modal/Dialog
- Bottom-positioned by default
- Has DrawerBody with
overflow-y-autoclass - Has DrawerFooter component
2. Layout Primitives (Stack, Box, etc.)
Flexbox-based Layout Components:
- VStack (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/VStack.tsx) - Vertical flex layout (flex-direction: column)
- Props:
gap,align,justify,width,maxWidth,minWidth,height,maxHeight,minHeight -
No overflow control built-in
-
HStack (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/HStack.tsx) - Horizontal flex layout (flex-direction: row)
- Props:
gap,align,justify,width,maxWidth,minWidth,hasWrap -
Supports flex wrapping
-
Flex (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/private/Flex.tsx) - PRIVATE - Powers both VStack and HStack
- Uses emotion styled-components
- Supports semantic HTML elements:
div,section,article,aside,header,footer,nav,main,ul,ol,li - Supports gap (uniform or x/y split) and padding (uniform, x/y split, or individual sides)
- NOT exported as public API
Helper Components:
- Box (
/Users/USER/workspace/doctolib/oxygen/packages/core/src/layout/LayoutHelperComponents.tsx) - Only a Storybook helper component for documentation/visualization (colored borders for layout demonstration)
- Not meant for production use
-
Just a wrapper div with styles
-
Container - Also a Storybook helper component only
3. Scrollable Container Patterns
Explicit scroll implementations found:
-
Modal Body scrolling (Modal.scss): -
.dl-modal-content { overflow-y: auto; max-height: calc(100vh - 32px); }-.dl-modal-content.dl-modal-content-fullheight .dl-modal-body { height: 100%; overflow-y: auto; }- Uses flex-direction: column to enable scroll -
AlphaSidePanel scrolling (AlphaSidePanel.module.scss): -
.content { overflow: auto; height: 100%; max-height: 100%; }- Flex column layout with footer as flex-grow: 0 - Content main div takes full height -
Drawer Body scrolling (Drawer.tsx + Drawer.scss): - Uses class
dl-overflow-y-autoanddl-full-height- Shadow effect at bottom:radial-gradient(...) at 50% 100%for visual scroll indicator -
Modal fullheight pattern (Modal.scss): - Header: sticky at top (no explicit position: sticky, but structurally fixed via flex) - Body: flex-grow with overflow-y-auto - Footer: fixed height at bottom
4. Sticky Header + Scrollable Content + Sticky Footer Pattern
Currently implemented in Modal and AlphaSidePanel:
Modal structure:
├─ Modal (overflow-y: auto on container for centering)
└─ modal-content (flex-direction: column, max-height: 100vh - margin)
├─ modal-header (fixed height, margin-bottom)
├─ modal-body (overflow-y: auto, flex-grow)
└─ modal-footer (fixed height, sticky via footer positioning)
AlphaSidePanel structure:
├─ side-panel (height: 100%)
└─ content (flex-direction: column, height: 100%, overflow: auto)
├─ content-main (height: 100%, scrollable via parent)
└─ footer (flex-grow: 0, height: 7.2rem, Divider + content)
Key CSS pattern for sticky layouts:
.parent {
display: flex;
flex-direction: column;
height: 100%;
}
.header { /* fixed height */ }
.scrollable-body {
overflow-y: auto;
flex: 1; /* grows to fill */
}
.footer {
flex-grow: 0; /* stays at bottom */
height: /* fixed */;
}
5. Existing Scroll/Overflow-Related Patterns
Files with scroll implementations:
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Modal/Modal.scss
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/ModalBody/ModalBody.scss
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/AlphaSidePanel/AlphaSidePanel.module.scss
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/overlays/Drawer/Drawer.tsx (via CSS classes)
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/dataDisplay/Table/Table.scss (also has sticky patterns)
- /Users/USER/workspace/doctolib/oxygen/packages/core/src/navigation/Tabs/v2/Tabs.module.scss (sticky tabs)
Recommendation for NHRDocumentList Container
For hosting a scrollable list of documents in a modal:
-
Use Modal component as the main container: - Set
size="fullheight"for a tall scrollable modal - Pass your document list content to ModalBody (which has auto scroll) - Optional ModalFooter for actions -
OR use AlphaSidePanel if right-side panel is preferred (currently alpha, check before use)
-
Structure inside ModalBody: - Use VStack for vertical layout - No need to add explicit overflow - ModalBody handles it via
.overflow-y-auto- Keep ModalBody and ModalFooter separate for proper sticky footer -
CSS approach if custom: - Flex column container with
max-height: 100vh- Body section withoverflow-y: auto; flex: 1- Footer section withflex-grow: 0
All key component files are ready to review and understand the architecture!