Skip to content

feat(Alert): add maxHeight with show more toggle - #1279

Open
fneves wants to merge 7 commits into
mainfrom
fn/cui-336-alert-max-height-0fd0
Open

fneves wants to merge 7 commits into
mainfrom
fn/cui-336-alert-max-height-0fd0

Conversation

@fneves

@fneves fneves commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Alert takes four new optional props. Long alert or error text can now be capped, so a long message no longer shifts the layout around it. This follow-up was agreed in #1277.

  • maxHeight?: number | string caps the whole alert, toggle included. A number is px; a string is any CSS length ('12lh', '100%'). When the text overflows, a Show more / Show less toggle appears.
  • onExpandedChange?: (expanded: boolean) => void fires when the user toggles. It only fires when maxHeight is set.
  • expandLabel / collapseLabel (strings) default to 'Show more' / 'Show less'.
  • WarningAlert, DangerAlert, InfoAlert and SuccessAlert pass the props through.
<WarningAlert title="Query failed" text={error.message} preserveLineBreaks maxHeight={240} />
<WarningAlert key={run.id} text={error.message} maxHeight="100%" onExpandedChange={track} />

Behaviour:

  • Collapsed: the text is clipped, fades out at the bottom (mask-image, which works on any background), and shows the toggle.
  • Expanded: the alert keeps the same height and the text scrolls inside it. Show less scrolls back to the top. The alert never grows past maxHeight.
  • Fit check: the toggle only appears when the text doesn't fit the space it would have without the toggle, so it can't get stuck at the boundary. The title stays pinned, and only the text area clips or scrolls.
  • State: the expanded state is internal. Remount with key to reset it.
  • Default: without maxHeight, nothing changes. No new class, custom property, observer or DOM.

Links and tickets

Good to know

  • Deliberately out of scope: controlled expanded / defaultExpanded, a grow-to-full-height mode, and opening the text in a modal.
  • Pre-existing Alert issues, unchanged here, for a follow-up: the dismiss button's name sits on the icon, the root has no role, AlertProps doesn't extend HTMLAttributes, and there is no forwardRef.
  • Overflow measuring: a private hook, useAlertOverflow, in the Alert folder. It is not exported, and useIsTruncated is untouched. Observers are created once per mount and not rebuilt on toggle.
  • Tokens: no exact token exists for the fade height or the toggle gap, so they use the nearest spacing tokens: --click-container-space-sm and --click-container-gap-xxs.
  • Prefixed mask: -webkit-mask-image sits beside mask-image under a scoped stylelint disable, because the browserslist targets include Chrome below 120 and the build has no autoprefixer.
  • MaxHeightKeyboard story: once expanded, the scroll region is one Shift+Tab back from the toggle, because the DOM order is title, text, toggle.
  • Open question for maintainers: feat(Alert): add preserveLineBreaks prop #1277 also floated a dedicated error-message component instead of growing Alert. This PR takes the prop route; happy to discuss.
  • No new dependencies. eslint-suppressions.json is unchanged.

Checklist

  • Breaking changes? (add migration notes in changesets) — no. The changeset is minor.
  • Visual changes? (specify in changesets) — only when maxHeight is set. All 40 existing Alert snapshots pass unchanged (no regenerations); 14 new snapshots cover the new stories.
  • Design review needed? — yes, for the text-style toggle and the labels.

Contribution

  • Sufficient research before PR
  • Self-reviewed the PR
  • Manually tested the changes (when applies - visual confirmation in Storybook)
  • build and build-storybook work locally
  • Tests and Stories are aligned with the changes

Accessibility

  • Keyboard — the toggle is a native <button> (Enter / Space), and focus stays on it after both actions. While expanded and scrollable, the text area is focusable, so arrow keys scroll it. Tabbing onto a link inside clipped text expands the alert. Esc doesn't apply.
  • Names — the toggle's visible label is its accessible name, with aria-expanded and aria-controls. When a title exists, the scroll region is role="region", named by the title.
  • Vision — the toggle inherits the alert text colour, and its focus ring uses --click-global-color-outline-default. The fade is removed in forced-colors mode. The text toggle is under 24 px tall and relies on the WCAG 2.5.8 spacing exception (it sits alone on its row).

WCAG 2.2 criteria checked: 1.4.3 Contrast (the toggle inherits the alert text colour), 2.1.1 Keyboard, 2.4.3 Focus Order, 2.4.7 Focus Visible, 2.5.3 Label in Name, 4.1.2 Name, Role, Value. In the Storybook Accessibility panel, axe shows no new violations on the new stories. The existing colour-contrast findings on info-state alerts also appear on the current StateInfo story. Not tested with a real screen reader.

Screenshots

Collapsed (light): fade and Show more.

Alert with maxHeight, collapsed, light theme

Expanded (danger, dark): same height, the text scrolls, focus stays on Show less.

Alert with maxHeight, expanded, danger state, dark theme

Open in Web Open in Cursor 

Note

Low Risk
Opt-in API with no default-path changes; risk is limited to consumers setting maxHeight and to observer/measurement edge cases, not auth or data handling.

Reviewed by Cursor Bugbot for commit 68815ed. Bugbot is set up for automated code reviews on this repo. Configure here.

cursoragent and others added 7 commits October 23, 2026 16:47
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
…g it

Co-authored-by: Fábio Neves <fabio.neves@clickhouse.com>
@changeset-bot

changeset-bot Bot commented Oct 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 68815ed

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

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@workflow-authentication-public

Copy link
Copy Markdown
Contributor

Storybook Preview Deployed

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

Built from commit: 484f5b9a49c373563d3a41c16dccc52efb17128d

@workflow-authentication-public

Copy link
Copy Markdown
Contributor

Chromatic Storybook

Check Status Link
Storybook ✅ 678 stories published Open Storybook
UI Tests ⏳ 8 changes must be accepted as baselines Open build

Built from commit: 68815edef763ac05ece38a30ae79bdba066e2303 · Chromatic run

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants