Skip to content

Commit 475db7c

Browse files
committed
Make the empty state interactive
1 parent c2c43c3 commit 475db7c

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

packages/playground-react/pages/combobox/combobox-virtual-with-empty-states.tsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRef, useState } from 'react'
33
import { classNames } from '../../utils/class-names'
44

55
import { Button } from '../../components/button'
6+
import { flushSync } from 'react-dom'
67

78
type Option = {
89
name: string
@@ -67,6 +68,17 @@ export default function Home() {
6768
setQuery('')
6869
}}
6970
as="div"
71+
72+
// Don't do this lol — it's not supported
73+
// It's just so we can tab to the "Add" button for the demo
74+
// The combobox doesn't actually support this behavior
75+
onKeyDownCapture={(event: KeyboardEvent) => {
76+
let addButton = document.querySelector('#add_person')
77+
if (event.key === 'Tab' && addButton && filtered.length === 0) {
78+
event.preventDefault()
79+
setTimeout(() => addButton.focus(), 0)
80+
}
81+
}}
7082
>
7183
<Combobox.Label className="block text-sm font-medium leading-5 text-gray-700">
7284
Person
@@ -100,6 +112,11 @@ export default function Home() {
100112

101113
<div className="absolute mt-1 w-full rounded-md bg-white shadow-lg">
102114
<Combobox.Options
115+
// This is a hack to make keep the options list around when it's empty
116+
// It comes with some caveats:
117+
// like the option callback being called with a null option (which is probably a bug)
118+
static={filtered.length === 0}
119+
103120
ref={optionsRef}
104121
className={classNames(
105122
"shadow-xs max-h-60 rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5",
@@ -108,13 +125,13 @@ export default function Home() {
108125
>
109126
{
110127
({ option }: { option: Option }) => {
111-
if (option.empty) {
128+
if (!option || option.empty) {
112129
return (
113130
<Combobox.Option
114131
// TODO: `disabled` being required is a bug
115132
disabled
116133
// Note: Do NOT use `null` for the `value`
117-
value={option}
134+
value={option ?? emptyOption.current}
118135
className="relative w-full cursor-default select-none py-2 px-3 focus:outline-none text-center"
119136
>
120137
<div className="grid grid-cols-1 grid-rows-1 h-full relative">
@@ -124,7 +141,19 @@ export default function Home() {
124141
</svg>
125142
</div>
126143
<div className="z-20 col-start-1 row-start-1 col-span-full row-span-full p-8 flex flex-col justify-center items-center">
127-
<h3 className="mx-2 text-xl text-gray-400 font-semibold">No people found</h3>
144+
<h3 className="mx-2 text-xl mb-4 text-gray-400 font-semibold">No people found</h3>
145+
<button
146+
id="add_person"
147+
type="button"
148+
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded font-semibold focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:outline-none"
149+
onClick={() => {
150+
let person = { name: query, disabled: false }
151+
setList(list => [...list, person])
152+
setSelectedPerson(person)
153+
}}
154+
>
155+
Add "{query}"
156+
</button>
128157
</div>
129158
</div>
130159
</Combobox.Option>

0 commit comments

Comments
 (0)