Skip to content

Commit d935d57

Browse files
fix: move CodeBlock accessibility labels outside containers
- Fixes blank rendering in virtualized CodeBlock when scrolled (#9034) - Moves labels outside <pre> in both virtualized and regular variants - Preserves accessibility while preventing react-window calculation issues - Ensures consistent architecture across all CodeBlock rendering modes Partially reverts the implementation approach from PR #8887 while maintaining the accessibility improvements.
1 parent 15f3d0a commit d935d57

File tree

4 files changed

+88
-72
lines changed

4 files changed

+88
-72
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
**Bug fixes**
2+
3+
- Fixed virtualized `EuiCodeBlock` rendering blank lines when content updates while scrolled by moving accessibility labels outside the virtualized container

packages/eui/src/components/code/__snapshots__/code_block.test.tsx.snap

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ exports[`EuiCodeBlock Virtualization renders a virtualized code block 1`] = `
55
class="euiCodeBlock testClass1 testClass2 emotion-euiCodeBlock-s-hasControls-euiTestCss"
66
style="block-size: 50%;"
77
>
8+
<span
9+
aria-hidden="true"
10+
class="euiScreenReaderOnly"
11+
data-tabular-copy-marker="no-copy"
12+
>
13+
✄𐘗
14+
</span>
15+
<div
16+
class="emotion-euiScreenReaderOnly"
17+
>
18+
aria-label,
19+
text code block:
20+
</div>
21+
<span
22+
aria-hidden="true"
23+
class="euiScreenReaderOnly"
24+
data-tabular-copy-marker="no-copy"
25+
>
26+
✄𐘗
27+
</span>
828
<div
929
data-eui="EuiAutoSizer"
1030
>
@@ -13,26 +33,6 @@ exports[`EuiCodeBlock Virtualization renders a virtualized code block 1`] = `
1333
style="position: relative; block-size: 600px; inline-size: 600px; overflow: auto; will-change: transform; direction: ltr;"
1434
tabindex="0"
1535
>
16-
<span
17-
aria-hidden="true"
18-
class="euiScreenReaderOnly"
19-
data-tabular-copy-marker="no-copy"
20-
>
21-
✄𐘗
22-
</span>
23-
<div
24-
class="emotion-euiScreenReaderOnly"
25-
>
26-
aria-label,
27-
text code block:
28-
</div>
29-
<span
30-
aria-hidden="true"
31-
class="euiScreenReaderOnly"
32-
data-tabular-copy-marker="no-copy"
33-
>
34-
✄𐘗
35-
</span>
3636
<code
3737
class="euiCodeBlock__code emotion-euiCodeBlock__code-isVirtualized"
3838
data-code-language="text"
@@ -78,30 +78,30 @@ exports[`EuiCodeBlock renders a code block 1`] = `
7878
<div
7979
class="euiCodeBlock testClass1 testClass2 emotion-euiCodeBlock-s-euiTestCss"
8080
>
81+
<span
82+
aria-hidden="true"
83+
class="euiScreenReaderOnly"
84+
data-tabular-copy-marker="no-copy"
85+
>
86+
✄𐘗
87+
</span>
88+
<div
89+
class="emotion-euiScreenReaderOnly"
90+
>
91+
aria-label,
92+
text code block:
93+
</div>
94+
<span
95+
aria-hidden="true"
96+
class="euiScreenReaderOnly"
97+
data-tabular-copy-marker="no-copy"
98+
>
99+
✄𐘗
100+
</span>
81101
<pre
82102
class="euiCodeBlock__pre emotion-euiCodeBlock__pre-preWrap-padding"
83103
tabindex="-1"
84104
>
85-
<span
86-
aria-hidden="true"
87-
class="euiScreenReaderOnly"
88-
data-tabular-copy-marker="no-copy"
89-
>
90-
✄𐘗
91-
</span>
92-
<div
93-
class="emotion-euiScreenReaderOnly"
94-
>
95-
aria-label,
96-
text code block:
97-
</div>
98-
<span
99-
aria-hidden="true"
100-
class="euiScreenReaderOnly"
101-
data-tabular-copy-marker="no-copy"
102-
>
103-
✄𐘗
104-
</span>
105105
<code
106106
class="euiCodeBlock__code emotion-euiCodeBlock__code"
107107
data-code-language="text"

packages/eui/src/components/code/code_block.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,12 @@ export const EuiCodeBlock: FunctionComponent<EuiCodeBlockProps> = ({
304304
codeProps={codeProps}
305305
/>
306306
) : (
307-
<pre {...preProps} ref={combinedRef} style={overflowHeightStyles}>
307+
<>
308308
{codeBlockLabelElement}
309-
<code {...codeProps}>{content}</code>
310-
</pre>
309+
<pre {...preProps} ref={combinedRef} style={overflowHeightStyles}>
310+
<code {...codeProps}>{content}</code>
311+
</pre>
312+
</>
311313
)}
312314
<EuiCodeBlockControls
313315
controls={[fullScreenButton, copyButton]}
@@ -325,10 +327,12 @@ export const EuiCodeBlock: FunctionComponent<EuiCodeBlockProps> = ({
325327
codeProps={codeProps}
326328
/>
327329
) : (
328-
<pre {...preFullscreenProps}>
330+
<>
329331
{codeBlockLabelElement}
330-
<code {...codeProps}>{content}</code>
331-
</pre>
332+
<pre {...preFullscreenProps}>
333+
<code {...codeProps}>{content}</code>
334+
</pre>
335+
</>
332336
)}
333337
<EuiCodeBlockControls
334338
controls={[fullScreenButton, copyButton]}

packages/eui/src/components/code/code_block_virtualized.tsx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,14 @@ export const EuiCodeBlockVirtualized = ({
3232
preProps: HTMLAttributes<HTMLPreElement>;
3333
codeProps: HTMLAttributes<HTMLElement>;
3434
}) => {
35+
// FIX: Don't inject label inside the virtualized container
36+
// react-window expects the outer element to be clean for proper scroll calculations
3537
const VirtualizedOuterElement = useMemo(
3638
() =>
37-
forwardRef<any, any>(({ style, children, ...props }, ref) => (
38-
<pre style={logicalStyles(style)} {...props} ref={ref} {...preProps}>
39-
{label}
40-
{children}
41-
</pre>
39+
forwardRef<any, any>(({ style, ...props }, ref) => (
40+
<pre style={logicalStyles(style)} {...props} ref={ref} {...preProps} />
4241
)),
43-
[preProps, label]
42+
[preProps]
4443
);
4544

4645
const VirtualizedInnerElement = useMemo(
@@ -64,26 +63,36 @@ export const EuiCodeBlockVirtualized = ({
6463
innerElementType: VirtualizedInnerElement,
6564
};
6665

67-
return typeof overflowHeight === 'number' ? (
68-
<EuiAutoSizer disableHeight={true}>
69-
{({ width }: EuiAutoSizeHorizontal) => (
70-
<FixedSizeList
71-
height={overflowHeight}
72-
width={width}
73-
{...virtualizationProps}
74-
>
75-
{ListRow}
76-
</FixedSizeList>
77-
)}
78-
</EuiAutoSizer>
79-
) : (
80-
<EuiAutoSizer>
81-
{({ height, width }: EuiAutoSize) => (
82-
<FixedSizeList height={height} width={width} {...virtualizationProps}>
83-
{ListRow}
84-
</FixedSizeList>
85-
)}
86-
</EuiAutoSizer>
66+
const virtualizedList =
67+
typeof overflowHeight === 'number' ? (
68+
<EuiAutoSizer disableHeight={true}>
69+
{({ width }: EuiAutoSizeHorizontal) => (
70+
<FixedSizeList
71+
height={overflowHeight}
72+
width={width}
73+
{...virtualizationProps}
74+
>
75+
{ListRow}
76+
</FixedSizeList>
77+
)}
78+
</EuiAutoSizer>
79+
) : (
80+
<EuiAutoSizer>
81+
{({ height, width }: EuiAutoSize) => (
82+
<FixedSizeList height={height} width={width} {...virtualizationProps}>
83+
{ListRow}
84+
</FixedSizeList>
85+
)}
86+
</EuiAutoSizer>
87+
);
88+
89+
// Render the accessibility label outside the virtualized container
90+
// This preserves accessibility while fixing virtualization bugs
91+
return (
92+
<>
93+
{label}
94+
{virtualizedList}
95+
</>
8796
);
8897
};
8998

0 commit comments

Comments
 (0)