Created
October 1, 2021 04:36
-
-
Save Shahaed/6094a3a971fc3afd7f82c8b1ddcc71cc to your computer and use it in GitHub Desktop.
How to use headless ui listbox with formik
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Fragment, useState } from 'react' | |
import { Listbox, Transition } from '@headlessui/react' | |
import { CheckIcon, SelectorIcon } from '@heroicons/react/solid' | |
export interface ListboxProps<T> { | |
/** | |
* The options to display in the dropdown. | |
*/ | |
options: T[]; | |
/** | |
* Callback for when the value changes. | |
*/ | |
onChange?: (value?: T) => void; | |
/** | |
* The selected value. | |
*/ | |
value?: T; | |
/** | |
* Will call on each onBlur event | |
*/ | |
setTouched?: (value: boolean) => void; | |
/** | |
* Placeholder text to display when no value is selected. | |
*/ | |
placeholder?: string; | |
/** | |
* Use this to disable the entire Listbox component & related children. | |
*/ | |
disabled?: boolean; | |
/** | |
* When true, the orientation of the Listbox.Options will be horizontal, otherwise it will be | |
* vertical. | |
*/ | |
horizontal?: boolean; | |
} | |
export default function Listbox<T>(props: ListboxProps) { | |
const [selected, setSelected] = useState( | |
placeholder ? undefined : props.options?.[0] | |
); | |
return ( | |
<div className="w-72 fixed top-16"> | |
<Listboxvalue={props.value ?? selected} | |
onChange={(value) => { | |
setSelected(value); | |
props.onChange?.(value); | |
}} | |
> | |
<div className="relative mt-1"> | |
<Listbox.Button | |
onBlur={() => props.setTouched?.(true)} | |
className="relative w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md cursor-default focus:outline-none focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-white focus-visible:ring-offset-orange-300 focus-visible:ring-offset-2 focus-visible:border-indigo-500 sm:text-sm" | |
> | |
<span className="block truncate">{selected.name}</span> | |
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"> | |
<SelectorIcon | |
className="w-5 h-5 text-gray-400" | |
aria-hidden="true" | |
/> | |
</span> | |
</Listbox.Button> | |
<Transition | |
as={Fragment} | |
leave="transition ease-in duration-100" | |
leaveFrom="opacity-100" | |
leaveTo="opacity-0" | |
> | |
<Listbox.Options className="absolute w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"> | |
{options.map((option, i) => ( | |
<Listbox.Option | |
key={i} | |
className={({ active }) => | |
`${active ? 'text-amber-900 bg-amber-100' : 'text-gray-900'} | |
cursor-default select-none relative py-2 pl-10 pr-4` | |
} | |
value={option} | |
> | |
{({ selected, active }) => ( | |
<> | |
<span | |
className={`${ | |
selected ? 'font-medium' : 'font-normal' | |
} block truncate`} | |
> | |
{option} | |
</span> | |
{selected ? ( | |
<span | |
className={`${ | |
active ? 'text-amber-600' : 'text-amber-600' | |
} | |
absolute inset-y-0 left-0 flex items-center pl-3`} | |
> | |
<CheckIcon className="w-5 h-5" aria-hidden="true" /> | |
</span> | |
) : null} | |
</> | |
)} | |
</Listbox.Option> | |
))} | |
</Listbox.Options> | |
</Transition> | |
</div> | |
</Listbox> | |
</div> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Field, Form, Formik, FormikProps, useField } from "formik"; | |
import Listbox from "./listbox"; | |
export default function ListboxWithFormik() { | |
const [, meta, helpers] = useField("mySelect"); | |
const { value, error } = meta; | |
const { setValue, setTouched } = helpers; | |
return ( | |
<Formik> | |
<Form> | |
<Listbox | |
options={["Jan", "Feb", "Mar", "Apr"]} | |
value={value} | |
onChange={setValue} | |
setTouched={setTouched} | |
/> | |
</Form> | |
</Formik> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment