Skip to content

Commit

Permalink
fix: accessibility issues with ProgressBar (#1193)
Browse files Browse the repository at this point in the history
* fix: accessibility issues with `ProgressBar`

* update API docs for progress
  • Loading branch information
huntabyte authored Feb 17, 2025
1 parent 547aa94 commit 511da28
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-tigers-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

fix: don't apply `aria-valuenow` and `data-value` attributes when `Progress.Root`'s `value === null`
5 changes: 5 additions & 0 deletions .changeset/brave-bottles-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": minor
---

feat: expose `min` prop on `Progress.Root` to specify a custom minimum value for the progress bar (defaults to `0`)
5 changes: 5 additions & 0 deletions .changeset/brown-nails-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": minor
---

feat: apply `data-indeterminate` to `Progress.Root` when the `value` is `null` for easier styling of indeterminate state
5 changes: 5 additions & 0 deletions .changeset/eleven-candles-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

fix: remove invalid `max` attribute applied to the `Progress.Root` element as it is redundant to `aria-valuemax`
5 changes: 5 additions & 0 deletions .changeset/mighty-experts-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

fix: change `Progress.Root` `role` from `"meter"` to `"progressbar"` to improve accessibility
5 changes: 5 additions & 0 deletions .changeset/nasty-sloths-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": minor
---

feat: apply `data-min` attribute to `Progress.Root` for custom styling based on the minimum value of the progress bar
21 changes: 17 additions & 4 deletions docs/src/lib/content/api-reference/progress.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
createApiSchema,
createDataAttrSchema,
createNumberProp,
createPropSchema,
withChildProps,
} from "./helpers.js";
import { ProgressStateAttr } from "./extended-types/progress/index.js";
Expand All @@ -13,12 +14,16 @@ export const root = createApiSchema<ProgressRootPropsWithoutHTML>({
props: {
max: createNumberProp({
default: "100",
description:
"The maximum value of the progress bar. Used to calculate the percentage of the progress bar.",
description: "The maximum value of the progress bar.",
}),
value: createNumberProp({
min: createNumberProp({
default: "0",
description: "The current value of the progress bar.",
description: "The minimum value of the progress bar.",
}),
value: createPropSchema({
default: "0",
description: "The current value of the progress bar. If set to `null` ",
type: "number | null",
}),
...withChildProps({ elType: "HTMLDivElement" }),
},
Expand All @@ -33,10 +38,18 @@ export const root = createApiSchema<ProgressRootPropsWithoutHTML>({
description: "The current state of the progress bar.",
isEnum: true,
}),
createDataAttrSchema({
name: "min",
description: "The minimum value of the progress bar.",
}),
createDataAttrSchema({
name: "max",
description: "The maximum value of the progress bar.",
}),
createDataAttrSchema({
name: "indeterminate",
description: "Present when the value is `null`.",
}),
createDataAttrSchema({
name: "progress-root",
description: "Present on the root element.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
children,
value = 0,
max = 100,
min = 0,
id = useId(),
ref = $bindable(null),
...restProps
Expand All @@ -17,6 +18,7 @@
const rootState = useProgressRootState({
value: box.with(() => value),
max: box.with(() => max),
min: box.with(() => min),
id: box.with(() => id),
ref: box.with(
() => ref,
Expand Down
14 changes: 9 additions & 5 deletions packages/bits-ui/src/lib/bits/progress/progress.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type ProgressRootStateProps = WithRefProps<
ReadableBoxedValues<{
value: number | null;
max: number;
min: number;
}>
>;

Expand All @@ -19,15 +20,18 @@ class ProgressRootState {
props = $derived.by(
() =>
({
role: "meter",
role: "progressbar",
value: this.opts.value.current,
max: this.opts.max.current,
"aria-valuemin": 0,
"aria-valuemin": this.opts.min.current,
"aria-valuemax": this.opts.max.current,
"aria-valuenow": this.opts.value.current,
"data-value": this.opts.value.current,
"aria-valuenow":
this.opts.value.current === null ? undefined : this.opts.value.current,
"data-value":
this.opts.value.current === null ? undefined : this.opts.value.current,
"data-state": getProgressDataState(this.opts.value.current, this.opts.max.current),
"data-max": this.opts.max.current,
"data-min": this.opts.min.current,
"data-indeterminate": this.opts.value.current === null ? "" : undefined,
[ROOT_ATTR]: "",
}) as const
);
Expand Down
14 changes: 12 additions & 2 deletions packages/bits-ui/src/lib/bits/progress/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@ export type ProgressRootPropsWithoutHTML = WithChild<{
/**
* The current value of the progress bar.
* If `null`, the progress bar will be in an indeterminate state.
*
* @default 0
*/
value?: number | null;

/**
* The maximum value of the progress bar. Used to calculate the percentage
* of the progress bar along with the `value` prop.
* The maximum value of the progress bar.
*
* @default 100
*/
max?: number;

/**
* The minimum value of the progress bar.
*
* @default 0
*/
min?: number;
}>;

export type ProgressRootProps = ProgressRootPropsWithoutHTML &
Expand Down
28 changes: 26 additions & 2 deletions tests/src/tests/progress/progress.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ describe("progress", () => {
expect(root).toHaveAttribute("aria-valuemax", "20");
});

it("should respect the min prop", async () => {
const { root } = setup({ min: 10 });
expect(root).toHaveAttribute("aria-valuemin", "10");
});

it("should react to updates to the value prop", async () => {
const user = userEvent.setup();
const { getByTestId } = render(ProgressTest);
const { user, getByTestId } = setup();
const root = getByTestId("root");
const binding = getByTestId("binding");
expect(root).toHaveAttribute("aria-valuenow", "0");
Expand All @@ -45,4 +49,24 @@ describe("progress", () => {
expect(binding).toHaveTextContent("50");
expect(root).toHaveAttribute("aria-valuenow", "50");
});

it("should not have an `aria-valuenow` attribute when the `value` is `null`", async () => {
const { root } = setup({ value: null });
expect(root).not.toHaveAttribute("aria-valuenow");
});

it("should apply the `data-indeterminate` attribute when the `value` is `null`", async () => {
const { root } = setup({ value: null });
expect(root).toHaveAttribute("data-indeterminate");
});

it("should have a default value of 0", async () => {
const { root } = setup();
expect(root).toHaveAttribute("aria-valuenow", "0");
});

it("should have a default max of 100", async () => {
const { root } = setup();
expect(root).toHaveAttribute("aria-valuemax", "100");
});
});

0 comments on commit 511da28

Please sign in to comment.