[circularprogress][linearprogress] Improve accessibility#48172
[circularprogress][linearprogress] Improve accessibility#48172silviuaavram merged 46 commits intomui:masterfrom
Conversation
Netlify deploy previewBundle size report
|
There was a problem hiding this comment.
Pull request overview
Improves accessibility and flexibility of LinearProgress and CircularProgress by introducing configurable value ranges (minValue/maxValue), adding dev-time range validation, and updating documentation/examples to better demonstrate accessible labeling patterns.
Changes:
- Add
minValue/maxValueprops to Linear/Circular progress and update determinate/buffer calculations to use the custom range. - Add/extend tests for RTL determinate behavior and custom range + dev warnings.
- Update docs and API descriptions with new demos (custom scale,
aria-valuetext, query variant) and revised labeling example.
Reviewed changes
Copilot reviewed 22 out of 24 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/mui-material/src/LinearProgress/LinearProgress.js | Implements minValue/maxValue handling and dev warnings for LinearProgress. |
| packages/mui-material/src/LinearProgress/LinearProgress.d.ts | Adds TS typings for minValue/maxValue. |
| packages/mui-material/src/LinearProgress/LinearProgress.test.js | Adds RTL determinate coverage and custom range/warning tests. |
| packages/mui-material/src/CircularProgress/CircularProgress.js | Implements minValue/maxValue handling and dev warnings for CircularProgress determinate. |
| packages/mui-material/src/CircularProgress/CircularProgress.d.ts | Adds TS typings for minValue/maxValue. |
| packages/mui-material/src/CircularProgress/CircularProgress.test.js | Adds custom range and warning tests for CircularProgress. |
| docs/translations/api-docs/linear-progress/linear-progress.json | Documents new props in generated API translations. |
| docs/translations/api-docs/circular-progress/circular-progress.json | Documents new props in generated API translations. |
| docs/pages/material-ui/api/linear-progress.json | Adds minValue/maxValue to API page JSON. |
| docs/pages/material-ui/api/circular-progress.json | Adds minValue/maxValue to API page JSON. |
| docs/data/material/components/progress/progress.md | Adds new demos/sections (custom scale, query, aria-valuetext) and updates headings/text. |
| docs/data/material/components/progress/LinearWithValueLabel.tsx | Updates the “with label” demo to use aria-labelledby + visible label and value label. |
| docs/data/material/components/progress/LinearWithValueLabel.js | JS version of the updated “with label” demo. |
| docs/data/material/components/progress/LinearWithValueLabel.tsx.preview | Updates preview snippet to new component name. |
| docs/data/material/components/progress/LinearWithAriaValueText.tsx | New demo showing aria-valuetext for non-percentage scales. |
| docs/data/material/components/progress/LinearWithAriaValueText.js | JS version of the new aria-valuetext demo. |
| docs/data/material/components/progress/LinearWithAriaValueText.tsx.preview | Preview snippet for the new aria-valuetext demo. |
| docs/data/material/components/progress/LinearQuery.tsx | New demo for variant="query". |
| docs/data/material/components/progress/LinearQuery.js | JS version of the new query demo. |
| docs/data/material/components/progress/LinearQuery.tsx.preview | Preview snippet for the new query demo. |
| docs/data/material/components/progress/CircularCustomScale.tsx | New demo showing custom scale usage for CircularProgress. |
| docs/data/material/components/progress/CircularCustomScale.js | JS version of the custom scale demo. |
| docs/data/material/components/progress/CircularCustomScale.tsx.preview | Preview snippet for the custom scale demo. |
| docs/data/material/components/progress/CircularWithValueLabel.js | Updates wording to reference minValue/maxValue. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| rootProps['aria-valuemin'] = minValue; | ||
| rootProps['aria-valuemax'] = maxValue; | ||
| let transform = ((value - minValue) / (maxValue - minValue)) * 100 - 100; | ||
| if (isRtl) { |
There was a problem hiding this comment.
Technically a user could pass in identical max and min, causing division by 0, we could add another dev warning when min >= max, e.g. https://github.com/mui/base-ui/blob/d15bc0a4fb82f56f08c16d50cd6a4acc3c5247e5/packages/react/src/slider/root/SliderRoot.tsx#L270-L274
and then no need to handle it here
2e8c17d to
a91d06e
Compare
mapache-salvaje
left a comment
There was a problem hiding this comment.
Docs changes look good! 👍
siriwatknp
left a comment
There was a problem hiding this comment.
Good accessibility improvements overall — min/max props, dev warnings, and new demos are solid additions. A few issues to address:
| if (isRtl) { | ||
| transform = -transform; | ||
| } | ||
| inlineStyles.bar1.transform = `translateX(${transform}%)`; |
There was a problem hiding this comment.
Same division-by-zero issue here. If max === min, ((value - min) / (max - min)) → NaN. Should guard range > 0 before computing transforms, or clamp.
There was a problem hiding this comment.
I think this is fine since we already have an error for min>=max, which is obvious developer error
There was a problem hiding this comment.
Added a guard for both this one and circular progress
| circleStyle.strokeDashoffset = `${(((max - value) / (max - min)) * circumference).toFixed(3)}px`; | ||
| rootStyle.transform = 'rotate(-90deg)'; | ||
|
|
||
| rootProps['aria-valuenow'] = Math.round(value); |
There was a problem hiding this comment.
Nit: aria-valuemin and aria-valuemax are only set in the determinate branch. Per WAI-ARIA progressbar, aria-valuemin/aria-valuemax are optional when using the default 0-100 range. But when custom min/max are provided by the user for indeterminate (which is ignored here), no warning is emitted. Consider warning if min/max are provided with variant="indeterminate" since they have no effect.
dba6fe7 to
fac9022
Compare
| inlineStyles.bar1.transform = `translateX(${transform}%)`; | ||
| inlineStyles.bar1.transform = range > 0 ? `translateX(${transform}%)` : undefined; | ||
|
|
||
| rootProps['aria-valuenow'] = Math.round(value); |
There was a problem hiding this comment.
| rootProps['aria-valuenow'] = Math.round(value); | |
| rootProps['aria-valuenow'] = value; |
Shouldn't round this or it will break when min={0} max={1} value={0.25}
There was a problem hiding this comment.
It was like this before my changes, but the comment is relevant. Will change for both!
ac8c332 to
4a3d781
Compare
73fd6d6 to
6a1b88f
Compare
Bundle size
Deploy previewCheck out the code infra dashboard for more information about this PR. |
|
Might be worth adding just a bit more docs and close this issue out as well: #39072 |
siriwatknp
left a comment
There was a problem hiding this comment.
Adversarial review flagged a few concerns around the new range support. Details inline.
| transform = -transform; | ||
| } | ||
| inlineStyles.bar2.transform = `translateX(${transform}%)`; | ||
| inlineStyles.bar2.transform = range > 0 ? `translateX(${transform}%)` : undefined; |
There was a problem hiding this comment.
[high] Fails open on invalid range.
When min >= max, the inline transform is set to undefined, but the base bar styling renders both bars at full width — so production builds display a completed bar for invalid input. That turns bad backend/config data into a user-visible false-success state, which is the exact class of bug these props should surface.
Recommendation: fail closed instead of open. Either clamp to an empty state (translateX(-100%) / equivalent), or skip rendering the determinate fill entirely when the range is invalid, while still logging the validation error in development.
There was a problem hiding this comment.
There was a problem hiding this comment.
Added the translateX(-100%) fallback when min > max
siriwatknp
left a comment
There was a problem hiding this comment.
Thanks for the fixes — fail-closed behavior and error prefix look good. One minor doc nit from re-review.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 24 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| it('should warn if the value is out of range', () => { | ||
| expect(() => { | ||
| render(<LinearProgress variant="determinate" value={-1} min={0} max={10} />); | ||
| }).toErrorDev([ | ||
| 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=0, max=10, value=-1.', |
There was a problem hiding this comment.
Test name says "should warn" but the assertion expects console.error via toErrorDev. Rename the test (or change the expectation) so the wording matches the actual behavior being verified.
Closes #48179.
Closes #39072.
LinearProgress
minandmaxpropsminandmaxwith indeterminate / query variantsaria-valuetextqueryvariant.CircularProgress
minandmaxpropsminandmaxwith indeterminate / query variants