-
-
Notifications
You must be signed in to change notification settings - Fork 32.6k
Description
Steps to reproduce
Steps:
- Open this link to live example: https://codesandbox.io/p/devbox/mui-timeline-nextjs-spxvgc
- Navigate to the
/server
route — you’ll see extra space appearing even thoughTimelineOppositeContent
is present.


This issue occurs when TimelineItem
is rendered inside a Server Component (e.g. a component without 'use client'
in a Next.js App Router environment).
Current behavior
The ::before
styling is incorrectly applied to TimelineItem
even when TimelineOppositeContent
is present, causing unwanted extra space at the start of the row.
Expected behavior
The ::before
styling should not be applied to TimelineItem
when TimelineOppositeContent
is present.
Context
It appears that when the TimelineItem
component is rendered on the server (i.e., without 'use client'
), props.children
is not being passed. As a result, React.Children.toArray(props.children)
will always return []
, incorrectly indicating that TimelineOppositeContent
is not present.
material-ui/packages/mui-lab/src/TimelineItem/TimelineItem.js
Lines 71 to 75 in 5052446
React.Children.forEach(props.children, (child) => { | |
if (isMuiElement(child, ['TimelineOppositeContent'])) { | |
hasOppositeContent = true; | |
} | |
}); |
Since JSX children are not serializable, React does not pass them from server components to client components.
Proposed Solution
This can be addressed using pure CSS by leveraging the :has()
selector to detect whether a <TimelineItem>
contains a child with the MuiTimelineOppositeContent-root
class (the default class applied to TimelineOppositeContent
). Based on that, conditional styles can be applied.
I've been testing this approach locally and I can submit a PR shortly!
Your environment
System:
OS: macOS 14.5
Binaries:
Node: 22.16.0 - ~/.nvm/versions/node/v22.16.0/bin/node
npm: 10.9.2 - ~/.nvm/versions/node/v22.16.0/bin/npm
pnpm: 10.13.1 - ~/Library/pnpm/pnpm
Browsers:
Chrome: 138.0.7204.184
Edge: 138.0.3351.109
Safari: 17.5
npmPackages:
@mui/internal-babel-plugin-minify-errors: ^2.0.8-canary.3 => 2.0.8-canary.3
@mui/internal-babel-plugin-resolve-imports: ^2.0.7-canary.11 => 2.0.7-canary.11
@mui/internal-bundle-size-checker: ^1.0.9-canary.10 => 1.0.9-canary.10
@mui/internal-code-infra: 0.0.2-canary.22 => 0.0.2-canary.22
@mui/internal-docs-utils: workspace:^ => 2.0.1
@mui/internal-scripts: workspace:^ => 2.0.10
@mui/internal-test-utils: workspace:^ => 2.0.10
@mui/material: workspace:^ => 7.2.0
@mui/utils: workspace:^ => 7.2.0
@pigment-css/react: 0.0.30 => 0.0.30
@types/react: ^19.1.8 => 19.1.8
typescript: ^5.8.3 => 5.8.3
Search keywords: Timeline TimelineItem TimelineOppositeContent