Session: majestic-whistling-beaver-subagent-a08def15 — 2026-04-13

workspace-doctolib · Claude · branch HEAD · claude-haiku-4-5-20251001 · 2026-04-13 16:02 · 1 msgs · 29 tools · 17 min read · updated 3 weeks ago

Explore the Oxygen design system at /Users/USER/workspace/doctolib/oxygen to understand:

tools: Bash, Read
← workspace-doctolib Download .md .txt .json
Tool calls
Bash Bash: 16 calls (55.2%) 16 Read Read: 13 calls (44.8%) 13
Token usage4.1M total
Input144
Cache creation157.8K
Cache read3.9M
Output5.8K
Cache hit ratio96%· healthy

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:

  1. What Modal/Dialog components are available (look in packages/ directory)
  2. What layout primitives exist (Stack, Box, etc.) that support flex/overflow
  3. Whether there are any "SidePanel" or "FilterPanel" components
  4. 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: auto when 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-auto class
  • 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:

  1. 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

  2. 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

  3. Drawer Body scrolling (Drawer.tsx + Drawer.scss): - Uses class dl-overflow-y-auto and dl-full-height - Shadow effect at bottom: radial-gradient(...) at 50% 100% for visual scroll indicator

  4. 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

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 */;
}

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:

  1. 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

  2. OR use AlphaSidePanel if right-side panel is preferred (currently alpha, check before use)

  3. 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

  4. CSS approach if custom: - Flex column container with max-height: 100vh - Body section with overflow-y: auto; flex: 1 - Footer section with flex-grow: 0

All key component files are ready to review and understand the architecture!

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date