Skip to content

Commit 9bf0b75

Browse files
authored
Merge pull request #2826 from SUI-Components/input-a11y
a11y Atom Input
2 parents e1be0ab + 9b24685 commit 9bf0b75

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1236
-687
lines changed

components/atom/button/demo/articles/ArticleA11y.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import PropTypes from 'prop-types'
22

3-
import {Article, Box, H2, Paragraph, ListItem, UnorderedList, Strong, Anchor} from '@s-ui/documentation-library'
3+
import {Anchor, Article, Box, H2, ListItem, Paragraph, Strong, UnorderedList} from '@s-ui/documentation-library'
44

55
const ArticleA11y = ({className}) => {
66
return (
77
<Article className={className}>
8-
<H2>Accessibility</H2>
8+
<H2>
9+
Accessibility –{' '}
10+
<Anchor href="https://github.com/SUI-Components/sui-components/blob/master/contributor-docs/Accessibility%20Standards.md">
11+
<Strong>Guidelines</Strong>
12+
</Anchor>
13+
</H2>
914
<Box style={{backgroundColor: 'color-mix(in srgb, #00FF00 10%, transparent)'}}>
1015
<Paragraph>
1116
✅ This component has been successfully tested for{' '}

components/atom/button/demo/articles/ArticleKeyboardNavigation.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import PropTypes from 'prop-types'
22

33
import {Article, H2, ListItem, UnorderedList} from '@s-ui/documentation-library'
4-
54
import AtomKbd from '@s-ui/react-atom-kbd'
65

76
const ArticleKeyboardNavigation = ({className}) => {

components/atom/button/demo/articles/ArticleNegative.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Fragment} from 'react'
2-
import usePrefersColorScheme from 'use-prefers-color-scheme'
32

43
import PropTypes from 'prop-types'
4+
import usePrefersColorScheme from 'use-prefers-color-scheme'
55

66
import {Article, Cell, Code, Grid, H2, Label, Paragraph} from '@s-ui/documentation-library'
77

components/atom/button/demo/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
import {H1, Paragraph} from '@s-ui/documentation-library'
44

5+
import ArticleA11y from './articles/ArticleA11y.js'
56
import ArticleAlignment from './articles/ArticleAlignment.js'
67
import ArticleColor from './articles/ArticleColor.js'
78
import ArticleDesign from './articles/ArticleDesign.js'
89
import ArticleDesignColor from './articles/ArticleDesignColor.js'
910
import ArticleElevation from './articles/ArticleElevation.js'
1011
import ArticleIsFitted from './articles/ArticleIsFitted.js'
12+
import ArticleKeyboardNavigation from './articles/ArticleKeyboardNavigation.js'
1113
import ArticleLink from './articles/ArticleLink.js'
1214
import ArticleNegative from './articles/ArticleNegative.js'
1315
import ArticlePlayground from './articles/ArticlePlayground.js'
1416
import ArticleShape from './articles/ArticleShape.js'
1517
import ArticleSize from './articles/ArticleSize.js'
1618
import ArticleSocialColor from './articles/ArticleSocialColor.js'
17-
import ArticleA11y from './articles/ArticleA11y.js'
18-
import ArticleKeyboardNavigation from './articles/ArticleKeyboardNavigation.js'
19-
import TypeDeprecatedArticle from './TypeDeprecatedArticle.js'
2019
import {CLASS_SECTION} from './settings.js'
20+
import TypeDeprecatedArticle from './TypeDeprecatedArticle.js'
2121

2222
const Demo = () => {
2323
return (

components/atom/button/src/styles/index.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ $base-class: '.sui-AtomButton';
246246
}
247247
}
248248

249-
&:focus {
249+
&:focus-visible {
250250
box-shadow: $bxsh-atom-button-focus;
251251
outline: 2px solid transparentize($c-primary, 0.2);
252252
outline-offset: 2px;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import PropTypes from 'prop-types'
2+
3+
import {Anchor, Article, Box, Code, H2, ListItem, Paragraph, Strong, UnorderedList} from '@s-ui/documentation-library'
4+
5+
const ArticleA11y = ({className}) => {
6+
return (
7+
<Article className={className}>
8+
<H2>
9+
Accessibility –{' '}
10+
<Anchor href="https://github.com/SUI-Components/sui-components/blob/master/contributor-docs/Accessibility%20Standards.md">
11+
<Strong>Guidelines</Strong>
12+
</Anchor>
13+
</H2>
14+
<Box style={{backgroundColor: 'color-mix(in srgb, #00FF00 10%, transparent)'}}>
15+
<Paragraph>
16+
✅ This component has been successfully tested for{' '}
17+
<Strong>WCAG 2.0 levels A and AA, WCAG 2.1 levels A and AA</Strong> and for common accessibility best
18+
practices.
19+
</Paragraph>
20+
</Box>
21+
<UnorderedList>
22+
<ListItem>
23+
<Strong>Label</Strong>: Ensure text fields are properly labeled using <Code>label</Code> elements, with the
24+
for attribute linking to the input. This helps screen readers identify the field’s purpose.
25+
</ListItem>
26+
<ListItem>
27+
<Strong>Aria Label</Strong>: Use <Code>aria-label</Code> for inputs without visible labels (e.g., search bars
28+
with placeholder text only). This attribute provides an accessible name that describes the purpose of the
29+
input.
30+
</ListItem>
31+
<ListItem>
32+
<Strong>Descriptive Text</Strong>: When additional descriptive text is required, use{' '}
33+
<Code>aria-describedby</Code> to associate the input field with explanatory content, such as error messages or
34+
guidelines.
35+
</ListItem>
36+
<ListItem>
37+
<Strong>Error Feedback</Strong>: Use <Code>role="alert"</Code> or <Code>aria-live="assertive"</Code> for error
38+
messages, ensuring screen readers announce them immediately upon field validation.
39+
</ListItem>
40+
</UnorderedList>
41+
<Box style={{backgroundColor: 'color-mix(in srgb, #FFFF00 10%, transparent)'}}>
42+
<Strong>Mandatory / Required</Strong>
43+
<UnorderedList>
44+
<ListItem>
45+
The asterisk * for mandatory needs to be read as <Strong>mandatory</Strong>.
46+
</ListItem>
47+
</UnorderedList>
48+
</Box>
49+
</Article>
50+
)
51+
}
52+
53+
ArticleA11y.propTypes = {
54+
className: PropTypes.string
55+
}
56+
57+
export default ArticleA11y
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import {useState} from 'react'
2+
3+
import PropTypes from 'prop-types'
4+
5+
import {
6+
AntDesignIcon,
7+
Article,
8+
Cell,
9+
Code,
10+
Grid,
11+
H2,
12+
Input,
13+
ListItem,
14+
Paragraph,
15+
RadioButton,
16+
RadioButtonGroup,
17+
UnorderedList
18+
} from '@s-ui/documentation-library'
19+
import AtomLabel from '@s-ui/react-atom-label/lib'
20+
import PrimitiveVisuallyHidden from '@s-ui/react-primitive-visually-hidden'
21+
22+
import AtomInput from '../../src/index.js'
23+
24+
const ArticleAddonAndIcon = ({className}) => {
25+
const [state, setState] = useState({})
26+
const {icon, iconValue, rightAddon, leftAddon} = state
27+
const setStatus = (newState = {}) => setState({...state, ...newState})
28+
const valueIcon = iconValue ? <AntDesignIcon icon={iconValue} style={{color: 'currentColor'}} /> : null
29+
return (
30+
<Article className={className}>
31+
<H2>Addon and Icon</H2>
32+
<Paragraph>Input offers the possibility to add icons and contents on its left or right positions</Paragraph>
33+
<UnorderedList>
34+
<ListItem>
35+
<Code>leftAddon</Code> and <Code>rightAddon</Code>: use it as a label for the input field
36+
</ListItem>
37+
<ListItem>
38+
<Code>leftIcon</Code> and <Code>rightIcon</Code>: use it as a valid symbol for the field
39+
</ListItem>
40+
</UnorderedList>
41+
<Paragraph>This field props can be combined all together.</Paragraph>
42+
<Grid cols={2} gutter={[8, 8]}>
43+
<Cell span={2}>
44+
<PrimitiveVisuallyHidden>
45+
<AtomLabel htmlFor="input-icons-and-addons" text="icons and addons" />
46+
</PrimitiveVisuallyHidden>
47+
<AtomInput
48+
id="input-icons-and-addons"
49+
placeholder="icons and addons"
50+
leftIcon={icon === 'leftIcon' ? valueIcon : undefined}
51+
rightIcon={icon === 'rightIcon' ? valueIcon : undefined}
52+
leftAddon={leftAddon}
53+
rightAddon={rightAddon}
54+
/>
55+
</Cell>
56+
<Cell>
57+
<RadioButtonGroup
58+
onChange={(event, value) => {
59+
setStatus({icon: value})
60+
}}
61+
fullWidth
62+
>
63+
<RadioButton value="leftIcon" label="leftIcon" />
64+
<RadioButton value="rightIcon" label="rightIcon" />
65+
</RadioButtonGroup>
66+
</Cell>
67+
<Cell>
68+
<RadioButtonGroup
69+
onChange={(event, value) =>
70+
setStatus({
71+
iconValue: value
72+
})
73+
}
74+
fullWidth
75+
>
76+
<RadioButton
77+
value="AiFillFire"
78+
aria-label="fire"
79+
label={<AntDesignIcon icon="AiFillFire" style={{color: 'currentColor'}} />}
80+
/>
81+
<RadioButton
82+
value="AiOutlineSketch"
83+
aria-label="sketch"
84+
label={<AntDesignIcon icon="AiOutlineSketch" style={{color: 'currentColor'}} />}
85+
/>
86+
<RadioButton
87+
value="AiOutlineInfoCircle"
88+
aria-label="info"
89+
label={<AntDesignIcon icon="AiOutlineInfoCircle" style={{color: 'currentColor'}} />}
90+
/>
91+
<RadioButton
92+
value="AiTwotoneSkin"
93+
aria-label="skin"
94+
label={<AntDesignIcon icon="AiTwotoneSkin" style={{color: 'currentColor'}} />}
95+
/>
96+
<RadioButton
97+
value="AiOutlineExclamationCircle"
98+
aria-label="exclamation"
99+
label={<AntDesignIcon icon="AiOutlineExclamationCircle" style={{color: 'currentColor'}} />}
100+
/>
101+
<RadioButton
102+
value="AiOutlineCar"
103+
aria-label="car"
104+
label={<AntDesignIcon icon="AiOutlineCar" style={{color: 'currentColor'}} />}
105+
/>
106+
<RadioButton
107+
value="AiOutlineAppstore"
108+
aria-label="appstore"
109+
label={<AntDesignIcon icon="AiOutlineAppstore" style={{color: 'currentColor'}} />}
110+
/>
111+
<RadioButton
112+
value="AiFillTrophy"
113+
aria-label="trophy"
114+
label={<AntDesignIcon icon="AiFillTrophy" style={{color: 'currentColor'}} />}
115+
/>
116+
</RadioButtonGroup>
117+
</Cell>
118+
<Cell>
119+
<Input
120+
fullWidth
121+
placeholder="leftAddon text"
122+
onChange={event => setStatus({leftAddon: event.target.value})}
123+
/>
124+
</Cell>
125+
<Cell>
126+
<Input
127+
fullWidth
128+
placeholder="rightAddon text"
129+
onChange={event => setStatus({rightAddon: event.target.value})}
130+
/>
131+
</Cell>
132+
</Grid>
133+
</Article>
134+
)
135+
}
136+
137+
ArticleAddonAndIcon.propTypes = {
138+
className: PropTypes.node
139+
}
140+
141+
export default ArticleAddonAndIcon
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {useState} from 'react'
2+
3+
import PropTypes from 'prop-types'
4+
5+
import {Article, Box, Cell, Code, Grid, H2, Paragraph, RadioButton} from '@s-ui/documentation-library'
6+
7+
import AtomInput from '../../src/index.js'
8+
9+
const ArticleBorderless = ({className}) => {
10+
const [border, setBorder] = useState(true)
11+
const [mode, setMode] = useState('light')
12+
return (
13+
<Article className={className}>
14+
<H2>No border</H2>
15+
<Paragraph>
16+
The border of the input can be removed using the boolean prop <Code>noBorder</Code>
17+
</Paragraph>
18+
<Grid cols={2} gutter={[8, 8]}>
19+
<Cell>
20+
<RadioButton fullWidth value={border} label="hide border" onClick={(event, value) => setBorder(!value)} />
21+
</Cell>
22+
<Cell>
23+
<RadioButton
24+
fullWidth
25+
value={mode}
26+
label="set dark"
27+
onClick={(event, value) => setMode(value ? 'dark' : 'light')}
28+
/>
29+
</Cell>
30+
<Cell span={2}>
31+
<Box mode={mode}>
32+
<AtomInput placeholder="click to interact" noBorder={!border} />
33+
</Box>
34+
</Cell>
35+
</Grid>
36+
</Article>
37+
)
38+
}
39+
40+
ArticleBorderless.propTypes = {
41+
className: PropTypes.node
42+
}
43+
44+
export default ArticleBorderless
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import PropTypes from 'prop-types'
2+
3+
import {Article, H2, Paragraph} from '@s-ui/documentation-library'
4+
import AtomLabel from '@s-ui/react-atom-label/lib'
5+
import PrimitiveVisuallyHidden from '@s-ui/react-primitive-visually-hidden'
6+
7+
import AtomInput from '../../src/index.js'
8+
9+
const ArticleDefault = ({className}) => {
10+
return (
11+
<Article className={className}>
12+
<H2>Default</H2>
13+
<Paragraph>By default, the element gets the following look and feel.</Paragraph>
14+
<PrimitiveVisuallyHidden>
15+
<AtomLabel htmlFor="default" text="Label for default input" />
16+
</PrimitiveVisuallyHidden>
17+
<div>
18+
<AtomInput id="default" />
19+
</div>
20+
</Article>
21+
)
22+
}
23+
24+
ArticleDefault.propTypes = {
25+
className: PropTypes.node
26+
}
27+
28+
export default ArticleDefault
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import PropTypes from 'prop-types'
2+
3+
import {Article, Cell, Code, Grid, H2, Label, Paragraph} from '@s-ui/documentation-library'
4+
5+
import AtomInput from '../../src/index.js'
6+
7+
const ArticleDisabledReadOnly = ({className}) => {
8+
return (
9+
<Article className={className}>
10+
<H2>Disable and ReadOnly</H2>
11+
<Paragraph>
12+
Input provides two different modes that blocks the component behavior the difference between them is the
13+
appearance.
14+
</Paragraph>
15+
<Paragraph>
16+
The developer can disable the component using the <Code>disabled</Code> boolean prop. It can be blocked also
17+
using the <Code>readOnly</Code> boolean prop, but it will look like the default input.
18+
</Paragraph>
19+
<Grid gutter={[8, 8]} cols={2}>
20+
<Cell>
21+
<Label htmlFor="input-disabled">disabled</Label>
22+
</Cell>
23+
<Cell>
24+
<Label htmlFor="input-read-only">readOnly</Label>
25+
</Cell>
26+
<Cell>
27+
<AtomInput id="input-disabled" value="disabled" disabled />
28+
</Cell>
29+
<Cell>
30+
<AtomInput id="input-read-only" value="readOnly" readOnly />
31+
</Cell>
32+
</Grid>
33+
</Article>
34+
)
35+
}
36+
37+
ArticleDisabledReadOnly.propTypes = {
38+
className: PropTypes.node
39+
}
40+
41+
export default ArticleDisabledReadOnly

0 commit comments

Comments
 (0)