Skip to content

Commit 9ca62f9

Browse files
author
Michael Jordan
authored
fix(#2476): Picker: HTML5 autoComplete prop does not get added to HiddenSelect within Picker (#2477)
1 parent 9651f18 commit 9ca62f9

File tree

7 files changed

+414
-15
lines changed

7 files changed

+414
-15
lines changed

packages/@react-aria/select/src/HiddenSelect.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import {useInteractionModality} from '@react-aria/interactions';
1616
import {useVisuallyHidden} from '@react-aria/visually-hidden';
1717

1818
interface AriaHiddenSelectProps {
19+
/**
20+
* Describes the type of autocomplete functionality the input should provide if any. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete).
21+
*/
22+
autoComplete?: string,
23+
1924
/** The text label for the select. */
2025
label?: ReactNode,
2126

@@ -40,7 +45,7 @@ interface HiddenSelectProps<T> extends AriaHiddenSelectProps {
4045
* navigation, and native HTML form submission.
4146
*/
4247
export function useHiddenSelect<T>(props: AriaHiddenSelectProps, state: SelectState<T>, triggerRef: RefObject<HTMLElement>) {
43-
let {name, isDisabled} = props;
48+
let {autoComplete, name, isDisabled} = props;
4449
let modality = useInteractionModality();
4550
let {visuallyHiddenProps} = useVisuallyHidden();
4651

@@ -76,6 +81,7 @@ export function useHiddenSelect<T>(props: AriaHiddenSelectProps, state: SelectSt
7681
},
7782
selectProps: {
7883
tabIndex: -1,
84+
autoComplete,
7985
disabled: isDisabled,
8086
name,
8187
size: state.collection.size,
@@ -124,6 +130,7 @@ export function HiddenSelect<T>(props: HiddenSelectProps<T>) {
124130
return (
125131
<input
126132
type="hidden"
133+
autoComplete={selectProps.autoComplete}
127134
name={name}
128135
disabled={isDisabled}
129136
value={state.selectedKey} />

packages/@react-spectrum/form/stories/Form.stories.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {StatusLight} from '@react-spectrum/statuslight';
2929
import {storiesOf} from '@storybook/react';
3030
import {Switch} from '@react-spectrum/switch';
3131
import {TextArea, TextField} from '@react-spectrum/textfield';
32+
import typographyStyles from '@adobe/spectrum-css-temp/components/typography/vars.css';
33+
import {Well} from '@react-spectrum/well';
3234

3335
storiesOf('Form', module)
3436
.addParameters({providerSwitcher: {status: 'positive'}})
@@ -75,6 +77,74 @@ storiesOf('Form', module)
7577
</Form>
7678
)
7779
)
80+
.add(
81+
'fields with autoComplete property',
82+
() => {
83+
const [checked, setChecked] = useState(true);
84+
return (
85+
<Form>
86+
<Well role="group" aria-labelledby="billing-legend">
87+
<h2 id="billing-legend" className={typographyStyles['spectrum-Heading4']}>Billing address</h2>
88+
<Flex>
89+
<TextField autoComplete="billing given-name" name="firstName" isRequired label="First Name" placeholder="John" marginEnd="size-100" flex={1} />
90+
<TextField autoComplete="billing family-name" name="lastName" isRequired label="Last Name" placeholder="Smith" flex={1} />
91+
</Flex>
92+
<Flex>
93+
<TextArea autoComplete="billing street-address" name="streetAddress" isRequired label="Street Address" placeholder="123 Any Street" flex={1} />
94+
</Flex>
95+
<Flex>
96+
<TextField autoComplete="billing address-level2" name="city" isRequired label="City" placeholder="San Francisco" marginEnd="size-100" flex={1} />
97+
<Picker autoComplete="billing address-level1" name="state" isRequired label="State" placeholder="Select a state" items={states} marginEnd="size-100" flex={1}>
98+
{item => <Item key={item.abbr}>{item.name}</Item>}
99+
</Picker>
100+
<TextField autoComplete="billing postal-code" name="zip" isRequired label="Zip code" placeholder="12345" flex={1} />
101+
</Flex>
102+
<Flex>
103+
<Picker autoComplete="billing country" name="country" isRequired label="Country" placeholder="Select a country" items={countries} marginEnd="size-100" flex={1}>
104+
{item => <Item key={item.code}>{item.name}</Item>}
105+
</Picker>
106+
</Flex>
107+
<Flex>
108+
<TextField autoComplete="billing tel" type="tel" name="phone" label="Phone number" placeholder="123-456-7890" marginEnd="size-100" flex={1} />
109+
<TextField autoComplete="billing email" type="email" name="email" isRequired label="Email address" placeholder="[email protected]" marginEnd="size-100" flex={1} />
110+
</Flex>
111+
</Well>
112+
<Well role="group" aria-labelledby="shipping-legend">
113+
<h2 id="shipping-legend" className={typographyStyles['spectrum-Heading4']}>Shipping address</h2>
114+
<Checkbox isSelected={checked} onChange={setChecked} >Same as billing address</Checkbox>
115+
{
116+
!checked &&
117+
<>
118+
<Flex>
119+
<TextField autoComplete="shipping given-name" name="shippingFirstName" isRequired label="First Name" placeholder="John" marginEnd="size-100" flex={1} />
120+
<TextField autoComplete="shipping family-name" name="shippingLastName" isRequired label="Last Name" placeholder="Smith" flex={1} />
121+
</Flex>
122+
<Flex>
123+
<TextArea autoComplete="shipping street-address" name="shippingStreetAddress" isRequired label="Street Address" placeholder="123 Any Street" flex={1} />
124+
</Flex>
125+
<Flex>
126+
<TextField autoComplete="shipping address-level2" name="shippingCity" isRequired label="City" placeholder="San Francisco" marginEnd="size-100" flex={1} />
127+
<Picker autoComplete="shipping address-level1" name="shippingState" isRequired label="State" placeholder="Select a state" items={states} marginEnd="size-100" flex={1}>
128+
{item => <Item key={item.abbr}>{item.name}</Item>}
129+
</Picker>
130+
<TextField autoComplete="shipping postal-code" name="shippingZip" isRequired label="Zip code" placeholder="12345" flex={1} />
131+
</Flex>
132+
<Flex>
133+
<Picker autoComplete="shipping country" name="shippingCountry" isRequired label="Country" placeholder="Select a country" items={countries} marginEnd="size-100" flex={1}>
134+
{item => <Item key={item.code}>{item.name}</Item>}
135+
</Picker>
136+
</Flex>
137+
<Flex>
138+
<TextField autoComplete="shipping tel" type="tel" name="shippingPhone" label="Phone number" placeholder="123-456-7890" marginEnd="size-100" flex={1} />
139+
<TextField autoComplete="shipping email" type="email" name="shippingEmail" isRequired label="Email address" placeholder="[email protected]" marginEnd="size-100" flex={1} />
140+
</Flex>
141+
</>
142+
}
143+
</Well>
144+
</Form>
145+
);
146+
}
147+
)
78148
.add(
79149
'isRequired: true',
80150
() => render({isRequired: true})

packages/@react-spectrum/form/stories/data.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
export const states = [
22
{name: 'Alabama', abbr: 'AL'},
33
{name: 'Alaska', abbr: 'AK'},
4+
{name: 'American Samoa', abbr: 'AS'},
45
{name: 'Arizona', abbr: 'AZ'},
56
{name: 'Arkansas', abbr: 'AR'},
67
{name: 'California', abbr: 'CA'},
78
{name: 'Colorado', abbr: 'CO'},
89
{name: 'Connecticut', abbr: 'CT'},
910
{name: 'Delaware', abbr: 'DE'},
11+
{name: 'District Of Columbia', abbr: 'DC'},
12+
{name: 'Federated States Of Micronesia', abbr: 'FM'},
1013
{name: 'Florida', abbr: 'FL'},
1114
{name: 'Georgia', abbr: 'GA'},
15+
{name: 'Guam', abbr: 'GU'},
1216
{name: 'Hawaii', abbr: 'HI'},
1317
{name: 'Idaho', abbr: 'ID'},
1418
{name: 'Illinois', abbr: 'IL'},
@@ -17,34 +21,42 @@ export const states = [
1721
{name: 'Kansas', abbr: 'KS'},
1822
{name: 'Kentucky', abbr: 'KY'},
1923
{name: 'Louisiana', abbr: 'LA'},
24+
{name: 'Maine', abbr: 'ME'},
25+
{name: 'Marshall Islands', abbr: 'MH'},
2026
{name: 'Maryland', abbr: 'MD'},
2127
{name: 'Massachusetts', abbr: 'MA'},
22-
{name: 'Maine', abbr: 'ME'},
2328
{name: 'Michigan', abbr: 'MI'},
2429
{name: 'Minnesota', abbr: 'MN'},
2530
{name: 'Mississippi', abbr: 'MS'},
2631
{name: 'Missouri', abbr: 'MO'},
27-
{name: 'Montana', abbr: 'NT'},
32+
{name: 'Montana', abbr: 'MT'},
33+
{name: 'Nebraska', abbr: 'NE'},
2834
{name: 'Nevada', abbr: 'NV'},
35+
{name: 'New Hampshire', abbr: 'NH'},
2936
{name: 'New Jersey', abbr: 'NJ'},
3037
{name: 'New Mexico', abbr: 'NM'},
3138
{name: 'New York', abbr: 'NY'},
3239
{name: 'North Carolina', abbr: 'NC'},
3340
{name: 'North Dakota', abbr: 'ND'},
41+
{name: 'Northern Mariana Islands', abbr: 'MP'},
3442
{name: 'Ohio', abbr: 'OH'},
3543
{name: 'Oklahoma', abbr: 'OK'},
3644
{name: 'Oregon', abbr: 'OR'},
45+
{name: 'Palau', abbr: 'PW'},
3746
{name: 'Pennsylvania', abbr: 'PA'},
47+
{name: 'Puerto Rico', abbr: 'PR'},
3848
{name: 'Rhode Island', abbr: 'RI'},
3949
{name: 'South Carolina', abbr: 'SC'},
4050
{name: 'South Dakota', abbr: 'SD'},
4151
{name: 'Tennessee', abbr: 'TN'},
4252
{name: 'Texas', abbr: 'TX'},
4353
{name: 'Utah', abbr: 'UT'},
4454
{name: 'Vermont', abbr: 'VT'},
55+
{name: 'Virgin Islands', abbr: 'VI'},
4556
{name: 'Virginia', abbr: 'VA'},
4657
{name: 'Washington', abbr: 'WA'},
4758
{name: 'West Virginia', abbr: 'WV'},
59+
{name: 'Wisconsin', abbr: 'WI'},
4860
{name: 'Wyoming', abbr: 'WY'}
4961
];
5062

packages/@react-spectrum/picker/src/Picker.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function Picker<T extends object>(props: SpectrumPickerProps<T>, ref: DOMRef<HTM
4848
props = useProviderProps(props);
4949
let formatMessage = useMessageFormatter(intlMessages);
5050
let {
51+
autoComplete,
5152
isDisabled,
5253
direction = 'bottom',
5354
align = 'start',
@@ -199,6 +200,7 @@ function Picker<T extends object>(props: SpectrumPickerProps<T>, ref: DOMRef<HTM
199200
)
200201
}>
201202
<HiddenSelect
203+
autoComplete={autoComplete}
202204
isDisabled={isDisabled}
203205
state={state}
204206
triggerRef={unwrappedTriggerRef}

packages/@react-spectrum/picker/test/Picker.test.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {Item, Picker, Section} from '../src';
2020
import Paste from '@spectrum-icons/workflow/Paste';
2121
import {Provider} from '@react-spectrum/provider';
2222
import React from 'react';
23+
import {states} from './data';
2324
import {Text} from '@react-spectrum/text';
2425
import {theme} from '@react-spectrum/theme-default';
2526
import {triggerPress} from '@react-spectrum/test-utils';
@@ -1740,10 +1741,8 @@ describe('Picker', function () {
17401741
it('should have a hidden select element for form autocomplete', function () {
17411742
let {getByText, getByRole} = render(
17421743
<Provider theme={theme}>
1743-
<Picker label="Test" onSelectionChange={onSelectionChange}>
1744-
<Item key="one">One</Item>
1745-
<Item key="two">Two</Item>
1746-
<Item key="three">Three</Item>
1744+
<Picker label="Test" autoComplete="address-level1" items={states} onSelectionChange={onSelectionChange}>
1745+
{item => <Item key={item.abbr}>{item.name}</Item>}
17471746
</Picker>
17481747
</Provider>
17491748
);
@@ -1766,18 +1765,16 @@ describe('Picker', function () {
17661765
let hiddenSelect = getByRole('listbox', {hidden: true});
17671766
expect(hiddenSelect.parentElement).toBe(hiddenLabel);
17681767
expect(hiddenSelect).toHaveAttribute('tabIndex', '-1');
1768+
expect(hiddenSelect).toHaveAttribute('autoComplete', 'address-level1');
17691769

17701770
let options = within(hiddenSelect).getAllByRole('option', {hidden: true});
1771-
expect(options.length).toBe(4);
1772-
expect(options[0]).toHaveTextContent('');
1773-
expect(options[1]).toHaveTextContent('One');
1774-
expect(options[2]).toHaveTextContent('Two');
1775-
expect(options[3]).toHaveTextContent('Three');
1771+
expect(options.length).toBe(60);
1772+
options.forEach((option, index) => index > 0 && expect(option).toHaveTextContent(states[index - 1].name));
17761773

1777-
fireEvent.change(hiddenSelect, {target: {value: 'two'}});
1774+
fireEvent.change(hiddenSelect, {target: {value: 'CA'}});
17781775
expect(onSelectionChange).toHaveBeenCalledTimes(1);
1779-
expect(onSelectionChange).toHaveBeenLastCalledWith('two');
1780-
expect(picker).toHaveTextContent('Two');
1776+
expect(onSelectionChange).toHaveBeenLastCalledWith('CA');
1777+
expect(picker).toHaveTextContent('California');
17811778
});
17821779

17831780
it('should have a hidden input to marshall focus to the button', function () {

0 commit comments

Comments
 (0)