diff --git a/.changeset/plenty-mangos-sniff.md b/.changeset/plenty-mangos-sniff.md
new file mode 100644
index 00000000000..e2d9b1f5904
--- /dev/null
+++ b/.changeset/plenty-mangos-sniff.md
@@ -0,0 +1,7 @@
+---
+'@primer/react': patch
+---
+
+Adding aria-attributes and role to the ProgressBar component
+
+
diff --git a/docs/content/ProgressBar.mdx b/docs/content/ProgressBar.mdx
index 888cccf8d15..4e3eb5c7246 100644
--- a/docs/content/ProgressBar.mdx
+++ b/docs/content/ProgressBar.mdx
@@ -14,7 +14,7 @@ import {ProgressBar} from '@primer/react'
## Examples
```jsx live
-
+
```
### Inline
@@ -24,7 +24,7 @@ If you'd like to use ProgressBar inline, pass the `inline` boolean prop & **be s
```jsx live
<>
5 of 10
-
+
>
```
@@ -34,7 +34,7 @@ If you want to show multiple segments in a ProgressBar, pass separate `Item`s as
```jsx live
<>
-
+
diff --git a/src/ProgressBar/ProgressBar.features.stories.tsx b/src/ProgressBar/ProgressBar.features.stories.tsx
index de3b28d9735..5c1e860a26a 100644
--- a/src/ProgressBar/ProgressBar.features.stories.tsx
+++ b/src/ProgressBar/ProgressBar.features.stories.tsx
@@ -1,25 +1,25 @@
import React from 'react'
-import {ComponentMeta} from '@storybook/react'
+import {Meta} from '@storybook/react'
import {ProgressBar} from '..'
export default {
title: 'Components/ProgressBar/Features',
component: ProgressBar,
-} as ComponentMeta
+} as Meta
-export const ProgressZero = () =>
-export const ProgressHalf = () =>
-export const ProgressDone = () =>
+export const ProgressZero = () =>
+export const ProgressHalf = () =>
+export const ProgressDone = () =>
-export const SizeSmall = () =>
-export const SizeLarge = () =>
+export const SizeSmall = () =>
+export const SizeLarge = () =>
-export const Inline = () =>
+export const Inline = () =>
-export const Color = () =>
+export const Color = () =>
export const MultipleItems = () => (
-
+
diff --git a/src/ProgressBar/ProgressBar.stories.tsx b/src/ProgressBar/ProgressBar.stories.tsx
index 36628e8a777..fc4ee9e07a5 100644
--- a/src/ProgressBar/ProgressBar.stories.tsx
+++ b/src/ProgressBar/ProgressBar.stories.tsx
@@ -7,10 +7,10 @@ export default {
component: ProgressBar,
} as Meta
-export const Default = () =>
+export const Default = () =>
export const Playground: ComponentStory = args => (
-
+
)
Playground.args = {
diff --git a/src/ProgressBar/ProgressBar.tsx b/src/ProgressBar/ProgressBar.tsx
index 88c8dbbf500..bc7fb26a5be 100644
--- a/src/ProgressBar/ProgressBar.tsx
+++ b/src/ProgressBar/ProgressBar.tsx
@@ -1,8 +1,9 @@
-import React from 'react'
+import React, {forwardRef} from 'react'
import styled from 'styled-components'
import {width, WidthProps} from 'styled-system'
import {get} from '../constants'
import sx, {SxProp} from '../sx'
+import {warning} from '../utils/warning'
type ProgressProp = {progress?: string | number}
@@ -37,22 +38,37 @@ const ProgressContainer = styled.span`
${sx};
`
-export type ProgressBarProps = React.PropsWithChildren & {bg?: string} & StyledProgressContainerProps & ProgressProp
-
-export const ProgressBar = ({
- progress,
- bg = 'success.emphasis',
- barSize = 'default',
- children,
- ...rest
-}: ProgressBarProps) => {
- if (children && progress) {
- throw new Error('You should pass `progress` or children, not both.')
- }
-
- return (
-
- {children ?? }
-
- )
-}
+export type ProgressBarProps = React.HTMLAttributes & {bg?: string} & StyledProgressContainerProps &
+ ProgressProp
+
+export const ProgressBar = forwardRef(
+ ({progress, bg = 'success.emphasis', barSize = 'default', children, ...rest}: ProgressBarProps, forwardRef) => {
+ if (children && progress) {
+ throw new Error('You should pass `progress` or children, not both.')
+ }
+
+ warning(
+ children &&
+ typeof (rest as React.AriaAttributes)['aria-valuenow'] === 'undefined' &&
+ typeof (rest as React.AriaAttributes)['aria-valuetext'] === 'undefined',
+ 'Expected `aria-valuenow` or `aria-valuetext` to be provided to . Provide one of these values so screen reader users can determine the current progress. This warning will become an error in the next major release.',
+ )
+
+ const progressAsNumber = typeof progress === 'string' ? parseInt(progress, 10) : progress
+
+ const ariaAttributes = {
+ 'aria-valuenow': progressAsNumber ? Math.round(progressAsNumber) : undefined,
+ 'aria-valuemin': 0,
+ 'aria-valuemax': 100,
+ 'aria-busy': progressAsNumber ? progressAsNumber !== 100 : false,
+ }
+
+ return (
+
+ {children ?? }
+
+ )
+ },
+)
+
+ProgressBar.displayName = 'ProgressBar'
diff --git a/src/__tests__/ProgressBar.test.tsx b/src/__tests__/ProgressBar.test.tsx
index 19735c739e6..4170d0db8f4 100644
--- a/src/__tests__/ProgressBar.test.tsx
+++ b/src/__tests__/ProgressBar.test.tsx
@@ -15,26 +15,41 @@ describe('ProgressBar', () => {
})
it('should have no axe violations', async () => {
- const {container} = HTMLRender()
+ const {container} = HTMLRender()
const results = await axe(container)
expect(results).toHaveNoViolations()
})
it('respects the "barSize" prop', () => {
- expect(render()).toHaveStyleRule('height', '5px')
- expect(render()).toHaveStyleRule('height', '8px')
- expect(render()).toHaveStyleRule('height', '10px')
+ expect(render()).toHaveStyleRule(
+ 'height',
+ '5px',
+ )
+ expect(render()).toHaveStyleRule(
+ 'height',
+ '8px',
+ )
+ expect(render()).toHaveStyleRule(
+ 'height',
+ '10px',
+ )
})
it('respects the "inline" prop', () => {
- expect(render()).toHaveStyleRule('display', 'inline-flex')
+ expect(render()).toHaveStyleRule(
+ 'display',
+ 'inline-flex',
+ )
})
it('respects the "width" prop', () => {
- expect(render()).toHaveStyleRule('width', '100px')
+ expect(render()).toHaveStyleRule(
+ 'width',
+ '100px',
+ )
})
it('respects the "progress" prop', () => {
- expect(render()).toMatchSnapshot()
+ expect(render()).toMatchSnapshot()
})
})
diff --git a/src/__tests__/__snapshots__/ProgressBar.test.tsx.snap b/src/__tests__/__snapshots__/ProgressBar.test.tsx.snap
index 7050d8d3b7d..dad58b54e9e 100644
--- a/src/__tests__/__snapshots__/ProgressBar.test.tsx.snap
+++ b/src/__tests__/__snapshots__/ProgressBar.test.tsx.snap
@@ -19,7 +19,11 @@ exports[`ProgressBar renders consistently 1`] = `
}