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

Allow passing in your own id prop #2060

Merged
merged 4 commits into from
Dec 2, 2022
Merged
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
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improve syncing of the `Combobox.Input` value ([#2042](https://github.com/tailwindlabs/headlessui/pull/2042))
- Fix crash when using `multiple` mode without `value` prop (uncontrolled) for `Listbox` and `Combobox` components ([#2058](https://github.com/tailwindlabs/headlessui/pull/2058))
- Apply `enter` and `enterFrom` classes in SSR for `Transition` component ([#2059](https://github.com/tailwindlabs/headlessui/pull/2059))
- Allow passing in your own `id` prop ([#2060](https://github.com/tailwindlabs/headlessui/pull/2060))

## [1.7.4] - 2022-11-03

Expand Down
40 changes: 23 additions & 17 deletions packages/@headlessui-react/src/components/combobox/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@ interface InputRenderPropArg {
disabled: boolean
}
type InputPropsWeControl =
| 'id'
| 'role'
| 'aria-labelledby'
| 'aria-expanded'
Expand All @@ -678,15 +677,21 @@ let Input = forwardRefWithAs(function Input<
},
ref: Ref<HTMLInputElement>
) {
let { value, onChange, displayValue, type = 'text', ...theirProps } = props
let internalId = useId()
let {
id = `headlessui-combobox-input-${internalId}`,
onChange,
displayValue,
type = 'text',
...theirProps
} = props
let data = useData('Combobox.Input')
let actions = useActions('Combobox.Input')

let inputRef = useSyncRefs(data.inputRef, ref)

let isTyping = useRef(false)

let id = `headlessui-combobox-input-${useId()}`
let d = useDisposables()

// When a `displayValue` prop is given, we should use it to transform the current selected
Expand Down Expand Up @@ -931,7 +936,6 @@ interface ButtonRenderPropArg {
value: any
}
type ButtonPropsWeControl =
| 'id'
| 'type'
| 'tabIndex'
| 'aria-haspopup'
Expand All @@ -949,8 +953,8 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
let data = useData('Combobox.Button')
let actions = useActions('Combobox.Button')
let buttonRef = useSyncRefs(data.buttonRef, ref)

let id = `headlessui-combobox-button-${useId()}`
let internalId = useId()
let { id = `headlessui-combobox-button-${internalId}`, ...theirProps } = props
let d = useDisposables()

let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLUListElement>) => {
Expand Down Expand Up @@ -1017,7 +1021,6 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
}),
[data]
)
let theirProps = props
let ourProps = {
ref: buttonRef,
id,
Expand Down Expand Up @@ -1048,14 +1051,15 @@ interface LabelRenderPropArg {
open: boolean
disabled: boolean
}
type LabelPropsWeControl = 'id' | 'ref' | 'onClick'
type LabelPropsWeControl = 'ref' | 'onClick'

let Label = forwardRefWithAs(function Label<TTag extends ElementType = typeof DEFAULT_LABEL_TAG>(
props: Props<TTag, LabelRenderPropArg, LabelPropsWeControl>,
ref: Ref<HTMLLabelElement>
) {
let internalId = useId()
let { id = `headlessui-combobox-label-${internalId}`, ...theirProps } = props
let data = useData('Combobox.Label')
let id = `headlessui-combobox-label-${useId()}`
let actions = useActions('Combobox.Label')
let labelRef = useSyncRefs(data.labelRef, ref)

Expand All @@ -1068,7 +1072,6 @@ let Label = forwardRefWithAs(function Label<TTag extends ElementType = typeof DE
[data]
)

let theirProps = props
let ourProps = { ref: labelRef, id, onClick: handleClick }

return render({
Expand All @@ -1090,7 +1093,6 @@ type OptionsPropsWeControl =
| 'aria-activedescendant'
| 'aria-labelledby'
| 'hold'
| 'id'
| 'onKeyDown'
| 'role'
| 'tabIndex'
Expand All @@ -1106,13 +1108,12 @@ let Options = forwardRefWithAs(function Options<
},
ref: Ref<HTMLUListElement>
) {
let { hold = false, ...theirProps } = props
let internalId = useId()
let { id = `headlessui-combobox-options-${internalId}`, hold = false, ...theirProps } = props
let data = useData('Combobox.Options')

let optionsRef = useSyncRefs(data.optionsRef, ref)

let id = `headlessui-combobox-options-${useId()}`

let usesOpenClosedState = useOpenClosed()
let visible = (() => {
if (usesOpenClosedState !== null) {
Expand Down Expand Up @@ -1179,7 +1180,7 @@ interface OptionRenderPropArg {
selected: boolean
disabled: boolean
}
type ComboboxOptionPropsWeControl = 'id' | 'role' | 'tabIndex' | 'aria-disabled' | 'aria-selected'
type ComboboxOptionPropsWeControl = 'role' | 'tabIndex' | 'aria-disabled' | 'aria-selected'

let Option = forwardRefWithAs(function Option<
TTag extends ElementType = typeof DEFAULT_OPTION_TAG,
Expand All @@ -1193,11 +1194,16 @@ let Option = forwardRefWithAs(function Option<
},
ref: Ref<HTMLLIElement>
) {
let { disabled = false, value, ...theirProps } = props
let internalId = useId()
let {
id = `headlessui-combobox-option-${internalId}`,
disabled = false,
value,
...theirProps
} = props
let data = useData('Combobox.Option')
let actions = useActions('Combobox.Option')

let id = `headlessui-combobox-option-${useId()}`
let active =
data.activeOptionIndex !== null ? data.options[data.activeOptionIndex].id === id : false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ let DEFAULT_DESCRIPTION_TAG = 'p' as const

export let Description = forwardRefWithAs(function Description<
TTag extends ElementType = typeof DEFAULT_DESCRIPTION_TAG
>(props: Props<TTag, {}, 'id'>, ref: Ref<HTMLParagraphElement>) {
>(props: Props<TTag>, ref: Ref<HTMLParagraphElement>) {
let internalId = useId()
let { id = `headlessui-description-${internalId}`, ...theirProps } = props
let context = useDescriptionContext()
let id = `headlessui-description-${useId()}`
let descriptionRef = useSyncRefs(ref)

useIsoMorphicEffect(() => context.register(id), [id, context.register])

let theirProps = props
let ourProps = { ref: descriptionRef, ...context.props, id }

return render({
Expand Down
40 changes: 21 additions & 19 deletions packages/@headlessui-react/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ let DEFAULT_DIALOG_TAG = 'div' as const
interface DialogRenderPropArg {
open: boolean
}
type DialogPropsWeControl = 'id' | 'role' | 'aria-modal' | 'aria-describedby' | 'aria-labelledby'
type DialogPropsWeControl = 'role' | 'aria-modal' | 'aria-describedby' | 'aria-labelledby'

let DialogRenderFeatures = Features.RenderStrategy | Features.Static

Expand All @@ -156,7 +156,15 @@ let DialogRoot = forwardRefWithAs(function Dialog<
},
ref: Ref<HTMLDivElement>
) {
let { open, onClose, initialFocus, __demoMode = false, ...theirProps } = props
let internalId = useId()
let {
id = `headlessui-dialog-${internalId}`,
open,
onClose,
initialFocus,
__demoMode = false,
...theirProps
} = props
let [nestedDialogCount, setNestedDialogCount] = useState(0)

let usesOpenClosedState = useOpenClosed()
Expand Down Expand Up @@ -295,8 +303,6 @@ let DialogRoot = forwardRefWithAs(function Dialog<

let [describedby, DescriptionProvider] = useDescriptions()

let id = `headlessui-dialog-${useId()}`

let contextBag = useMemo<ContextType<typeof DialogContext>>(
() => [{ dialogState, close, setTitleId }, state],
[dialogState, state, close, setTitleId]
Expand Down Expand Up @@ -381,16 +387,16 @@ let DEFAULT_OVERLAY_TAG = 'div' as const
interface OverlayRenderPropArg {
open: boolean
}
type OverlayPropsWeControl = 'id' | 'aria-hidden' | 'onClick'
type OverlayPropsWeControl = 'aria-hidden' | 'onClick'

let Overlay = forwardRefWithAs(function Overlay<
TTag extends ElementType = typeof DEFAULT_OVERLAY_TAG
>(props: Props<TTag, OverlayRenderPropArg, OverlayPropsWeControl>, ref: Ref<HTMLDivElement>) {
let internalId = useId()
let { id = `headlessui-dialog-overlay-${internalId}`, ...theirProps } = props
let [{ dialogState, close }] = useDialogContext('Dialog.Overlay')
let overlayRef = useSyncRefs(ref)

let id = `headlessui-dialog-overlay-${useId()}`

let handleClick = useEvent((event: ReactMouseEvent) => {
if (event.target !== event.currentTarget) return
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
Expand All @@ -404,7 +410,6 @@ let Overlay = forwardRefWithAs(function Overlay<
[dialogState]
)

let theirProps = props
let ourProps = {
ref: overlayRef,
id,
Expand All @@ -427,16 +432,16 @@ let DEFAULT_BACKDROP_TAG = 'div' as const
interface BackdropRenderPropArg {
open: boolean
}
type BackdropPropsWeControl = 'id' | 'aria-hidden' | 'onClick'
type BackdropPropsWeControl = 'aria-hidden' | 'onClick'

let Backdrop = forwardRefWithAs(function Backdrop<
TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG
>(props: Props<TTag, BackdropRenderPropArg, BackdropPropsWeControl>, ref: Ref<HTMLDivElement>) {
let internalId = useId()
let { id = `headlessui-dialog-backdrop-${internalId}`, ...theirProps } = props
let [{ dialogState }, state] = useDialogContext('Dialog.Backdrop')
let backdropRef = useSyncRefs(ref)

let id = `headlessui-dialog-backdrop-${useId()}`

useEffect(() => {
if (state.panelRef.current === null) {
throw new Error(
Expand All @@ -450,7 +455,6 @@ let Backdrop = forwardRefWithAs(function Backdrop<
[dialogState]
)

let theirProps = props
let ourProps = {
ref: backdropRef,
id,
Expand Down Expand Up @@ -483,11 +487,11 @@ let Panel = forwardRefWithAs(function Panel<TTag extends ElementType = typeof DE
props: Props<TTag, PanelRenderPropArg>,
ref: Ref<HTMLDivElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-panel-${internalId}`, ...theirProps } = props
let [{ dialogState }, state] = useDialogContext('Dialog.Panel')
let panelRef = useSyncRefs(ref, state.panelRef)

let id = `headlessui-dialog-panel-${useId()}`

let slot = useMemo<PanelRenderPropArg>(
() => ({ open: dialogState === DialogStates.Open }),
[dialogState]
Expand All @@ -499,7 +503,6 @@ let Panel = forwardRefWithAs(function Panel<TTag extends ElementType = typeof DE
event.stopPropagation()
})

let theirProps = props
let ourProps = {
ref: panelRef,
id,
Expand All @@ -521,15 +524,15 @@ let DEFAULT_TITLE_TAG = 'h2' as const
interface TitleRenderPropArg {
open: boolean
}
type TitlePropsWeControl = 'id'

let Title = forwardRefWithAs(function Title<TTag extends ElementType = typeof DEFAULT_TITLE_TAG>(
props: Props<TTag, TitleRenderPropArg, TitlePropsWeControl>,
props: Props<TTag, TitleRenderPropArg>,
ref: Ref<HTMLHeadingElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-title-${internalId}`, ...theirProps } = props
let [{ dialogState, setTitleId }] = useDialogContext('Dialog.Title')

let id = `headlessui-dialog-title-${useId()}`
let titleRef = useSyncRefs(ref)

useEffect(() => {
Expand All @@ -542,7 +545,6 @@ let Title = forwardRefWithAs(function Title<TTag extends ElementType = typeof DE
[dialogState]
)

let theirProps = props
let ourProps = { ref: titleRef, id }

return render({
Expand Down
Loading