diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index e010ef6c5f..c8291c4ebc 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Prefer incoming `data-*` attributes, over the ones set by Headless UI ([#3035](https://github.com/tailwindlabs/headlessui/pull/3035))
- Respect `selectedIndex` for controlled `` components ([#3037](https://github.com/tailwindlabs/headlessui/pull/3037))
- Prevent unnecessary execution of the `displayValue` callback in the `ComboboxInput` component ([#3048](https://github.com/tailwindlabs/headlessui/pull/3048))
+- Expose missing `data-disabled` and `data-focus` attributes on the `TabsPanel`, `MenuButton`, `PopoverButton` and `DisclosureButton` components ([#3061](https://github.com/tailwindlabs/headlessui/pull/3061))
### Changed
diff --git a/packages/@headlessui-react/src/components/button/button.tsx b/packages/@headlessui-react/src/components/button/button.tsx
index 031fef5220..daf3e9bfc6 100644
--- a/packages/@headlessui-react/src/components/button/button.tsx
+++ b/packages/@headlessui-react/src/components/button/button.tsx
@@ -41,34 +41,27 @@ function ButtonFn(
ref: Ref
) {
let providedDisabled = useDisabled()
- let { disabled = providedDisabled || false, ...theirProps } = props
+ let { disabled = providedDisabled || false, autoFocus = false, ...theirProps } = props
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let { pressed: active, pressProps } = useActivePress({ disabled })
let ourProps = mergeProps(
{
ref,
- disabled: disabled || undefined,
type: theirProps.type ?? 'button',
+ disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps,
pressProps
)
- let slot = useMemo(
- () =>
- ({
- disabled,
- hover,
- focus,
- active,
- autofocus: props.autoFocus ?? false,
- }) satisfies ButtonRenderPropArg,
- [disabled, hover, focus, active, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return { disabled, hover, focus, active, autofocus: autoFocus } satisfies ButtonRenderPropArg
+ }, [disabled, hover, focus, active, autoFocus])
return render({
ourProps,
diff --git a/packages/@headlessui-react/src/components/checkbox/checkbox.tsx b/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
index c67e9653ba..8ee45ba860 100644
--- a/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
+++ b/packages/@headlessui-react/src/components/checkbox/checkbox.tsx
@@ -83,6 +83,7 @@ function CheckboxFn) => event.preventDefault())
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
let ourProps = mergeProps(
{
@@ -151,20 +152,18 @@ function CheckboxFn
- ({
- checked,
- disabled,
- hover,
- focus,
- active,
- indeterminate,
- changing,
- autofocus: props.autoFocus ?? false,
- }) satisfies CheckboxRenderPropArg,
- [checked, indeterminate, disabled, hover, focus, active, changing, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ checked,
+ disabled,
+ hover,
+ focus,
+ active,
+ indeterminate,
+ changing,
+ autofocus: autoFocus,
+ } satisfies CheckboxRenderPropArg
+ }, [checked, indeterminate, disabled, hover, focus, active, changing, autoFocus])
let reset = useCallback(() => {
return onChange?.(defaultChecked)
diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx
index f5752a0935..42bd0446fb 100644
--- a/packages/@headlessui-react/src/components/combobox/combobox.tsx
+++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx
@@ -770,22 +770,20 @@ function ComboboxFn
- ({
- open: data.comboboxState === ComboboxState.Open,
- disabled,
- activeIndex: data.activeOptionIndex,
- activeOption:
- data.activeOptionIndex === null
- ? null
- : data.virtual
- ? data.virtual.options[data.activeOptionIndex ?? 0]
- : (data.options[data.activeOptionIndex]?.dataRef.current.value as TValue) ?? null,
- value,
- }) satisfies ComboboxRenderPropArg,
- [data, disabled, value]
- )
+ let slot = useMemo(() => {
+ return {
+ open: data.comboboxState === ComboboxState.Open,
+ disabled,
+ activeIndex: data.activeOptionIndex,
+ activeOption:
+ data.activeOptionIndex === null
+ ? null
+ : data.virtual
+ ? data.virtual.options[data.activeOptionIndex ?? 0]
+ : (data.options[data.activeOptionIndex]?.dataRef.current.value as TValue) ?? null,
+ value,
+ } satisfies ComboboxRenderPropArg
+ }, [data, disabled, value])
let selectActiveOption = useEvent(() => {
if (data.activeOptionIndex === null) return
@@ -958,6 +956,7 @@ export type ComboboxInputProps<
InputPropsWeControl,
{
defaultValue?: TType
+ disabled?: boolean
displayValue?(item: TType): string
onChange?(event: React.ChangeEvent): void
autoFocus?: boolean
@@ -970,18 +969,21 @@ function InputFn<
// But today is not that day..
TType = Parameters[0]['value'],
>(props: ComboboxInputProps, ref: Ref) {
+ let data = useData('Combobox.Input')
+ let actions = useActions('Combobox.Input')
+
let internalId = useId()
let providedId = useProvidedId()
let {
id = providedId || `headlessui-combobox-input-${internalId}`,
onChange,
displayValue,
+ disabled = data.disabled || false,
+ autoFocus = false,
// @ts-ignore: We know this MAY NOT exist for a given tag but we only care when it _does_ exist.
type = 'text',
...theirProps
} = props
- let data = useData('Combobox.Input')
- let actions = useActions('Combobox.Input')
let inputRef = useSyncRefs(data.inputRef, ref, useFloatingReference())
let ownerDocument = useOwnerDocument(data.inputRef)
@@ -1320,20 +1322,18 @@ function InputFn<
let labelledBy = useLabelledBy()
let describedBy = useDescribedBy()
- let { isFocused: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: data.disabled ?? false })
+ let { isFocused: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
- let slot = useMemo(
- () =>
- ({
- open: data.comboboxState === ComboboxState.Open,
- disabled: data.disabled,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies InputRenderPropArg,
- [data, hover, focus, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ open: data.comboboxState === ComboboxState.Open,
+ disabled,
+ hover,
+ focus,
+ autofocus: autoFocus,
+ } satisfies InputRenderPropArg
+ }, [data, hover, focus, autoFocus, disabled])
let ourProps = mergeProps(
{
@@ -1365,7 +1365,8 @@ function InputFn<
? displayValue?.(data.defaultValue as unknown as TType)
: null) ??
data.defaultValue,
- disabled: data.disabled,
+ disabled: disabled || undefined,
+ autoFocus,
onCompositionStart: handleCompositionStart,
onCompositionEnd: handleCompositionEnd,
onKeyDown: handleKeyDown,
@@ -1411,6 +1412,7 @@ export type ComboboxButtonProps
@@ -1422,7 +1424,12 @@ function ButtonFn(
let actions = useActions('Combobox.Button')
let buttonRef = useSyncRefs(data.buttonRef, ref)
let internalId = useId()
- let { id = `headlessui-combobox-button-${internalId}`, ...theirProps } = props
+ let {
+ id = `headlessui-combobox-button-${internalId}`,
+ disabled = data.disabled || false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let d = useDisposables()
let handleKeyDown = useEvent((event: ReactKeyboardEvent) => {
@@ -1479,22 +1486,20 @@ function ButtonFn(
let labelledBy = useLabelledBy([id])
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: data.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: data.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
- let slot = useMemo(
- () =>
- ({
- open: data.comboboxState === ComboboxState.Open,
- active: active || data.comboboxState === ComboboxState.Open,
- disabled: data.disabled,
- value: data.value,
- hover,
- focus,
- }) satisfies ButtonRenderPropArg,
- [data, hover, focus, active]
- )
+ let slot = useMemo(() => {
+ return {
+ open: data.comboboxState === ComboboxState.Open,
+ active: active || data.comboboxState === ComboboxState.Open,
+ disabled,
+ value: data.value,
+ hover,
+ focus,
+ } satisfies ButtonRenderPropArg
+ }, [data, hover, focus, active, disabled])
let ourProps = mergeProps(
{
ref: buttonRef,
@@ -1505,7 +1510,8 @@ function ButtonFn(
'aria-controls': data.optionsRef.current?.id,
'aria-expanded': data.comboboxState === ComboboxState.Open,
'aria-labelledby': labelledBy,
- disabled: data.disabled,
+ disabled: disabled || undefined,
+ autoFocus,
onClick: handleClick,
onKeyDown: handleKeyDown,
},
@@ -1592,14 +1598,12 @@ function OptionsFn(
let labelledBy = useLabelledBy([data.buttonRef.current?.id])
- let slot = useMemo(
- () =>
- ({
- open: data.comboboxState === ComboboxState.Open,
- option: undefined,
- }) satisfies OptionsRenderPropArg,
- [data]
- )
+ let slot = useMemo(() => {
+ return {
+ open: data.comboboxState === ComboboxState.Open,
+ option: undefined,
+ } satisfies OptionsRenderPropArg
+ }, [data])
let ourProps = mergeProps(anchor ? getFloatingPanelProps() : {}, {
'aria-labelledby': labelledBy,
role: 'listbox',
diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx
index 349c06e01d..2f9935513f 100644
--- a/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx
+++ b/packages/@headlessui-react/src/components/disclosure/disclosure.test.tsx
@@ -268,6 +268,7 @@ describe('Rendering', () => {
open: false,
hover: false,
active: false,
+ disabled: false,
focus: false,
autofocus: false,
}),
@@ -283,6 +284,7 @@ describe('Rendering', () => {
open: true,
hover: false,
active: false,
+ disabled: false,
focus: false,
autofocus: false,
}),
@@ -310,6 +312,7 @@ describe('Rendering', () => {
open: false,
hover: false,
active: false,
+ disabled: false,
focus: false,
autofocus: false,
}),
@@ -325,6 +328,7 @@ describe('Rendering', () => {
open: true,
hover: false,
active: false,
+ disabled: false,
focus: false,
autofocus: false,
}),
diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx
index 70c01b1550..4c6d01db43 100644
--- a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx
+++ b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx
@@ -220,14 +220,12 @@ function DisclosureFn(
let api = useMemo>(() => ({ close }), [close])
- let slot = useMemo(
- () =>
- ({
- open: disclosureState === DisclosureStates.Open,
- close,
- }) satisfies DisclosureRenderPropArg,
- [disclosureState, close]
- )
+ let slot = useMemo(() => {
+ return {
+ open: disclosureState === DisclosureStates.Open,
+ close,
+ } satisfies DisclosureRenderPropArg
+ }, [disclosureState, close])
let ourProps = {
ref: disclosureRef,
@@ -262,6 +260,7 @@ type ButtonRenderPropArg = {
open: boolean
hover: boolean
active: boolean
+ disabled: boolean
focus: boolean
autofocus: boolean
}
@@ -282,7 +281,12 @@ function ButtonFn(
ref: Ref
) {
let internalId = useId()
- let { id = `headlessui-disclosure-button-${internalId}`, ...theirProps } = props
+ let {
+ id = `headlessui-disclosure-button-${internalId}`,
+ disabled = false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let [state, dispatch] = useDisclosureContext('Disclosure.Button')
let panelContext = useDisclosurePanelContext()
let isWithinPanel = panelContext === null ? false : panelContext === state.panelId
@@ -338,7 +342,7 @@ function ButtonFn(
let handleClick = useEvent((event: ReactMouseEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return
- if (props.disabled) return
+ if (disabled) return
if (isWithinPanel) {
dispatch({ type: ActionTypes.ToggleDisclosure })
@@ -348,21 +352,20 @@ function ButtonFn(
}
})
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: props.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: props.disabled ?? false })
-
- let slot = useMemo(
- () =>
- ({
- open: state.disclosureState === DisclosureStates.Open,
- hover,
- active,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies ButtonRenderPropArg,
- [state, hover, active, focus, props.autoFocus]
- )
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
+
+ let slot = useMemo(() => {
+ return {
+ open: state.disclosureState === DisclosureStates.Open,
+ hover,
+ active,
+ disabled,
+ focus,
+ autofocus: autoFocus,
+ } satisfies ButtonRenderPropArg
+ }, [state, hover, active, focus, disabled, autoFocus])
let type = useResolveButtonType(props, internalButtonRef)
let ourProps = isWithinPanel
@@ -370,6 +373,8 @@ function ButtonFn(
{
ref: buttonRef,
type,
+ disabled: disabled || undefined,
+ autoFocus,
onKeyDown: handleKeyDown,
onClick: handleClick,
},
@@ -384,6 +389,8 @@ function ButtonFn(
type,
'aria-expanded': state.disclosureState === DisclosureStates.Open,
'aria-controls': state.linkedPanel ? state.panelId : undefined,
+ disabled: disabled || undefined,
+ autoFocus,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onClick: handleClick,
@@ -451,14 +458,12 @@ function PanelFn(
return state.disclosureState === DisclosureStates.Open
})()
- let slot = useMemo(
- () =>
- ({
- open: state.disclosureState === DisclosureStates.Open,
- close,
- }) satisfies PanelRenderPropArg,
- [state, close]
- )
+ let slot = useMemo(() => {
+ return {
+ open: state.disclosureState === DisclosureStates.Open,
+ close,
+ } satisfies PanelRenderPropArg
+ }, [state, close])
let ourProps = {
ref: panelRef,
diff --git a/packages/@headlessui-react/src/components/field/field.tsx b/packages/@headlessui-react/src/components/field/field.tsx
index d770c162dd..5225433fd9 100644
--- a/packages/@headlessui-react/src/components/field/field.tsx
+++ b/packages/@headlessui-react/src/components/field/field.tsx
@@ -40,7 +40,7 @@ function FieldFn(
let ourProps = {
ref,
- disabled,
+ disabled: disabled || undefined,
'aria-disabled': disabled || undefined,
}
diff --git a/packages/@headlessui-react/src/components/input/input.tsx b/packages/@headlessui-react/src/components/input/input.tsx
index 27b0d68063..2eac0d9b7c 100644
--- a/packages/@headlessui-react/src/components/input/input.tsx
+++ b/packages/@headlessui-react/src/components/input/input.tsx
@@ -49,6 +49,7 @@ function InputFn(
let {
id = providedId || `headlessui-input-${internalId}`,
disabled = providedDisabled || false,
+ autoFocus = false,
invalid = false,
...theirProps
} = props
@@ -56,10 +57,8 @@ function InputFn(
let labelledBy = useLabelledBy()
let describedBy = useDescribedBy()
- let { isFocused: focus, focusProps } = useFocusRing({
- autoFocus: props.autoFocus ?? false,
- })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
+ let { isFocused: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let ourProps = mergeProps(
{
@@ -69,22 +68,15 @@ function InputFn(
'aria-describedby': describedBy,
'aria-invalid': invalid ? '' : undefined,
disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps
)
- let slot = useMemo(
- () =>
- ({
- disabled,
- invalid,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies InputRenderPropArg,
- [disabled, invalid, hover, focus, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return { disabled, invalid, hover, focus, autofocus: autoFocus } satisfies InputRenderPropArg
+ }, [disabled, invalid, hover, focus, autoFocus])
return render({
ourProps,
diff --git a/packages/@headlessui-react/src/components/listbox/listbox.tsx b/packages/@headlessui-react/src/components/listbox/listbox.tsx
index 129dd7408f..d9d5ed6c8e 100644
--- a/packages/@headlessui-react/src/components/listbox/listbox.tsx
+++ b/packages/@headlessui-react/src/components/listbox/listbox.tsx
@@ -554,16 +554,14 @@ function ListboxFn<
data.listboxState === ListboxStates.Open
)
- let slot = useMemo(
- () =>
- ({
- open: data.listboxState === ListboxStates.Open,
- disabled,
- invalid,
- value,
- }) satisfies ListboxRenderPropArg,
- [data, disabled, value, invalid]
- )
+ let slot = useMemo(() => {
+ return {
+ open: data.listboxState === ListboxStates.Open,
+ disabled,
+ invalid,
+ value,
+ } satisfies ListboxRenderPropArg
+ }, [data, disabled, value, invalid])
let selectOption = useEvent((id: string) => {
let option = data.options.find((item) => item.id === id)
@@ -718,6 +716,7 @@ export type ListboxButtonProps
@@ -725,11 +724,17 @@ function ButtonFn(
props: ListboxButtonProps,
ref: Ref
) {
- let internalId = useId()
- let providedId = useProvidedId()
- let { id = providedId || `headlessui-listbox-button-${internalId}`, ...theirProps } = props
let data = useData('Listbox.Button')
let actions = useActions('Listbox.Button')
+
+ let internalId = useId()
+ let providedId = useProvidedId()
+ let {
+ id = providedId || `headlessui-listbox-button-${internalId}`,
+ disabled = data.disabled || false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let buttonRef = useSyncRefs(data.buttonRef, ref, useFloatingReference())
let getFloatingReferenceProps = useFloatingReferenceProps()
@@ -790,33 +795,22 @@ function ButtonFn(
let labelledBy = useLabelledBy([id])
let describedBy = useDescribedBy()
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: data.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: data.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
- let slot = useMemo(
- () =>
- ({
- open: data.listboxState === ListboxStates.Open,
- active: active || data.listboxState === ListboxStates.Open,
- disabled: data.disabled,
- invalid: data.invalid,
- value: data.value,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies ButtonRenderPropArg,
- [
- data.listboxState,
- data.disabled,
- data.value,
+ let slot = useMemo(() => {
+ return {
+ open: data.listboxState === ListboxStates.Open,
+ active: active || data.listboxState === ListboxStates.Open,
+ disabled,
+ invalid: data.invalid,
+ value: data.value,
hover,
focus,
- active,
- data.invalid,
- props.autoFocus,
- ]
- )
+ autofocus: autoFocus,
+ } satisfies ButtonRenderPropArg
+ }, [data.listboxState, data.value, disabled, hover, focus, active, data.invalid, autoFocus])
let ourProps = mergeProps(
getFloatingReferenceProps(),
@@ -829,7 +823,8 @@ function ButtonFn(
'aria-expanded': data.listboxState === ListboxStates.Open,
'aria-labelledby': labelledBy,
'aria-describedby': describedBy,
- disabled: data.disabled,
+ disabled: disabled || undefined,
+ autoFocus,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onKeyPress: handleKeyPress,
@@ -1225,17 +1220,15 @@ function OptionFn<
actions.goToOption(Focus.Nothing)
})
- let slot = useMemo(
- () =>
- ({
- active,
- focus: active,
- selected,
- disabled,
- selectedOption: selected && usedInSelectedOption,
- }) satisfies OptionRenderPropArg,
- [active, selected, disabled, usedInSelectedOption]
- )
+ let slot = useMemo(() => {
+ return {
+ active,
+ focus: active,
+ selected,
+ disabled,
+ selectedOption: selected && usedInSelectedOption,
+ } satisfies OptionRenderPropArg
+ }, [active, selected, disabled, usedInSelectedOption])
let ourProps = !usedInSelectedOption
? {
id,
diff --git a/packages/@headlessui-react/src/components/menu/menu.test.tsx b/packages/@headlessui-react/src/components/menu/menu.test.tsx
index 2a26ef11aa..3646ee4500 100644
--- a/packages/@headlessui-react/src/components/menu/menu.test.tsx
+++ b/packages/@headlessui-react/src/components/menu/menu.test.tsx
@@ -179,6 +179,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: false,
active: false,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -194,6 +195,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: true,
active: true,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -225,6 +227,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: false,
active: false,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -240,6 +243,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: true,
active: true,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -248,6 +252,7 @@ describe('Rendering', () => {
assertMenu({ state: MenuState.Visible })
})
)
+
describe('`type` attribute', () => {
it('should set the `type` to "button" by default', async () => {
render(
diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx
index 359e67430d..9cf528ec38 100644
--- a/packages/@headlessui-react/src/components/menu/menu.tsx
+++ b/packages/@headlessui-react/src/components/menu/menu.tsx
@@ -436,6 +436,7 @@ type ButtonRenderPropArg = {
active: boolean
hover: boolean
focus: boolean
+ disabled: boolean
autofocus: boolean
}
type ButtonPropsWeControl = 'aria-controls' | 'aria-expanded' | 'aria-haspopup'
@@ -455,7 +456,12 @@ function ButtonFn(
ref: Ref
) {
let internalId = useId()
- let { id = `headlessui-menu-button-${internalId}`, ...theirProps } = props
+ let {
+ id = `headlessui-menu-button-${internalId}`,
+ disabled = false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let [state, dispatch] = useMenuContext('Menu.Button')
let getFloatingReferenceProps = useFloatingReferenceProps()
let buttonRef = useSyncRefs(state.buttonRef, ref, useFloatingReference())
@@ -497,7 +503,7 @@ function ButtonFn(
let handleClick = useEvent((event: ReactMouseEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
- if (props.disabled) return
+ if (disabled) return
if (state.menuState === MenuStates.Open) {
dispatch({ type: ActionTypes.CloseMenu })
d.nextFrame(() => state.buttonRef.current?.focus({ preventScroll: true }))
@@ -507,21 +513,20 @@ function ButtonFn(
}
})
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: props.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: props.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
- let slot = useMemo(
- () =>
- ({
- open: state.menuState === MenuStates.Open,
- active: active || state.menuState === MenuStates.Open,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies ButtonRenderPropArg,
- [state, hover, focus, active, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ open: state.menuState === MenuStates.Open,
+ active: active || state.menuState === MenuStates.Open,
+ disabled,
+ hover,
+ focus,
+ autofocus: autoFocus,
+ } satisfies ButtonRenderPropArg
+ }, [state, hover, focus, active, disabled, autoFocus])
let ourProps = mergeProps(
getFloatingReferenceProps(),
@@ -532,6 +537,8 @@ function ButtonFn(
'aria-haspopup': 'menu',
'aria-controls': state.itemsRef.current?.id,
'aria-expanded': state.menuState === MenuStates.Open,
+ disabled: disabled || undefined,
+ autoFocus,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onClick: handleClick,
diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx
index cdcc77525c..405778a173 100644
--- a/packages/@headlessui-react/src/components/popover/popover.test.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx
@@ -387,6 +387,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: false,
active: false,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -402,6 +403,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: true,
active: true,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -429,6 +431,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: false,
active: false,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
@@ -444,6 +447,7 @@ describe('Rendering', () => {
textContent: JSON.stringify({
open: true,
active: true,
+ disabled: false,
hover: false,
focus: false,
autofocus: false,
diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx
index 6a26b2168a..9ff7687306 100644
--- a/packages/@headlessui-react/src/components/popover/popover.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.tsx
@@ -440,6 +440,7 @@ type ButtonRenderPropArg = {
active: boolean
hover: boolean
focus: boolean
+ disabled: boolean
autofocus: boolean
}
type ButtonPropsWeControl = 'aria-controls' | 'aria-expanded'
@@ -459,7 +460,12 @@ function ButtonFn(
ref: Ref
) {
let internalId = useId()
- let { id = `headlessui-popover-button-${internalId}`, ...theirProps } = props
+ let {
+ id = `headlessui-popover-button-${internalId}`,
+ disabled = false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let [state, dispatch] = usePopoverContext('Popover.Button')
let { isPortalled } = usePopoverAPIContext('Popover.Button')
let internalButtonRef = useRef(null)
@@ -584,7 +590,7 @@ function ButtonFn(
let handleClick = useEvent((event: ReactMouseEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return
- if (props.disabled) return
+ if (disabled) return
if (isWithinPanel) {
dispatch({ type: ActionTypes.ClosePopover })
state.button?.focus() // Re-focus the original opening Button
@@ -602,22 +608,21 @@ function ButtonFn(
event.stopPropagation()
})
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: props.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: props.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
let visible = state.popoverState === PopoverStates.Open
- let slot = useMemo(
- () =>
- ({
- open: visible,
- active: active || visible,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies ButtonRenderPropArg,
- [visible, hover, focus, active, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ open: visible,
+ active: active || visible,
+ disabled,
+ hover,
+ focus,
+ autofocus: autoFocus,
+ } satisfies ButtonRenderPropArg
+ }, [visible, hover, focus, active, disabled, autoFocus])
let type = useResolveButtonType(props, internalButtonRef)
let ourProps = isWithinPanel
@@ -627,6 +632,8 @@ function ButtonFn(
type,
onKeyDown: handleKeyDown,
onClick: handleClick,
+ disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps,
@@ -639,6 +646,8 @@ function ButtonFn(
type,
'aria-expanded': state.popoverState === PopoverStates.Open,
'aria-controls': state.panel ? state.panelId : undefined,
+ disabled: disabled || undefined,
+ autoFocus,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onClick: handleClick,
diff --git a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
index 2fabaa2dc4..c3c46ce3ea 100644
--- a/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
+++ b/packages/@headlessui-react/src/components/radio-group/radio-group.tsx
@@ -371,13 +371,18 @@ function OptionFn<
// But today is not that day..
TType = Parameters[0]['value'],
>(props: RadioOptionProps, ref: Ref) {
+ let data = useData('RadioGroup.Option')
+ let actions = useActions('RadioGroup.Option')
+
let internalId = useId()
let {
id = `headlessui-radiogroup-option-${internalId}`,
value,
- disabled = false,
+ disabled = data.disabled || false,
+ autoFocus = false,
...theirProps
} = props
+
let internalOptionRef = useRef(null)
let optionRef = useSyncRefs(internalOptionRef, ref)
@@ -386,9 +391,6 @@ function OptionFn<
let propsRef = useLatestValue({ value, disabled })
- let data = useData('RadioGroup.Option')
- let actions = useActions('RadioGroup.Option')
-
useIsoMorphicEffect(
() => actions.registerOption({ id, element: internalOptionRef, propsRef }),
[id, actions, internalOptionRef, propsRef]
@@ -401,10 +403,9 @@ function OptionFn<
})
let isFirstOption = data.firstOption?.id === id
- let isDisabled = data.disabled || disabled
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: isDisabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let checked = data.compare(data.value as TType, value)
let ourProps = mergeProps(
@@ -415,31 +416,30 @@ function OptionFn<
'aria-checked': checked ? 'true' : 'false',
'aria-labelledby': labelledby,
'aria-describedby': describedby,
- 'aria-disabled': isDisabled ? true : undefined,
+ 'aria-disabled': disabled ? true : undefined,
tabIndex: (() => {
- if (isDisabled) return -1
+ if (disabled) return -1
if (checked) return 0
if (!data.containsCheckedOption && isFirstOption) return 0
return -1
})(),
- onClick: isDisabled ? undefined : handleClick,
+ onClick: disabled ? undefined : handleClick,
+ autoFocus,
},
focusProps,
hoverProps
)
- let slot = useMemo(
- () =>
- ({
- checked,
- disabled: isDisabled,
- active: focus,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies OptionRenderPropArg,
- [checked, isDisabled, hover, focus, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ checked,
+ disabled,
+ active: focus,
+ hover,
+ focus,
+ autofocus: autoFocus,
+ } satisfies OptionRenderPropArg
+ }, [checked, disabled, hover, focus, autoFocus])
return (
@@ -500,6 +500,7 @@ function RadioFn<
id = providedId || `headlessui-radio-${internalId}`,
value,
disabled = data.disabled || providedDisabled || false,
+ autoFocus = false,
...theirProps
} = props
let internalRadioRef = useRef(null)
@@ -522,8 +523,8 @@ function RadioFn<
internalRadioRef.current?.focus()
})
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let isFirstOption = data.firstOption?.id === id
@@ -543,22 +544,15 @@ function RadioFn<
if (!data.containsCheckedOption && isFirstOption) return 0
return -1
})(),
+ autoFocus,
onClick: disabled ? undefined : handleClick,
},
focusProps,
hoverProps
)
- let slot = useMemo(
- () =>
- ({
- checked,
- disabled,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies RadioRenderPropArg,
- [checked, disabled, hover, focus, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return { checked, disabled, hover, focus, autofocus: autoFocus } satisfies RadioRenderPropArg
+ }, [checked, disabled, hover, focus, autoFocus])
return render({
ourProps,
diff --git a/packages/@headlessui-react/src/components/select/select.tsx b/packages/@headlessui-react/src/components/select/select.tsx
index 3b83496c20..c3823b3f11 100644
--- a/packages/@headlessui-react/src/components/select/select.tsx
+++ b/packages/@headlessui-react/src/components/select/select.tsx
@@ -52,15 +52,16 @@ function SelectFn(
id = providedId || `headlessui-select-${internalId}`,
disabled = providedDisabled || false,
invalid = false,
+ autoFocus = false,
...theirProps
} = props
let labelledBy = useLabelledBy()
let describedBy = useDescribedBy()
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
let ourProps = mergeProps(
{
@@ -70,24 +71,23 @@ function SelectFn(
'aria-describedby': describedBy,
'aria-invalid': invalid ? '' : undefined,
disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps,
pressProps
)
- let slot = useMemo(
- () =>
- ({
- disabled,
- invalid,
- hover,
- focus,
- active,
- autofocus: props.autoFocus ?? false,
- }) satisfies SelectRenderPropArg,
- [disabled, invalid, hover, focus, active, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return {
+ disabled,
+ invalid,
+ hover,
+ focus,
+ active,
+ autofocus: autoFocus,
+ } satisfies SelectRenderPropArg
+ }, [disabled, invalid, hover, focus, active, autoFocus])
return render({
ourProps,
diff --git a/packages/@headlessui-react/src/components/switch/switch.tsx b/packages/@headlessui-react/src/components/switch/switch.tsx
index eedf7a9f7b..78bf9a31e9 100644
--- a/packages/@headlessui-react/src/components/switch/switch.tsx
+++ b/packages/@headlessui-react/src/components/switch/switch.tsx
@@ -151,6 +151,7 @@ function SwitchFn(
name,
value,
form,
+ autoFocus = false,
...theirProps
} = props
let groupContext = useContext(GroupContext)
@@ -192,23 +193,22 @@ function SwitchFn(
let labelledBy = useLabelledBy()
let describedBy = useDescribedBy()
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: disabled ?? false })
- let slot = useMemo(
- () =>
- ({
- checked,
- disabled,
- hover,
- focus,
- active,
- autofocus: props.autoFocus ?? false,
- changing,
- }) satisfies SwitchRenderPropArg,
- [checked, hover, focus, active, disabled, changing, props.autoFocus]
- )
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
+
+ let slot = useMemo(() => {
+ return {
+ checked,
+ disabled,
+ hover,
+ focus,
+ active,
+ autofocus: autoFocus,
+ changing,
+ } satisfies SwitchRenderPropArg
+ }, [checked, hover, focus, active, disabled, changing, autoFocus])
let ourProps = mergeProps(
{
@@ -220,7 +220,8 @@ function SwitchFn(
'aria-checked': checked,
'aria-labelledby': labelledBy,
'aria-describedby': describedBy,
- disabled,
+ disabled: disabled || undefined,
+ autoFocus,
onClick: handleClick,
onKeyUp: handleKeyUp,
onKeyPress: handleKeyPress,
diff --git a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
index 659140eb1c..e2da0394f5 100644
--- a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
+++ b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
@@ -691,25 +691,25 @@ describe('Rendering', () => {
)
expect(document.querySelector('[data-panel="0"]')).toHaveTextContent(
- JSON.stringify({ selected: true })
+ JSON.stringify({ selected: true, focus: false })
)
expect(document.querySelector('[data-panel="1"]')).toHaveTextContent(
- JSON.stringify({ selected: false })
+ JSON.stringify({ selected: false, focus: false })
)
expect(document.querySelector('[data-panel="2"]')).toHaveTextContent(
- JSON.stringify({ selected: false })
+ JSON.stringify({ selected: false, focus: false })
)
await click(getByText('Tab 2'))
expect(document.querySelector('[data-panel="0"]')).toHaveTextContent(
- JSON.stringify({ selected: false })
+ JSON.stringify({ selected: false, focus: false })
)
expect(document.querySelector('[data-panel="1"]')).toHaveTextContent(
- JSON.stringify({ selected: true })
+ JSON.stringify({ selected: true, focus: false })
)
expect(document.querySelector('[data-panel="2"]')).toHaveTextContent(
- JSON.stringify({ selected: false })
+ JSON.stringify({ selected: false, focus: false })
)
})
)
diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx
index f259050706..e98e813c75 100644
--- a/packages/@headlessui-react/src/components/tabs/tabs.tsx
+++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx
@@ -421,7 +421,12 @@ function TabFn(
ref: Ref
) {
let internalId = useId()
- let { id = `headlessui-tabs-tab-${internalId}`, ...theirProps } = props
+ let {
+ id = `headlessui-tabs-tab-${internalId}`,
+ disabled = false,
+ autoFocus = false,
+ ...theirProps
+ } = props
let { orientation, activation, selectedIndex, tabs, panels } = useData('Tab')
let actions = useActions('Tab')
@@ -515,22 +520,20 @@ function TabFn(
event.preventDefault()
})
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: props.disabled ?? false })
- let { pressed: active, pressProps } = useActivePress({ disabled: props.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
+ let { pressed: active, pressProps } = useActivePress({ disabled })
- let slot = useMemo(
- () =>
- ({
- selected,
- hover,
- active,
- focus,
- autofocus: props.autoFocus ?? false,
- disabled: props.disabled ?? false,
- }) satisfies TabRenderPropArg,
- [selected, hover, focus, active, props.autoFocus, props.disabled]
- )
+ let slot = useMemo(() => {
+ return {
+ selected,
+ hover,
+ active,
+ focus,
+ autofocus: autoFocus,
+ disabled,
+ } satisfies TabRenderPropArg
+ }, [selected, hover, focus, active, autoFocus, disabled])
let ourProps = mergeProps(
{
@@ -544,6 +547,8 @@ function TabFn(
'aria-controls': panels[myIndex]?.current?.id,
'aria-selected': selected,
tabIndex: selected ? 0 : -1,
+ disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps,
@@ -578,7 +583,7 @@ function PanelsFn(
let { selectedIndex } = useData('Tab.Panels')
let panelsRef = useSyncRefs(ref)
- let slot = useMemo(() => ({ selectedIndex }), [selectedIndex])
+ let slot = useMemo(() => ({ selectedIndex }) satisfies PanelsRenderPropArg, [selectedIndex])
let theirProps = props
let ourProps = { ref: panelsRef }
@@ -597,6 +602,7 @@ function PanelsFn(
let DEFAULT_PANEL_TAG = 'div' as const
type PanelRenderPropArg = {
selected: boolean
+ focus: boolean
}
type PanelPropsWeControl = 'role' | 'aria-labelledby'
let PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static
@@ -629,15 +635,19 @@ function PanelFn(
let selected = myIndex === selectedIndex
- let slot = useMemo(() => ({ selected }), [selected])
+ let { isFocusVisible: focus, focusProps } = useFocusRing()
+ let slot = useMemo(() => ({ selected, focus }) satisfies PanelRenderPropArg, [selected, focus])
- let ourProps = {
- ref: panelRef,
- id,
- role: 'tabpanel',
- 'aria-labelledby': tabs[myIndex]?.current?.id,
- tabIndex: selected ? tabIndex : -1,
- }
+ let ourProps = mergeProps(
+ {
+ ref: panelRef,
+ id,
+ role: 'tabpanel',
+ 'aria-labelledby': tabs[myIndex]?.current?.id,
+ tabIndex: selected ? tabIndex : -1,
+ },
+ focusProps
+ )
if (!selected && (theirProps.unmount ?? true) && !(theirProps.static ?? false)) {
return
diff --git a/packages/@headlessui-react/src/components/textarea/textarea.tsx b/packages/@headlessui-react/src/components/textarea/textarea.tsx
index 9091f8d753..f1fcf9d701 100644
--- a/packages/@headlessui-react/src/components/textarea/textarea.tsx
+++ b/packages/@headlessui-react/src/components/textarea/textarea.tsx
@@ -49,6 +49,7 @@ function TextareaFn(
let {
id = providedId || `headlessui-textarea-${internalId}`,
disabled = providedDisabled || false,
+ autoFocus = false,
invalid = false,
...theirProps
} = props
@@ -56,8 +57,8 @@ function TextareaFn(
let labelledBy = useLabelledBy()
let describedBy = useDescribedBy()
- let { isFocused: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
+ let { isFocused: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let ourProps = mergeProps(
{
@@ -67,22 +68,15 @@ function TextareaFn(
'aria-describedby': describedBy,
'aria-invalid': invalid ? '' : undefined,
disabled: disabled || undefined,
+ autoFocus,
},
focusProps,
hoverProps
)
- let slot = useMemo(
- () =>
- ({
- disabled,
- invalid,
- hover,
- focus,
- autofocus: props.autoFocus ?? false,
- }) satisfies TextareaRenderPropArg,
- [disabled, invalid, hover, focus, props.autoFocus]
- )
+ let slot = useMemo(() => {
+ return { disabled, invalid, hover, focus, autofocus: autoFocus } satisfies TextareaRenderPropArg
+ }, [disabled, invalid, hover, focus, autoFocus])
return render({
ourProps,
diff --git a/packages/@headlessui-react/src/components/tooltip/tooltip.tsx b/packages/@headlessui-react/src/components/tooltip/tooltip.tsx
index 577cf3cce1..99f57f75ae 100644
--- a/packages/@headlessui-react/src/components/tooltip/tooltip.tsx
+++ b/packages/@headlessui-react/src/components/tooltip/tooltip.tsx
@@ -326,15 +326,15 @@ function TriggerFn(
props: TooltipTriggerProps,
ref: Ref
) {
- let { ...theirProps } = props
+ let { disabled = false, autoFocus = false, ...theirProps } = props
let data = useData('TooltipTrigger')
let actions = useActions('TooltipTrigger')
let describedBy = useDescribedBy()
let internalButtonRef = useRef(null)
let triggerRef = useSyncRefs(internalButtonRef, ref, useFloatingReference())
- let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
- let { isHovered: hover, hoverProps } = useHover({ isDisabled: props.disabled ?? false })
+ let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus })
+ let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let handleKeyDown = useEvent((event: ReactKeyboardEvent) => {
switch (event.key) {
@@ -375,8 +375,8 @@ function TriggerFn(
})
let slot = useMemo(
- () => ({ hover, focus, autofocus: props.autoFocus ?? false }) satisfies TriggerRenderPropArg,
- [hover, focus, props.autoFocus]
+ () => ({ hover, focus, autofocus: autoFocus }) satisfies TriggerRenderPropArg,
+ [hover, focus, autoFocus]
)
let ourProps = mergeProps(
{