Skip to content

feat: TextTruncate - #1250

Merged
XOP merged 8 commits into
mainfrom
feat/cui-283-text-truncate
Oct 8, 2026
Merged

XOP merged 8 commits into
mainfrom
feat/cui-283-text-truncate

Conversation

@XOP

@XOP XOP commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

TextTruncate component

Summary

Adds TextTruncate (end or middle ellipsis; tooltip and tab stop while truncated) and deprecates EllipsisContent and MiddleTruncator. CUI-283. No Figma frame.

Component name: TextTruncate
Type: New Component, Component Deprecation (EllipsisContent, MiddleTruncator)

Motivation

  • Problem / gap in the current library: EllipsisContent is hover-only, measures only on render, has no middle mode or width cap; projects used multiple custom wrappers which can be replaced.
  • A11y gap: full text for mouse, keyboard and screen readers.

Design reference

  • Figma link provided: none, engineering-led from the console audit
  • Design reviewed and approved by the design team: Dani
  • All component states are covered in the design (default, hover, active, focus, disabled, error, loading): no design; the states that apply to text (default, truncated, hover, focus) are covered in the stories

Proposed API

<TextTruncate
  component="span"             // polymorphic; default span, shown as a block
  ellipsisPosition="end"       // 'end' | 'middle'; middle needs a string child
  trailingChars={8}            // middle only; no split when the tail would be longer than the start
  maxWidth="20ch"              // any CSS length; sets --text-truncate-max-width
  showTooltip                  // default true; false skips measuring, tooltip and tab stop
  tooltipContent={plainText}   // default: children
  tooltipProps={{ side: 'right' }} // side / align / sideOffset
>
  {fileName}
</TextTruncate>
  • Props are consistent with existing component conventions in click-ui
  • Component supports className and ref forwarding
  • Default prop values are documented (JSDoc in TextTruncate.types.ts)

Variants & states

  • Variants defined: ellipsisPosition end | middle
  • Sizes defined: N/A, typography is inherited from the parent
  • States handled: default, truncated, hover, focus; active and disabled N/A
  • Error / validation state: N/A
  • Loading state: N/A

Accessibility

  • Correct semantic HTML elements used: plain span/div (or the given component); role="group" only on a plain span/div, never over a native role
  • ARIA attributes added where needed: the truncated group is named by its own text (aria-labelledby to itself), a tooltip that repeats the name adds no aria-describedby, middle mode hides its two visual halves (aria-hidden) behind one visually hidden full copy. Known gap: a consumer aria-describedby replaces the tooltip description instead of merging with it
  • Keyboard navigation works (Tab, Enter, Escape, Arrow keys as applicable): Tab/Shift+Tab reach truncated text only, focus opens the tooltip, Escape closes it, Enter/Space do nothing; inside a control there is no extra tab stop and the tooltip is hover-only
  • Screen reader tested or reviewed: VoiceOver (middle mode inside a button and a link reads one word); Chromium accessibility names checked; NVDA and JAWS not tested
  • Focus management is correct (focus ring visible, focus trap if modal); known limit: if a focused text stops being truncated (resize, zoom), focus drops to <body>
  • Color contrast meets WCAG AA (4.5:1 text, 3:1 UI): focus ring 3.84:1 light, 15.40:1 dark; TextTruncate sets no text color. axe reports color-contrast in two light-theme stories only because of Link's own color (#437eef, 3.83:1), a pre-existing token issue tracked separately

Theming

  • Component works with the light theme
  • Component works with the dark theme
  • Uses design tokens from src/theme/tokens (no hardcoded colors, spacing, or font sizes); one component-local custom property, --text-truncate-max-width

Implementation checklist

  • Component file created: src/components/TextTruncate/TextTruncate.tsx
  • Exports added; exported from src/index.ts and the ./TextTruncate subpath in package.json
  • Styled with CSS Modules (ComponentName.module.css, BEM class names) using theme tokens as CSS variables (var(--click-*)): plus a new shared module src/styles/visually-hidden.module.css (.sr-only)
  • TypeScript types/interfaces exported: TextTruncateProps, TextTruncateEllipsisPosition
  • No any types used

Testing

  • Unit tests added: TextTruncate.test.tsx (31) and src/hooks/internal/useIsTruncated.test.tsx (7)
  • All variants and states have test coverage
  • Accessibility checks included in tests (e.g., toHaveAccessibleName): accessible names, descriptions, roles and tab stops
  • Edge cases covered (empty state, overflow, long text, etc.): fits vs truncated, resize both ways, inside six kinds of controls, middle split boundaries, consumer id/aria-*
  • Storybook story added: TextTruncate.stories.tsx (13 stories)
  • Visual regression covered (Chromatic snapshot via Storybook): Chromatic only, no Playwright spec for TextTruncate in this PR

Documentation

  • Storybook story includes all variants, sizes, and states;
  • Props table is auto-generated or manually documented in the story
  • Usage guidelines / do's and don'ts added (if applicable): in story descriptions (showTooltip={false} in grids and large lists, component={Text} instead of a <Text> child, ellipsisContent={false} in Badge, cap the width of inline-flex controls such as Link)

Changeset

  • changes added
  • Change type is correct (minor for new components, patch for changes/fixes)

Security checklist

  • All user inputs are validated and sanitized: N/A
  • No usage of dangerouslySetInnerHTML
  • Sensitive data has been identified and is being protected properly: N/A
  • Build output contains no secrets or API keys

Rollout & migration (for component changes only)

  • Breaking changes are documented: none
  • Migration guide provided for consumers: N/A, nothing breaks; follow up is the internal updates CUI-319
  • Deprecated props/components marked with @deprecated JSDoc: EllipsisContent, EllipsisContentProps, MiddleTruncator;
  • Backward compatibility maintained or major version bump planned: maintained; EllipsisContent and MiddleTruncator code is untouched. Intended difference for later migrations: the TextTruncate tooltip stays open while hovered (WCAG 1.4.13)

Preview

image image image image image

See storybook for interactive examples.

@XOP XOP added the enhancement New feature or request label Oct 6, 2026
@changeset-bot

changeset-bot Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c927786

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clickhouse/click-ui Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@XOP
XOP requested review from DreaminDani and ariser October 6, 2026 08:45

@ariser ariser left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Niceee, great improvement

Comment thread src/components/TextTruncate/TextTruncate.types.ts Outdated
Comment thread src/components/TextTruncate/TextTruncate.tsx
Comment thread src/components/TextTruncate/TextTruncate.tsx Outdated
Comment thread src/components/TextTruncate/TextTruncate.tsx Outdated
Comment thread src/components/TextTruncate/TextTruncate.tsx Outdated
Comment thread src/hooks/useIsTruncated.ts

@DreaminDani DreaminDani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread src/components/TextTruncate/TextTruncate.tsx
@workflow-authentication-public

Copy link
Copy Markdown
Contributor

Storybook Preview Deployed

✅ Preview URL: https://click-hu2g03w78-clickhouse.vercel.app

Built from commit: 5c1db51a5ba4674d35bd95916936aa960865b232

@workflow-authentication-public

Copy link
Copy Markdown
Contributor

Chromatic Storybook

Check Status Link
Storybook ✅ 655 stories published Open Storybook
UI Tests ✅ 655 tests unchanged Open build

Built from commit: c927786e7597cfe17e6e98188b9602a2c97e3c97 · Chromatic run

Statuses as of the end of the run. The build link shows the live review state.

@XOP
XOP merged commit fae77ae into main Oct 8, 2026
10 checks passed
@XOP
XOP deleted the feat/cui-283-text-truncate branch October 8, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants