diff --git a/.changeset/violet-tools-refuse.md b/.changeset/violet-tools-refuse.md
new file mode 100644
index 0000000000..b6c6ccf257
--- /dev/null
+++ b/.changeset/violet-tools-refuse.md
@@ -0,0 +1,8 @@
+---
+"@nextui-org/checkbox": patch
+"@nextui-org/switch": patch
+"@nextui-org/radio": patch
+"@nextui-org/theme": patch
+---
+
+Fix #4252 #4260 interactive elements were not working properly
diff --git a/packages/components/checkbox/src/checkbox.tsx b/packages/components/checkbox/src/checkbox.tsx
index 9ca4ee6e2a..2fc2a18c2d 100644
--- a/packages/components/checkbox/src/checkbox.tsx
+++ b/packages/components/checkbox/src/checkbox.tsx
@@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
-import {VisuallyHidden} from "@react-aria/visually-hidden";
import {cloneElement, ReactElement} from "react";
import {UseCheckboxProps, useCheckbox} from "./use-checkbox";
@@ -26,9 +25,7 @@ const Checkbox = forwardRef<"input", CheckboxProps>((props, ref) => {
return (
-
-
-
+
{clonedIcon}
{children && {children}}
diff --git a/packages/components/checkbox/src/use-checkbox.ts b/packages/components/checkbox/src/use-checkbox.ts
index 376541cb1d..bba104f6d6 100644
--- a/packages/components/checkbox/src/use-checkbox.ts
+++ b/packages/components/checkbox/src/use-checkbox.ts
@@ -310,9 +310,10 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
return {
ref: mergeRefs(inputRef, ref),
...mergeProps(inputProps, focusProps),
+ className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(inputProps.onChange, handleCheckboxChange),
};
- }, [inputProps, focusProps, handleCheckboxChange]);
+ }, [inputProps, focusProps, handleCheckboxChange, classNames?.hiddenInput]);
const getLabelProps: PropGetter = useCallback(
() => ({
diff --git a/packages/components/radio/src/radio.tsx b/packages/components/radio/src/radio.tsx
index 85535004f0..df80b892a1 100644
--- a/packages/components/radio/src/radio.tsx
+++ b/packages/components/radio/src/radio.tsx
@@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
-import {VisuallyHidden} from "@react-aria/visually-hidden";
import {UseRadioProps, useRadio} from "./use-radio";
@@ -21,9 +20,7 @@ const Radio = forwardRef<"input", RadioProps>((props, ref) => {
return (
-
-
-
+
diff --git a/packages/components/radio/src/use-radio.ts b/packages/components/radio/src/use-radio.ts
index b171b1e006..78b452827e 100644
--- a/packages/components/radio/src/use-radio.ts
+++ b/packages/components/radio/src/use-radio.ts
@@ -202,6 +202,7 @@ export function useRadio(props: UseRadioProps) {
return {
ref: inputRef,
...mergeProps(props, inputProps, focusProps),
+ className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(inputProps.onChange, onChange),
};
},
diff --git a/packages/components/switch/src/switch.tsx b/packages/components/switch/src/switch.tsx
index d60428bfcd..bc64125194 100644
--- a/packages/components/switch/src/switch.tsx
+++ b/packages/components/switch/src/switch.tsx
@@ -1,4 +1,3 @@
-import {VisuallyHidden} from "@react-aria/visually-hidden";
import {cloneElement, ReactElement} from "react";
import {forwardRef} from "@nextui-org/system";
@@ -35,9 +34,7 @@ const Switch = forwardRef<"input", SwitchProps>((props, ref) => {
return (
-
-
-
+
{startContent && clonedStartContent}
{thumbIcon && clonedThumbIcon}
diff --git a/packages/components/switch/src/use-switch.ts b/packages/components/switch/src/use-switch.ts
index 34adb52e54..faee7334ed 100644
--- a/packages/components/switch/src/use-switch.ts
+++ b/packages/components/switch/src/use-switch.ts
@@ -162,6 +162,7 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
});
const isInteractionDisabled = ariaSwitchProps.isDisabled || isReadOnly;
+
const pressed = isInteractionDisabled ? false : isPressed;
const isSelected = inputProps.checked;
@@ -209,6 +210,7 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
...mergeProps(inputProps, focusProps, props),
ref: mergeRefs(inputRef, ref),
id: inputProps.id,
+ className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(onChange, inputProps.onChange),
};
};
diff --git a/packages/core/theme/src/components/checkbox.ts b/packages/core/theme/src/components/checkbox.ts
index 3a9de2c9a0..847f640662 100644
--- a/packages/core/theme/src/components/checkbox.ts
+++ b/packages/core/theme/src/components/checkbox.ts
@@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
-import {groupDataFocusVisibleClasses} from "../utils";
+import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Checkbox wrapper **Tailwind Variants** component
@@ -51,7 +51,8 @@ const checkbox = tv({
// focus ring
...groupDataFocusVisibleClasses,
],
- icon: "z-10 w-4 h-3 opacity-0 group-data-[selected=true]:opacity-100",
+ hiddenInput: hiddenInputClasses,
+ icon: "z-10 w-4 h-3 opacity-0 group-data-[selected=true]:opacity-100 pointer-events-none",
label: "relative text-foreground select-none",
},
variants: {
diff --git a/packages/core/theme/src/components/radio.ts b/packages/core/theme/src/components/radio.ts
index a5161981fd..40a826e1e2 100644
--- a/packages/core/theme/src/components/radio.ts
+++ b/packages/core/theme/src/components/radio.ts
@@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
-import {groupDataFocusVisibleClasses} from "../utils";
+import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Radio wrapper **Tailwind Variants** component
@@ -44,6 +44,7 @@ const radio = tv({
// focus ring
...groupDataFocusVisibleClasses,
],
+ hiddenInput: hiddenInputClasses,
labelWrapper: "flex flex-col ml-1",
control: [
"z-10",
diff --git a/packages/core/theme/src/components/toggle.ts b/packages/core/theme/src/components/toggle.ts
index a06217e8ae..2787728200 100644
--- a/packages/core/theme/src/components/toggle.ts
+++ b/packages/core/theme/src/components/toggle.ts
@@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
-import {groupDataFocusVisibleClasses} from "../utils";
+import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Toggle (Switch) wrapper **Tailwind Variants** component
@@ -53,7 +53,9 @@ const toggle = tv({
"shadow-small",
"rounded-full",
"origin-right",
+ "pointer-events-none",
],
+ hiddenInput: hiddenInputClasses,
startContent: "z-0 absolute start-1.5 text-current",
endContent: "z-0 absolute end-1.5 text-default-600",
thumbIcon: "text-black",
diff --git a/packages/core/theme/src/utils/classes.ts b/packages/core/theme/src/utils/classes.ts
index 7ed19d23a1..2711a48a3b 100644
--- a/packages/core/theme/src/utils/classes.ts
+++ b/packages/core/theme/src/utils/classes.ts
@@ -67,3 +67,38 @@ export const collapseAdjacentVariantBorders = {
warning: ["[&+.border-medium.border-warning]:ms-[calc(theme(borderWidth.medium)*-1)]"],
danger: ["[&+.border-medium.border-danger]:ms-[calc(theme(borderWidth.medium)*-1)]"],
};
+
+export const hiddenInputClasses = [
+ // Variables
+ "[--cursor-hit-x:8px]",
+
+ // Font styles
+ "font-inherit",
+ "text-[100%]",
+ "leading-[1.15]",
+
+ // Reset margins and padding
+ "m-0",
+ "p-0",
+
+ // Overflow and box-sizing
+ "overflow-visible",
+ "box-border",
+
+ // Positioning & Hit area
+ "absolute",
+ "top-0",
+ "start-[calc(var(--cursor-hit-x)*-1)]",
+ "w-[calc(100%+var(--cursor-hit-x)*2)]",
+ "h-full",
+
+ // Opacity and z-index
+ "opacity-[0.0001]",
+ "z-[1]",
+
+ // Cursor
+ "cursor-pointer",
+
+ // Disabled state
+ "disabled:cursor-default",
+];
diff --git a/packages/core/theme/src/utils/index.ts b/packages/core/theme/src/utils/index.ts
index 2a096ff86a..f80e69ec6b 100644
--- a/packages/core/theme/src/utils/index.ts
+++ b/packages/core/theme/src/utils/index.ts
@@ -7,6 +7,7 @@ export {
translateCenterClasses,
absoluteFullClasses,
collapseAdjacentVariantBorders,
+ hiddenInputClasses,
} from "./classes";
export type {SlotsToClasses} from "./types";
export {colorVariants} from "./variants";