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.

the-quarterly-financial-report-final-draft-v3-approved.pdf
<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.

text-body-20the-quarterly-financial-report-final-draft-v3-approved.pdf
text-body-16the-quarterly-financial-report-final-draft-v3-approved.pdf
text-body-14the-quarterly-financial-report-final-draft-v3-approved.pdf
text-body-12the-quarterly-financial-report-final-draft-v3-approved.pdf
text-body-10the-quarterly-financial-report-final-draft-v3-approved.pdf
text-body-8the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-32the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-28the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-24the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-18the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-16the-quarterly-financial-report-final-draft-v3-approved.pdf
text-heading-14the-quarterly-financial-report-final-draft-v3-approved.pdf
<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 are shrink-0).
  • min-w-0: flex items default to min-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-0 removes 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.

the-quarterly-financial-report-final-draft-v3-approved.pdf2.4 MB
<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.

the-quarterly-financial-report-final-draft-v3-approved.pdf
<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

PropDefaultDescription
children_string
The 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'ElementType
What to render as, defaulting to an unstyled <span>. Props are inferred from whatever as resolves to.
className?''string
Utility classes for the root element.
style?{}React.CSSProperties
Inline styles for the root element.