Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add disableNativeInput?: boolean prop to all components that render hidden inputs #3366

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .yarn/versions/9b6bc09d.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
releases:
"@radix-ui/react-checkbox": patch
"@radix-ui/react-radio-group": patch
"@radix-ui/react-select": patch
"@radix-ui/react-slider": patch
"@radix-ui/react-switch": patch
radix-ui: patch

declined:
- primitives
10 changes: 8 additions & 2 deletions packages/react/checkbox/src/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface CheckboxProps extends Omit<PrimitiveButtonProps, 'checked' | 'defaultC
checked?: CheckedState;
defaultChecked?: CheckedState;
required?: boolean;
disableNativeInput?: boolean;
onCheckedChange?(checked: CheckedState): void;
}

Expand All @@ -50,13 +51,18 @@ const Checkbox = React.forwardRef<CheckboxElement, CheckboxProps>(
value = 'on',
onCheckedChange,
form,
disableNativeInput,
...checkboxProps
} = props;
const [button, setButton] = React.useState<HTMLButtonElement | null>(null);
const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
const hasConsumerStoppedPropagationRef = React.useRef(false);
// We set this to true by default so that events bubble to forms without JS (SSR)
const isFormControl = button ? form || !!button.closest('form') : true;
// We set this to true by default so that events bubble to forms without JS (SSR).
const isFormControl = disableNativeInput
? false
: button
? form || !!button.closest('form')
: true;
const [checked = false, setChecked] = useControllableState({
prop: checkedProp,
defaultProp: defaultChecked,
Expand Down
8 changes: 7 additions & 1 deletion packages/react/radio-group/src/radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.butt
interface RadioProps extends PrimitiveButtonProps {
checked?: boolean;
required?: boolean;
disableNativeInput?: boolean;
onCheck?(): void;
}

Expand All @@ -40,13 +41,18 @@ const Radio = React.forwardRef<RadioElement, RadioProps>(
value = 'on',
onCheck,
form,
disableNativeInput,
...radioProps
} = props;
const [button, setButton] = React.useState<HTMLButtonElement | null>(null);
const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
const hasConsumerStoppedPropagationRef = React.useRef(false);
// We set this to true by default so that events bubble to forms without JS (SSR)
const isFormControl = button ? form || !!button.closest('form') : true;
const isFormControl = disableNativeInput
? false
: button
? form || !!button.closest('form')
: true;

return (
<RadioProvider scope={__scopeRadio} checked={checked} disabled={disabled}>
Expand Down
8 changes: 7 additions & 1 deletion packages/react/select/src/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ interface SelectProps {
disabled?: boolean;
required?: boolean;
form?: string;
disableNativeInput?: boolean;
}

const Select: React.FC<SelectProps> = (props: ScopedProps<SelectProps>) => {
Expand All @@ -110,6 +111,7 @@ const Select: React.FC<SelectProps> = (props: ScopedProps<SelectProps>) => {
disabled,
required,
form,
disableNativeInput,
} = props;
const popperScope = usePopperScope(__scopeSelect);
const [trigger, setTrigger] = React.useState<SelectTriggerElement | null>(null);
Expand All @@ -129,7 +131,11 @@ const Select: React.FC<SelectProps> = (props: ScopedProps<SelectProps>) => {
const triggerPointerDownPosRef = React.useRef<{ x: number; y: number } | null>(null);

// We set this to true by default so that events bubble to forms without JS (SSR)
const isFormControl = trigger ? form || !!trigger.closest('form') : true;
const isFormControl = disableNativeInput
? false
: trigger
? form || !!trigger.closest('form')
: true;
const [nativeOptionsSet, setNativeOptionsSet] = React.useState(new Set<NativeOption>());

// The native `select` only associates the correct default value if the corresponding
Expand Down
9 changes: 7 additions & 2 deletions packages/react/slider/src/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -550,17 +550,22 @@ type SliderThumbImplElement = React.ElementRef<typeof Primitive.span>;
interface SliderThumbImplProps extends PrimitiveSpanProps {
index: number;
name?: string;
disableNativeInput?: boolean;
}

const SliderThumbImpl = React.forwardRef<SliderThumbImplElement, SliderThumbImplProps>(
(props: ScopedProps<SliderThumbImplProps>, forwardedRef) => {
const { __scopeSlider, index, name, ...thumbProps } = props;
const { __scopeSlider, index, name, disableNativeInput, ...thumbProps } = props;
const context = useSliderContext(THUMB_NAME, __scopeSlider);
const orientation = useSliderOrientationContext(THUMB_NAME, __scopeSlider);
const [thumb, setThumb] = React.useState<HTMLSpanElement | null>(null);
const composedRefs = useComposedRefs(forwardedRef, (node) => setThumb(node));
// We set this to true by default so that events bubble to forms without JS (SSR)
const isFormControl = thumb ? context.form || !!thumb.closest('form') : true;
const isFormControl = disableNativeInput
? false
: thumb
? context.form || !!thumb.closest('form')
: true;
const size = useSize(thumb);
// We cast because index could be `-1` which would return undefined
const value = context.values[index] as number | undefined;
Expand Down
8 changes: 7 additions & 1 deletion packages/react/switch/src/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface SwitchProps extends PrimitiveButtonProps {
checked?: boolean;
defaultChecked?: boolean;
required?: boolean;
disableNativeInput?: boolean;
onCheckedChange?(checked: boolean): void;
}

Expand All @@ -42,13 +43,18 @@ const Switch = React.forwardRef<SwitchElement, SwitchProps>(
value = 'on',
onCheckedChange,
form,
disableNativeInput,
...switchProps
} = props;
const [button, setButton] = React.useState<HTMLButtonElement | null>(null);
const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node));
const hasConsumerStoppedPropagationRef = React.useRef(false);
// We set this to true by default so that events bubble to forms without JS (SSR)
const isFormControl = button ? form || !!button.closest('form') : true;
const isFormControl = disableNativeInput
? false
: button
? form || !!button.closest('form')
: true;
const [checked = false, setChecked] = useControllableState({
prop: checkedProp,
defaultProp: defaultChecked,
Expand Down