Add invalid prop to Combobox component (#3677)
This PR adds the `invalid` prop to the `Combobox` component. This will also expose the `invalid` value as a render prop to the `Combobox.Input` and `Combobox.Button` components. It will also expose the `data-invalid` attribute on these components when the `invalid` prop is set to `true`. ```tsx <Combobox invalid> <Combobox.Input /> <Combobox.Button /> </Combobox> ``` Without `invalid` prop: <img width="916" alt="image" src="https://github.com/user-attachments/assets/2c199691-7b29-450f-89a5-4b84e6704c6a" /> With invalid prop: <img width="913" alt="image" src="https://github.com/user-attachments/assets/4bdde518-39b3-4998-b353-604a818a3c99" /> Notice the `data-invalid` prop on the `<input>` and the `<button>`.
This commit is contained in:
@@ -15,8 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
|
||||
- Use correct `ownerDocument` when using internal `Portal` component ([#3594](https://github.com/tailwindlabs/headlessui/pull/3594))
|
||||
- Bump `@tanstack/react-virtual` to be fix warnings in React 19 projects ([#3588](https://github.com/tailwindlabs/headlessui/pull/3588))
|
||||
- Bump `@tanstack/react-virtual` to fix warnings in React 19 projects ([#3588](https://github.com/tailwindlabs/headlessui/pull/3588))
|
||||
- Fix `aria-invalid` attributes to have a valid `'true'` value ([#3639](https://github.com/tailwindlabs/headlessui/pull/3639))
|
||||
- Add missing `invalid` prop to `Combobox` component ([#3677](https://github.com/tailwindlabs/headlessui/pull/3677))
|
||||
|
||||
## [2.2.0] - 2024-10-25
|
||||
|
||||
|
||||
@@ -1045,6 +1045,7 @@ describe('Rendering', () => {
|
||||
open: false,
|
||||
active: false,
|
||||
disabled: false,
|
||||
invalid: false,
|
||||
value: 'test',
|
||||
hover: false,
|
||||
focus: false,
|
||||
@@ -1061,6 +1062,7 @@ describe('Rendering', () => {
|
||||
open: true,
|
||||
active: true,
|
||||
disabled: false,
|
||||
invalid: false,
|
||||
value: 'test',
|
||||
hover: false,
|
||||
focus: false,
|
||||
@@ -1094,6 +1096,7 @@ describe('Rendering', () => {
|
||||
open: false,
|
||||
active: false,
|
||||
disabled: false,
|
||||
invalid: false,
|
||||
value: 'test',
|
||||
hover: false,
|
||||
focus: false,
|
||||
@@ -1110,6 +1113,7 @@ describe('Rendering', () => {
|
||||
open: true,
|
||||
active: true,
|
||||
disabled: false,
|
||||
invalid: false,
|
||||
value: 'test',
|
||||
hover: false,
|
||||
focus: false,
|
||||
|
||||
@@ -577,6 +577,7 @@ let ComboboxDataContext = createContext<
|
||||
value: unknown
|
||||
defaultValue: unknown
|
||||
disabled: boolean
|
||||
invalid: boolean
|
||||
mode: ValueMode
|
||||
activeOptionIndex: number | null
|
||||
immediate: boolean
|
||||
@@ -619,6 +620,7 @@ let DEFAULT_COMBOBOX_TAG = Fragment
|
||||
type ComboboxRenderPropArg<TValue, TActive = TValue> = {
|
||||
open: boolean
|
||||
disabled: boolean
|
||||
invalid: boolean
|
||||
activeIndex: number | null
|
||||
activeOption: TActive | null
|
||||
value: TValue
|
||||
@@ -648,6 +650,7 @@ export type ComboboxProps<
|
||||
|
||||
multiple?: TMultiple
|
||||
disabled?: boolean
|
||||
invalid?: boolean
|
||||
form?: string
|
||||
name?: string
|
||||
immediate?: boolean
|
||||
@@ -676,6 +679,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
|
||||
form,
|
||||
name,
|
||||
by,
|
||||
invalid = false,
|
||||
disabled = providedDisabled || false,
|
||||
onClose,
|
||||
__demoMode = false,
|
||||
@@ -751,6 +755,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
|
||||
value,
|
||||
defaultValue,
|
||||
disabled,
|
||||
invalid,
|
||||
mode: multiple ? ValueMode.Multi : ValueMode.Single,
|
||||
virtual: virtual ? state.virtual : null,
|
||||
get activeOptionIndex() {
|
||||
@@ -785,7 +790,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
|
||||
isSelected,
|
||||
isActive,
|
||||
}),
|
||||
[value, defaultValue, disabled, multiple, __demoMode, state, virtual]
|
||||
[value, defaultValue, disabled, invalid, multiple, __demoMode, state, virtual]
|
||||
)
|
||||
|
||||
useIsoMorphicEffect(() => {
|
||||
@@ -813,6 +818,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
|
||||
return {
|
||||
open: data.comboboxState === ComboboxState.Open,
|
||||
disabled,
|
||||
invalid,
|
||||
activeIndex: data.activeOptionIndex,
|
||||
activeOption:
|
||||
data.activeOptionIndex === null
|
||||
@@ -822,7 +828,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
|
||||
: (data.options[data.activeOptionIndex]?.dataRef.current.value as TValue) ?? null,
|
||||
value,
|
||||
} satisfies ComboboxRenderPropArg<unknown>
|
||||
}, [data, disabled, value])
|
||||
}, [data, disabled, value, invalid])
|
||||
|
||||
let selectActiveOption = useEvent(() => {
|
||||
if (data.activeOptionIndex === null) return
|
||||
@@ -999,6 +1005,7 @@ let DEFAULT_INPUT_TAG = 'input' as const
|
||||
type InputRenderPropArg = {
|
||||
open: boolean
|
||||
disabled: boolean
|
||||
invalid: boolean
|
||||
hover: boolean
|
||||
focus: boolean
|
||||
autofocus: boolean
|
||||
@@ -1398,11 +1405,12 @@ function InputFn<
|
||||
return {
|
||||
open: data.comboboxState === ComboboxState.Open,
|
||||
disabled,
|
||||
invalid: data.invalid,
|
||||
hover,
|
||||
focus,
|
||||
autofocus: autoFocus,
|
||||
} satisfies InputRenderPropArg
|
||||
}, [data, hover, focus, autoFocus, disabled])
|
||||
}, [data, hover, focus, autoFocus, disabled, data.invalid])
|
||||
|
||||
let ourProps = mergeProps(
|
||||
{
|
||||
@@ -1463,6 +1471,7 @@ type ButtonRenderPropArg = {
|
||||
open: boolean
|
||||
active: boolean
|
||||
disabled: boolean
|
||||
invalid: boolean
|
||||
value: any
|
||||
focus: boolean
|
||||
hover: boolean
|
||||
@@ -1587,6 +1596,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
|
||||
open: data.comboboxState === ComboboxState.Open,
|
||||
active: active || data.comboboxState === ComboboxState.Open,
|
||||
disabled,
|
||||
invalid: data.invalid,
|
||||
value: data.value,
|
||||
hover,
|
||||
focus,
|
||||
|
||||
Reference in New Issue
Block a user