Skip to content

Commit 0b2a838

Browse files
Allow passing inputRef to RAC <Radio> (#6067)
* add focusable ref feature to RadioGroup * update story * add filter to getFocusableTreeWalker * Revert "add focusable ref feature to RadioGroup" This reverts commit 778dd64. * Add props.inputRef to <Radio> * Update RadioGroup.tsx - fix lint * Update RadioGroup.tsx - fix alphabet --------- Co-authored-by: Robert Snow <rsnow@adobe.com> Co-authored-by: Robert Snow <snowystinger@gmail.com>
1 parent 2318292 commit 0b2a838

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

packages/react-aria-components/src/RadioGroup.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@
1313
import {AriaRadioGroupProps, AriaRadioProps, HoverEvents, Orientation, useFocusRing, useHover, useRadio, useRadioGroup, VisuallyHidden} from 'react-aria';
1414
import {ContextValue, forwardRefType, Provider, RACValidation, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot} from './utils';
1515
import {FieldErrorContext} from './FieldError';
16-
import {filterDOMProps, mergeProps} from '@react-aria/utils';
16+
import {filterDOMProps, mergeProps, mergeRefs, useObjectRef} from '@react-aria/utils';
1717
import {FormValidationBehaviorContext} from './Form';
1818
import {LabelContext} from './Label';
1919
import {RadioGroupState, useRadioGroupState} from 'react-stately';
20-
import React, {createContext, ForwardedRef, forwardRef, useContext, useRef} from 'react';
20+
import React, {createContext, ForwardedRef, forwardRef, MutableRefObject, useContext} from 'react';
2121
import {TextContext} from './Text';
2222

2323
export interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'children' | 'label' | 'description' | 'errorMessage' | 'validationState' | 'validationBehavior'>, RACValidation, RenderProps<RadioGroupRenderProps>, SlotProps {}
24-
export interface RadioProps extends Omit<AriaRadioProps, 'children'>, HoverEvents, RenderProps<RadioRenderProps>, SlotProps {}
24+
export interface RadioProps extends Omit<AriaRadioProps, 'children'>, HoverEvents, RenderProps<RadioRenderProps>, SlotProps {
25+
/**
26+
* A ref for the HTML input element.
27+
*/
28+
inputRef?: MutableRefObject<HTMLInputElement>
29+
}
2530

2631
export interface RadioGroupRenderProps {
2732
/**
@@ -166,9 +171,13 @@ function RadioGroup(props: RadioGroupProps, ref: ForwardedRef<HTMLDivElement>) {
166171
}
167172

168173
function Radio(props: RadioProps, ref: ForwardedRef<HTMLLabelElement>) {
169-
[props, ref] = useContextProps(props, ref, RadioContext);
174+
let {
175+
inputRef: userProvidedInputRef = null,
176+
...otherProps
177+
} = props;
178+
[props, ref] = useContextProps(otherProps, ref, RadioContext);
170179
let state = React.useContext(RadioGroupStateContext)!;
171-
let inputRef = useRef<HTMLInputElement>(null);
180+
let inputRef = useObjectRef(mergeRefs(userProvidedInputRef, props.inputRef !== undefined ? props.inputRef : null));
172181
let {labelProps, inputProps, isSelected, isDisabled, isPressed} = useRadio({
173182
...removeDataAttributes<RadioProps>(props),
174183
// ReactNode type doesn't allow function children.

packages/react-aria-components/test/RadioGroup.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,4 +490,32 @@ describe('RadioGroup', () => {
490490
expect(groupRef.current).toBe(getByRole('radiogroup'));
491491
expect(radioRef.current).toBe(getByRole('radio').closest('.react-aria-Radio'));
492492
});
493+
494+
it('should support input ref', () => {
495+
let inputRef = React.createRef();
496+
let {getByRole} = render(
497+
<RadioGroup>
498+
<Label>Test</Label>
499+
<Radio inputRef={inputRef} value="a">A</Radio>
500+
</RadioGroup>
501+
);
502+
let radio = getByRole('radio');
503+
expect(inputRef.current).toBe(radio);
504+
});
505+
506+
it('should support and merge input ref on context', () => {
507+
let inputRef = React.createRef();
508+
let contextInputRef = React.createRef();
509+
let {getByRole} = render(
510+
<RadioGroup>
511+
<Label>Test</Label>
512+
<RadioContext.Provider value={{inputRef: contextInputRef}}>
513+
<Radio inputRef={inputRef} value="a">A</Radio>
514+
</RadioContext.Provider>
515+
</RadioGroup>
516+
);
517+
let radio = getByRole('radio');
518+
expect(inputRef.current).toBe(radio);
519+
expect(contextInputRef.current).toBe(radio);
520+
});
493521
});

0 commit comments

Comments
 (0)