Skip to content

Commit 5731f62

Browse files
TylerJDevfrancineluccahectahertz
authored
SelectPanel: Remove FormControl.Label link with SelectPanel (#6363)
Co-authored-by: Marie Lucca <40550942+francinelucca@users.noreply.github.com> Co-authored-by: Hector Garcia <hectahertz@github.com>
1 parent 8731f43 commit 5731f62

File tree

7 files changed

+163
-40
lines changed

7 files changed

+163
-40
lines changed

.changeset/mean-trains-ring.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": patch
3+
---
4+
5+
SelectPanel: Remove `FormControl.Label` link with SelectPanel

packages/react/src/FormControl/FormControl.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const FormControl = React.forwardRef<HTMLDivElement, FormControlProps>(
7575
const isChoiceInput =
7676
React.isValidElement(InputComponent) && (InputComponent.type === Checkbox || InputComponent.type === Radio)
7777
const isRadioInput = React.isValidElement(InputComponent) && InputComponent.type === Radio
78+
const isSelectPanel = React.isValidElement(InputComponent) && InputComponent.type === SelectPanel
7879

7980
if (InputComponent) {
8081
warning(
@@ -165,6 +166,7 @@ const FormControl = React.forwardRef<HTMLDivElement, FormControlProps>(
165166
id,
166167
required,
167168
validationMessageId,
169+
isReferenced: !isSelectPanel,
168170
}}
169171
>
170172
{isChoiceInput || layout === 'horizontal' ? (

packages/react/src/FormControl/FormControlLabel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type Props = {
1717
const FormControlLabel: React.FC<
1818
React.PropsWithChildren<{htmlFor?: string} & React.ComponentProps<typeof InputLabel> & Props>
1919
> = ({as, children, htmlFor, id, visuallyHidden, requiredIndicator = true, requiredText, sx, className, ...props}) => {
20-
const {disabled, id: formControlId, required} = useFormControlContext()
20+
const {disabled, id: formControlId, required, isReferenced} = useFormControlContext()
2121

2222
/**
2323
* Ensure we can pass through props correctly, since legend/span accept no defined 'htmlFor'
@@ -41,7 +41,7 @@ const FormControlLabel: React.FC<
4141
id,
4242
className,
4343
visuallyHidden,
44-
htmlFor: htmlFor || formControlId,
44+
htmlFor: isReferenced ? htmlFor || formControlId : undefined,
4545
required,
4646
requiredText,
4747
requiredIndicator,

packages/react/src/FormControl/_FormControlContext.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import type {FormControlProps} from './FormControl'
55
interface FormControlContext extends Pick<FormControlProps, 'disabled' | 'id' | 'required'> {
66
captionId?: string
77
validationMessageId?: string
8+
/**
9+
* Determines whether the label is referenced by a form control.
10+
* This is used to determine whether the `htmlFor` attribute should be set on the label.
11+
*/
12+
isReferenced?: boolean
813
validationStatus?: FormValidationStatus
914
}
1015

packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,15 @@ export const HeightInitialWithOverflowingItemsStory = () => {
6262

6363
return (
6464
<FormControl>
65-
<FormControl.Label>Labels</FormControl.Label>
65+
<FormControl.Label id="height-overflow-label">Labels</FormControl.Label>
6666
<SelectPanel
67+
id="height-overflow"
6768
renderAnchor={({children, ...anchorProps}) => (
68-
<Button trailingAction={TriangleDownIcon} {...anchorProps}>
69+
<Button
70+
aria-labelledby="height-overflow height-overflow-label"
71+
trailingAction={TriangleDownIcon}
72+
{...anchorProps}
73+
>
6974
{children}
7075
</Button>
7176
)}
@@ -94,10 +99,15 @@ export const HeightInitialWithUnderflowingItemsStory = () => {
9499

95100
return (
96101
<FormControl>
97-
<FormControl.Label>Labels</FormControl.Label>
102+
<FormControl.Label id="height-underflow-label">Labels</FormControl.Label>
98103
<SelectPanel
104+
id="height-underflow"
99105
renderAnchor={({children, ...anchorProps}) => (
100-
<Button trailingAction={TriangleDownIcon} {...anchorProps}>
106+
<Button
107+
aria-labelledby="height-underflow height-underflow-label"
108+
trailingAction={TriangleDownIcon}
109+
{...anchorProps}
110+
>
101111
{children}
102112
</Button>
103113
)}
@@ -139,10 +149,15 @@ export const HeightInitialWithUnderflowingItemsAfterFetch = () => {
139149

140150
return (
141151
<FormControl>
142-
<FormControl.Label>Labels</FormControl.Label>
152+
<FormControl.Label id="height-after-fetch-label">Labels</FormControl.Label>
143153
<SelectPanel
154+
id="height-after-fetch"
144155
renderAnchor={({children, 'aria-labelledby': ariaLabelledBy, ...anchorProps}) => (
145-
<Button trailingAction={TriangleDownIcon} aria-labelledby={` ${ariaLabelledBy}`} {...anchorProps}>
156+
<Button
157+
trailingAction={TriangleDownIcon}
158+
aria-labelledby={`height-after-fetch height-after-fetch-label ${ariaLabelledBy || ''}`}
159+
{...anchorProps}
160+
>
146161
{children}
147162
</Button>
148163
)}
@@ -171,10 +186,15 @@ export const AboveTallBody = () => {
171186
const [open, setOpen] = useState(false)
172187
return (
173188
<FormControl>
174-
<FormControl.Label>Labels</FormControl.Label>
189+
<FormControl.Label id="above-tall-body-label">Labels</FormControl.Label>
175190
<SelectPanel
191+
id="above-tall-body"
176192
renderAnchor={({children, 'aria-labelledby': ariaLabelledBy, ...anchorProps}) => (
177-
<Button trailingAction={TriangleDownIcon} aria-labelledby={` ${ariaLabelledBy}`} {...anchorProps}>
193+
<Button
194+
trailingAction={TriangleDownIcon}
195+
aria-labelledby={`above-tall-body above-tall-body-label ${ariaLabelledBy || ''}`}
196+
{...anchorProps}
197+
>
178198
{children}
179199
</Button>
180200
)}
@@ -222,10 +242,15 @@ export const HeightVariationsAndScroll = () => {
222242
return (
223243
<>
224244
<FormControl>
225-
<FormControl.Label>With height:medium</FormControl.Label>
245+
<FormControl.Label id="height-variation-medium-label">With height:medium</FormControl.Label>
226246
<SelectPanel
247+
id="height-variation-medium"
227248
renderAnchor={({children, ...anchorProps}) => (
228-
<Button trailingAction={TriangleDownIcon} {...anchorProps}>
249+
<Button
250+
aria-labelledby="height-variation-medium-label height-variation-medium"
251+
trailingAction={TriangleDownIcon}
252+
{...anchorProps}
253+
>
229254
{children ?? 'Select Labels'}
230255
</Button>
231256
)}
@@ -243,10 +268,15 @@ export const HeightVariationsAndScroll = () => {
243268
</FormControl>
244269
<br />
245270
<FormControl>
246-
<FormControl.Label>With height:auto, maxheight:medium</FormControl.Label>
271+
<FormControl.Label id="height-variation-maxheight-label">With height:auto, maxheight:medium</FormControl.Label>
247272
<SelectPanel
273+
id="height-variation-maxheight"
248274
renderAnchor={({children, ...anchorProps}) => (
249-
<Button trailingAction={TriangleDownIcon} {...anchorProps}>
275+
<Button
276+
aria-labelledby="height-variation-maxheight-label height-variation-maxheight"
277+
trailingAction={TriangleDownIcon}
278+
{...anchorProps}
279+
>
250280
{children ?? 'Select Labels'}
251281
</Button>
252282
)}
@@ -284,11 +314,19 @@ export const CustomItemRenderer = () => {
284314

285315
return (
286316
<FormControl>
287-
<FormControl.Label>Long string with truncation (not reviewed for accessibility)</FormControl.Label>
317+
<FormControl.Label id="custom-item-renderer-label">
318+
Long string with truncation (not reviewed for accessibility)
319+
</FormControl.Label>
288320
<SelectPanel
321+
id="custom-item-renderer"
289322
title="Select files"
290323
renderAnchor={anchorProps => (
291-
<Button trailingAction={TriangleDownIcon} {...anchorProps} aria-haspopup="dialog">
324+
<Button
325+
aria-labelledby="custom-item-renderer-label"
326+
trailingAction={TriangleDownIcon}
327+
{...anchorProps}
328+
aria-haspopup="dialog"
329+
>
292330
Select files
293331
</Button>
294332
)}
@@ -351,9 +389,19 @@ export const ItemsInScope = () => {
351389
const [open, setOpen] = useState(false)
352390
return (
353391
<FormControl>
354-
<FormControl.Label>Items in component scope</FormControl.Label>
392+
<FormControl.Label id="component-scope-label">Items in component scope</FormControl.Label>
355393
<SelectPanel
394+
id="component-scope"
356395
title="Select labels"
396+
renderAnchor={({children, ...anchorProps}) => (
397+
<Button
398+
aria-labelledby="component-scope component-scope-label"
399+
trailingAction={TriangleDownIcon}
400+
{...anchorProps}
401+
>
402+
{children}
403+
</Button>
404+
)}
357405
placeholder="Select labels" // button text when no items are selected
358406
open={open}
359407
onOpenChange={setOpen}

0 commit comments

Comments
 (0)