MiddleTruncatedText
Truncates single-line text in the middle, keeping the start and end visible (e.g. the-quarterly-…-approved.pdf). Useful for filenames and paths, where the extension or tail matters more than end-truncation would preserve. The full text is always exposed to screen readers as the accessible name.
Quick Start
- Installation
npm install @adaptavant/eds-core- Import
import { MiddleTruncatedText } from '@adaptavant/eds-core';
Basic Usage
By default MiddleTruncatedText renders an unstyled <span> and truncates its middle to fit the available width. It needs a width constraint to truncate (here, a resizable Box). Drag the bottom-right handle to widen or narrow it and watch the middle re-truncate live.
<Box
className="resize-x overflow-hidden border-2 border-dashed border-critical p-4"
style={{ width: 288, minWidth: 80, maxWidth: '100%' }}
>
<MiddleTruncatedText>
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
</Box>
Typography
The default <span> is unstyled. Apply typography with utility classes via className. No Text component needed. Here each class in the typography scale, all truncating to fit the same width.
<Box
className="resize-x overflow-hidden flex flex-col gap-3 border-2 border-dashed border-critical p-4"
style={{ width: 288, minWidth: 80, maxWidth: '100%' }}
>
{[
'text-body-20', 'text-body-16', 'text-body-14', 'text-body-12', 'text-body-10', 'text-body-8',
'text-heading-32', 'text-heading-28', 'text-heading-24', 'text-heading-18', 'text-heading-16', 'text-heading-14',
].map((typographyClass) => (
<div key={typographyClass}>
<span className="text-body-10 text-secondary">{typographyClass}</span>
<MiddleTruncatedText className={typographyClass}>
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
</div>
))}
</Box>
As TextLink
Pass as={TextLink} to render as a styled TextLink (<a>). The TextLink-only props (href, variant, target, rel) become available, and the middle still truncates to fit. Here every variant, plus a target="_blank" link.
Don't leave the children empty. An empty or whitespace-only string renders a link with no accessible name: a screen reader announces just "link," with no destination context. Always pass the real text.
<Box
className="resize-x overflow-hidden flex flex-col gap-3 border-2 border-dashed border-critical p-4"
style={{ width: 288, minWidth: 80, maxWidth: '100%' }}
>
{['accentPrimary', 'neutralPrimary', 'neutralSecondary', 'regular'].map((variant) => (
<div key={variant}>
<span className="text-body-10 text-secondary">
{variant}
</span>
<MiddleTruncatedText as={TextLink} href="#" variant={variant}>
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
</div>
))}
<div>
<span className="text-body-10 text-secondary">
target="_blank"
</span>
<MiddleTruncatedText
as={TextLink}
href="https://example.com"
rel="noreferrer"
target="_blank"
>
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
</div>
</Box>
File attachment row
A real composition: a filename in an attachment row next to a fixed-width size and a remove button. Middle truncation keeps the file extension visible.
flex-1 min-w-0 is required for it to truncate in a flex row. It's the #1 gotcha:
flex-1: the label takes the leftover space after the fixed siblings (icon, size, button, which areshrink-0).min-w-0: flex items default tomin-width: auto, which refuses to shrink below the text's intrinsic width, so a long filename would push the row wide instead of truncating.min-w-0removes that floor so the label can get narrower than its text, which is exactly what triggers the middle truncation.
Without min-w-0 the component never truncates in a flex row; the text just overflows the layout.
<Box
className="resize-x overflow-hidden flex items-center gap-2 border border-input rounded p-2"
style={{ width: 320, minWidth: 120, maxWidth: '100%' }}
>
<AttachmentIcon className="size-5 shrink-0" />
<MiddleTruncatedText className="flex-1 min-w-0 text-body-14">
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
<Text as="span" className="text-body-12 text-secondary shrink-0">
2.4 MB
</Text>
<IconButton
aria-label="Remove attachment"
icon={DeleteIcon}
size="small"
variant="neutralTertiary"
/>
</Box>
With tooltip
Pair with Tooltip for a hover affordance.
<Box
className="resize-x overflow-hidden border-2 border-dashed border-critical p-4"
style={{ width: 288, minWidth: 80, maxWidth: '100%' }}
>
<Tooltip
content="the-quarterly-financial-report-final-draft-v3-approved.pdf"
placement="top"
>
{({ triggerProps }) => (
<MiddleTruncatedText {...triggerProps} className="text-body-14">
the-quarterly-financial-report-final-draft-v3-approved.pdf
</MiddleTruncatedText>
)}
</Tooltip>
</Box>
API Reference
MiddleTruncatedText
| Prop | Default | Description |
|---|---|---|
children | _ | stringThe full, untruncated text. It's truncated in the middle to fit the available width and always exposed to screen readers as the accessible name. |
as? | 'span' | ElementTypeWhat to render as, defaulting to an unstyled <span>. Props are inferred from whatever as resolves to. |
className? | '' | stringUtility classes for the root element. |
style? | {} | React.CSSPropertiesInline styles for the root element. |