Skip to content

Commit 4d85c34

Browse files
authored
[ActionList] Prevent title="[object Object]" when Description has non-string children (#6223)
1 parent 0c73871 commit 4d85c34

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

.changeset/brown-rules-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': patch
3+
---
4+
5+
Fix ActionList.Description title attribute for non-string children with truncate

packages/react/src/ActionList/ActionList.docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,4 +393,4 @@
393393
]
394394
}
395395
]
396-
}
396+
}

packages/react/src/ActionList/ActionList.features.stories.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,18 @@ export const TextWrapAndTruncation = () => (
587587
<ArrowLeftIcon />
588588
</ActionList.TrailingVisual>
589589
</ActionList.Item>
590+
<ActionList.Item>
591+
<ActionList.LeadingVisual>
592+
<ArrowRightIcon />
593+
</ActionList.LeadingVisual>
594+
Description with truncation and complex children
595+
<ActionList.Description truncate>
596+
With <strong>bold</strong> and <em>italic</em> text, and it should truncate if it is too long
597+
</ActionList.Description>
598+
<ActionList.TrailingVisual>
599+
<ArrowLeftIcon />
600+
</ActionList.TrailingVisual>
601+
</ActionList.Item>
590602
<ActionList.Item>
591603
<ActionList.LeadingVisual>
592604
<ArrowRightIcon />

packages/react/src/ActionList/ActionList.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,32 @@ describe('ActionList', () => {
171171
expect(container.querySelector('li[aria-disabled="true"]')?.nextElementSibling).toHaveTextContent('Option 4')
172172
expect(container.querySelector('li[aria-disabled="true"]')?.nextElementSibling).toHaveAttribute('tabindex', '0')
173173
})
174+
175+
it('sets title correctly for Description component', () => {
176+
const {container} = HTMLRender(
177+
<ActionList>
178+
<ActionList.Item>
179+
Option 1<ActionList.Description truncate>Simple string description</ActionList.Description>
180+
</ActionList.Item>
181+
<ActionList.Item>
182+
Option 2
183+
<ActionList.Description truncate>
184+
<span>Complex</span> content
185+
</ActionList.Description>
186+
</ActionList.Item>
187+
<ActionList.Item>
188+
Option 3
189+
<ActionList.Description>
190+
<span>Non-truncated</span> content
191+
</ActionList.Description>
192+
</ActionList.Item>
193+
</ActionList>,
194+
)
195+
196+
const descriptions = container.querySelectorAll('[data-component="ActionList.Description"]')
197+
198+
expect(descriptions[0]).toHaveAttribute('title', 'Simple string description')
199+
expect(descriptions[1]).toHaveAttribute('title', 'Complex content')
200+
expect(descriptions[2]).not.toHaveAttribute('title')
201+
})
174202
})

packages/react/src/ActionList/Description.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type ActionListDescriptionProps = {
1515
* - `"block"` - Secondary text is positioned below primary text.
1616
*/
1717
variant?: 'inline' | 'block'
18+
1819
className?: string
1920
/**
2021
* Whether the inline description should truncate the text on overflow.
@@ -30,6 +31,18 @@ export const Description: React.FC<React.PropsWithChildren<ActionListDescription
3031
...props
3132
}) => {
3233
const {blockDescriptionId, inlineDescriptionId} = React.useContext(ItemContext)
34+
const containerRef = React.useRef<HTMLDivElement>(null)
35+
const [computedTitle, setComputedTitle] = React.useState<string>('')
36+
37+
// Extract text content from rendered DOM for tooltip
38+
React.useEffect(() => {
39+
if (truncate && containerRef.current) {
40+
const textContent = containerRef.current.textContent || ''
41+
setComputedTitle(textContent)
42+
}
43+
}, [truncate, props.children])
44+
45+
const effectiveTitle = typeof props.children === 'string' ? props.children : computedTitle
3346

3447
if (variant === 'block' || !truncate) {
3548
return (
@@ -46,10 +59,11 @@ export const Description: React.FC<React.PropsWithChildren<ActionListDescription
4659
} else {
4760
return (
4861
<Truncate
62+
ref={containerRef}
4963
id={inlineDescriptionId}
5064
className={clsx(className, classes.Description)}
5165
sx={sx}
52-
title={props.children as string}
66+
title={effectiveTitle}
5367
inline={true}
5468
maxWidth="100%"
5569
data-component="ActionList.Description"

0 commit comments

Comments
 (0)