Skip to content

Commit 11395f0

Browse files
feat: Adding new split layout component (#15438)
Adding a split layout component that lets you create a 2 column view within the center layout. You can use this to separate text on the left, and code samples on the right. <img width="1137" height="550" alt="CleanShot 2025-11-09 at 10  09 20@2x" src="https://github.com/user-attachments/assets/bd01a5a6-0221-4eb5-9ab4-9138784a23f3" /> --------- Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
1 parent 7027388 commit 11395f0

File tree

4 files changed

+289
-0
lines changed

4 files changed

+289
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# SplitLayout Component
2+
3+
A two-column layout component designed for getting started guides that places explanatory text on the left and code samples on the right.
4+
5+
## Features
6+
7+
- **Responsive Design**: Automatically stacks on mobile (under 1024px)
8+
- **Sticky Code**: Code samples stick to viewport on desktop for easy reference while scrolling
9+
- **Clean Separation**: Clear visual separation between explanation and implementation
10+
- **Flexible Content**: Support for any MDX content in both sections
11+
12+
## Usage
13+
14+
### Basic Example
15+
16+
**Note:** MDX requires direct component names, not dot notation.
17+
18+
````mdx
19+
<SplitLayout>
20+
<SplitSection>
21+
<SplitSectionText>
22+
### Your Heading Explanatory text goes here. You can use any markdown: -
23+
Lists - **Bold text** - Links This content appears on the left side.
24+
</SplitSectionText>
25+
26+
<SplitSectionCode>
27+
```javascript // Your code sample goes here const example = "This appears
28+
on the right"; ```
29+
</SplitSectionCode>
30+
31+
</SplitSection>
32+
</SplitLayout>
33+
````
34+
35+
### Multiple Sections
36+
37+
You can stack multiple split sections within one layout:
38+
39+
````mdx
40+
<SplitLayout>
41+
<SplitSection>
42+
<SplitSectionText>
43+
### First Topic
44+
Explanation for the first topic...
45+
</SplitSectionText>
46+
<SplitSectionCode>
47+
```javascript
48+
const first = "code";
49+
```
50+
</SplitSectionCode>
51+
</SplitSection>
52+
53+
<SplitSection>
54+
<SplitSectionText>
55+
### Second Topic
56+
Explanation for the second topic...
57+
</SplitSectionText>
58+
<SplitSectionCode>
59+
```javascript
60+
const second = "code";
61+
```
62+
</SplitSectionCode>
63+
</SplitSection>
64+
</SplitLayout>
65+
````
66+
67+
## Component Structure
68+
69+
- **`<SplitLayout>`**: Container for one or more split sections
70+
- **`<SplitSection>`**: Individual split section wrapper
71+
- **`<SplitSectionText>`**: Left side text content (use this, not `<SplitSection.Text>`)
72+
- **`<SplitSectionCode>`**: Right side code samples (use this, not `<SplitSection.Code>`)
73+
74+
## Styling
75+
76+
The component uses CSS Grid for layout and is fully responsive:
77+
78+
- **Desktop (>1024px)**: Two columns (50/50 split)
79+
- **Mobile (≤1024px)**: Single column (stacked)
80+
81+
The code section uses `position: sticky` on desktop to keep code visible while scrolling through long explanations.
82+
83+
## Best Practices
84+
85+
1. **Keep explanations concise**: The left column is limited in width, so focus on key points
86+
2. **Use headings**: Start each Text section with a heading (h3 or h4)
87+
3. **Code relevance**: Ensure code samples directly relate to the adjacent text
88+
4. **Progressive complexity**: Order sections from simple to complex
89+
5. **Mobile consideration**: Remember content stacks on mobile, so ensure reading flow makes sense
90+
91+
## Examples in Use
92+
93+
See it in action:
94+
95+
- [Next.js Getting Started - Essential Configuration](/platforms/javascript/guides/nextjs/getting-started/#essential-configuration)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use client';
2+
3+
/**
4+
* Component: SplitLayout / SplitSection
5+
*
6+
* Creates a two-column layout with text content on the left and code samples on the right.
7+
* Ideal for getting started guides where you want to explain concepts alongside code examples.
8+
*
9+
* Usage in MDX:
10+
* <SplitLayout>
11+
* <SplitSection>
12+
* <SplitSectionText>
13+
* ## Your Heading
14+
* Explanatory text goes here...
15+
* </SplitSectionText>
16+
* <SplitSectionCode>
17+
* ```javascript
18+
* // Your code sample
19+
* ```
20+
* </SplitSectionCode>
21+
* </SplitSection>
22+
* </SplitLayout>
23+
*
24+
* Props:
25+
* - SplitLayout: Container for one or more split sections
26+
* - SplitSection: Individual split section wrapper
27+
* - SplitSectionText: Left side text content
28+
* - SplitSectionCode: Right side code samples
29+
*
30+
* Note: While SplitSection.Text and SplitSection.Code are available as properties
31+
* for TypeScript convenience, MDX requires using the direct component names.
32+
*/
33+
34+
import {ReactNode} from 'react';
35+
36+
import styles from './style.module.scss';
37+
38+
type SplitLayoutProps = {
39+
children: ReactNode;
40+
};
41+
42+
type SplitSectionProps = {
43+
children: ReactNode;
44+
};
45+
46+
type SplitSectionTextProps = {
47+
children: ReactNode;
48+
};
49+
50+
type SplitSectionCodeProps = {
51+
children: ReactNode;
52+
};
53+
54+
export function SplitLayout({children}: SplitLayoutProps) {
55+
return <div className={styles.splitLayoutContainer}>{children}</div>;
56+
}
57+
58+
export function SplitSectionText({children}: SplitSectionTextProps) {
59+
return <div className={styles.splitText}>{children}</div>;
60+
}
61+
62+
export function SplitSectionCode({children}: SplitSectionCodeProps) {
63+
return <div className={styles.splitCode}>{children}</div>;
64+
}
65+
66+
export function SplitSection({children}: SplitSectionProps) {
67+
return <div className={styles.splitSection}>{children}</div>;
68+
}
69+
70+
// Attach Text and Code as properties of SplitSection for dot notation usage
71+
SplitSection.Text = SplitSectionText;
72+
SplitSection.Code = SplitSectionCode;
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
.splitLayoutContainer {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 2rem;
5+
margin: 2rem 0;
6+
}
7+
8+
.splitSection {
9+
display: grid;
10+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
11+
gap: 2rem;
12+
align-items: start;
13+
margin-bottom: 3rem; // Default spacing between sections (mb-5 equivalent)
14+
15+
@media (max-width: 1024px) {
16+
grid-template-columns: 1fr;
17+
gap: 1.5rem;
18+
margin-bottom: 2rem; // Reduced spacing on mobile
19+
}
20+
21+
// Remove margin from last section in a layout
22+
&:last-child {
23+
margin-bottom: 0;
24+
}
25+
}
26+
27+
.splitText {
28+
min-width: 0; // Allow flex item to shrink below content size
29+
overflow-wrap: break-word;
30+
31+
// Create a container that's 80% width
32+
> * {
33+
max-width: 80%;
34+
}
35+
36+
@media (max-width: 1024px) {
37+
// Full width on mobile
38+
> * {
39+
max-width: 100%;
40+
}
41+
}
42+
43+
// Ensure headings and paragraphs have appropriate spacing
44+
> *:first-child {
45+
margin-top: 0;
46+
}
47+
48+
> *:last-child {
49+
margin-bottom: 0;
50+
}
51+
52+
// Style headings within the text section
53+
h2, h3, h4 {
54+
margin-top: 0;
55+
margin-bottom: 0.75rem;
56+
}
57+
58+
p {
59+
margin-bottom: 1rem;
60+
line-height: 1.6;
61+
}
62+
63+
ul, ol {
64+
margin-bottom: 1rem;
65+
}
66+
}
67+
68+
.splitCode {
69+
position: sticky;
70+
top: calc(var(--header-height, 80px) + 1rem);
71+
min-width: 0; // Allow flex item to shrink below content size
72+
overflow: hidden; // Prevent content from expanding the column
73+
74+
@media (max-width: 1024px) {
75+
position: relative;
76+
top: auto;
77+
overflow: visible;
78+
}
79+
80+
// Ensure code blocks fill the space
81+
> *:first-child {
82+
margin-top: 0;
83+
}
84+
85+
> *:last-child {
86+
margin-bottom: 0;
87+
}
88+
89+
// Override global code block styles to enable wrapping
90+
// Use !important to ensure these override the global styles
91+
:global(pre),
92+
:global(pre[class*='language-']) {
93+
white-space: pre-wrap !important;
94+
word-wrap: break-word !important;
95+
overflow-wrap: break-word !important;
96+
overflow-x: visible !important;
97+
}
98+
99+
:global(code),
100+
:global(code[class*='language-']) {
101+
white-space: pre-wrap !important;
102+
word-wrap: break-word !important;
103+
overflow-wrap: break-word !important;
104+
}
105+
106+
:global(.code-line) {
107+
white-space: pre-wrap !important;
108+
word-wrap: break-word !important;
109+
overflow-wrap: break-word !important;
110+
}
111+
}
112+

src/mdxComponents.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ import {SdkApi} from './components/sdkApi';
4444
import {SdkOption} from './components/sdkOption';
4545
import {SignInNote} from './components/signInNote';
4646
import {SmartLink} from './components/smartLink';
47+
import {
48+
SplitLayout,
49+
SplitSection,
50+
SplitSectionCode,
51+
SplitSectionText,
52+
} from './components/splitLayout';
4753
import {StepComponent, StepConnector} from './components/stepConnector';
4854
import {TableOfContents} from './components/tableOfContents';
4955
import {VersionRequirement} from './components/version-requirement';
@@ -98,6 +104,10 @@ export function mdxComponents(
98104
RelayMetrics,
99105
SandboxLink,
100106
SignInNote,
107+
SplitLayout,
108+
SplitSection,
109+
SplitSectionText,
110+
SplitSectionCode,
101111
StepComponent,
102112
StepConnector,
103113
VimeoEmbed,

0 commit comments

Comments
 (0)