🏇 Autocomplete Component Package for Chakra UI
MIT License
npm i --save @choc-ui/chakra-autocomplete
#or
yarn add @choc-ui/chakra-autocomplete
import { Flex, FormControl, FormHelperText, FormLabel } from "@chakra-ui/react";
import * as React from "react";
import {
AutoComplete,
AutoCompleteInput,
AutoCompleteItem,
AutoCompleteList,
} from "@choc-ui/chakra-autocomplete";
function App() {
const countries = [
"nigeria",
"japan",
"india",
"united states",
"south korea",
];
return (
<Flex pt="48" justify="center" align="center" w="full">
<FormControl w="60">
<FormLabel>Olympics Soccer Winner</FormLabel>
<AutoComplete openOnFocus>
<AutoCompleteInput variant="filled" />
<AutoCompleteList>
{countries.map((country, cid) => (
<AutoCompleteItem
key={`option-${cid}`}
value={country}
textTransform="capitalize"
>
{country}
</AutoCompleteItem>
))}
</AutoCompleteList>
</AutoComplete>
<FormHelperText>Who do you support.</FormHelperText>
</FormControl>
</Flex>
);
}
export default App;
You can create groups with the AutoCompleteGroup
Component, and add a title with the AutoCompleteGroupTitle
component.
import { Flex, FormControl, FormHelperText, FormLabel } from "@chakra-ui/react";
import * as React from "react";
import {
AutoComplete,
AutoCompleteGroup,
AutoCompleteGroupTitle,
AutoCompleteInput,
AutoCompleteItem,
AutoCompleteList,
} from "@choc-ui/chakra-autocomplete";
function App() {
const continents = {
africa: ["nigeria", "south africa"],
asia: ["japan", "south korea"],
europe: ["united kingdom", "russia"],
};
return (
<Flex pt="48" justify="center" align="center" w="full">
<FormControl w="60">
<FormLabel>Olympics Soccer Winner</FormLabel>
<AutoComplete openOnFocus>
<AutoCompleteInput variant="filled" />
<AutoCompleteList>
{Object.entries(continents).map(([continent, countries], co_id) => (
<AutoCompleteGroup key={co_id} showDivider>
<AutoCompleteGroupTitle textTransform="capitalize">
{continent}
</AutoCompleteGroupTitle>
{countries.map((country, c_id) => (
<AutoCompleteItem
key={c_id}
value={country}
textTransform="capitalize"
>
{country}
</AutoCompleteItem>
))}
</AutoCompleteGroup>
))}
</AutoCompleteList>
</AutoComplete>
<FormHelperText>Who do you support.</FormHelperText>
</FormControl>
</Flex>
);
}
export default App;
To access the internal state of the AutoComplete
, use a function as children (commonly known as a render prop). You'll get access to the internal state isOpen
, with the onOpen
and onClose
methods.
import {
Flex,
FormControl,
FormHelperText,
FormLabel,
Icon,
InputGroup,
InputRightElement,
} from "@chakra-ui/react";
import * as React from "react";
import {
AutoComplete,
AutoCompleteInput,
AutoCompleteItem,
AutoCompleteList,
} from "@choc-ui/chakra-autocomplete";
import { FiChevronRight, FiChevronDown } from "react-icons/fi";
function App() {
const countries = [
"nigeria",
"japan",
"india",
"united states",
"south korea",
];
return (
<Flex pt="48" justify="center" align="center" w="full">
<FormControl w="60">
<FormLabel>Olympics Soccer Winner</FormLabel>
<AutoComplete openOnFocus>
{({ isOpen }) => (
<>
<InputGroup>
<AutoCompleteInput variant="filled" placeholder="Search..." />
<InputRightElement
children={
<Icon as={isOpen ? FiChevronRight : FiChevronDown} />
}
/>
</InputGroup>
<AutoCompleteList>
{countries.map((country, cid) => (
<AutoCompleteItem
key={`option-${cid}`}
value={country}
textTransform="capitalize"
>
{country}
</AutoCompleteItem>
))}
</AutoCompleteList>
</>
)}
</AutoComplete>
<FormHelperText>Who do you support.</FormHelperText>
</FormControl>
</Flex>
);
}
export default App;
You can Render whatever you want. The AutoComplete
Items are regular Chakra
Boxes.
import {
Avatar,
Flex,
FormControl,
FormHelperText,
FormLabel,
Text,
} from "@chakra-ui/react";
import * as React from "react";
import {
AutoComplete,
AutoCompleteInput,
AutoCompleteItem,
AutoCompleteList,
} from "@choc-ui/chakra-autocomplete";
function App() {
const people = [
{ name: "Dan Abramov", image: "https://bit.ly/dan-abramov" },
{ name: "Kent Dodds", image: "https://bit.ly/kent-c-dodds" },
{ name: "Segun Adebayo", image: "https://bit.ly/sage-adebayo" },
{ name: "Prosper Otemuyiwa", image: "https://bit.ly/prosper-baba" },
{ name: "Ryan Florence", image: "https://bit.ly/ryan-florence" },
];
return (
<Flex pt="48" justify="center" align="center" w="full" direction="column">
<FormControl id="email" w="60">
<FormLabel>Olympics Soccer Winner</FormLabel>
<AutoComplete openOnFocus>
<AutoCompleteInput variant="filled" />
<AutoCompleteList>
{people.map((person, oid) => (
<AutoCompleteItem
key={`option-${oid}`}
value={person.name}
textTransform="capitalize"
align="center"
>
<Avatar size="sm" name={person.name} src={person.image} />
<Text ml="4">{person.name}</Text>
</AutoCompleteItem>
))}
</AutoCompleteList>
</AutoComplete>
<FormHelperText>Who do you support.</FormHelperText>
</FormControl>
</Flex>
);
}
export default App;
Add the multiple
prop to AutoComplete
component, the AutoCompleteInput
will now expose the tags in it's children function.
The onChange
prop now returns an array of the chosen values
Now you can map the tags with the AutoCompleteTag
component or any other component of your choice. The label
and the onRemove
method are now exposed.
import { Flex, FormControl, FormHelperText, FormLabel } from "@chakra-ui/react";
import * as React from "react";
import {
AutoComplete,
AutoCompleteInput,
AutoCompleteItem,
AutoCompleteList,
AutoCompleteTag,
} from "@choc-ui/chakra-autocomplete";
function App() {
const countries = [
"nigeria",
"japan",
"india",
"united states",
"south korea",
];
return (
<Flex pt="48" justify="center" align="center" w="full" direction="column">
<FormControl id="email" w="60">
<FormLabel>Olympics Soccer Winner</FormLabel>
<AutoComplete openOnFocus multiple onChange={vals => console.log(vals)}>
<AutoCompleteInput variant="filled">
{({ tags }) =>
tags.map((tag, tid) => (
<AutoCompleteTag
key={tid}
label={tag.label}
onRemove={tag.onRemove}
/>
))
}
</AutoCompleteInput>
<AutoCompleteList>
{countries.map((country, cid) => (
<AutoCompleteItem
key={`option-${cid}`}
value={country}
textTransform="capitalize"
_selected={{ bg: "whiteAlpha.50" }}
_focus={{ bg: "whiteAlpha.100" }}
>
{country}
</AutoCompleteItem>
))}
</AutoCompleteList>
</AutoComplete>
<FormHelperText>Who do you support.</FormHelperText>
</FormControl>
</Flex>
);
}
export default App;
I know that title hardly expresses the point, but yeah, naming is tough. You might want your users to be able to add extra items when their options are not available in the provided options. e.g. adding a new tag to your Polywork profile.
First add the creatable
prop to the AutoComplete
component.
Then add the AutoCompleteCreatable
component to the bottom of the list. Refer to the references for more info on this component.
Need to pull data from API, but don't want your users to see a blank screen? You can enable the loading state by passing the isLoading
prop to AutoComplete
. By doing this, 2 other props will be enabled
loadingIcon
on AutoCompleteInput
will display some sort of loading icon on the right side of the input. By default, a Spinner
will be displayed, but you can pass in any custom element to be rendered
loadingState
on AutoCompleteList
can display custom loading content when isLoading
is true
. All content will be rendered in the center of the list. By default, a Spinner
will be displayed, but you can pass in any custom element to be rendered.
Best practice is to combine setTimeout
and useEffect
to create a debounce effect. This will prevent un-necessary API calls if your user types relatively quickly.
A working code demo can be found here
It is relatively easy to integrate with form libaries such as React Hook Form
, Formik
, and others. Working examples can be found in the demos
folder of this repo. See the Contributing section of this doc on how to clone and set it up for testing.
Does your favorite form library not have a working example? Submit a PR to get it added and help others using this library quickly get up and running.
Assign a ref to the AutoComplete
component and call the available methods with:
ref.current?.resetItems();
ref.current?.removeItem(itemValue);
NB: Feel free to request any additional Prop
in Issues.
Wrapper and Provider for AutoCompleteInput
and AutoCompleteList
AutoComplete composes Box so you can pass all Box props to change its style.
NB: None of the props passed to it are required.
boolean | MaybeRenderProp<{ value: Item["value"] }>
(query: string, optionValue: Item["value"], optionLabel: Item["label"]) =>
boolean;
(value: string | Item["value"][], item: Item| Item[]) => void
(params: {
item: Item;
selectMethod: "mouse" | "keyboard" | null;
isNewInput: boolean;
}) => boolean | void
(params: {
item: Item;
focusMethod: "mouse" | "keyboard" | null;
isNewInput: boolean;
}) => boolean | void
(props:{tags:ItemTag[]}) => void
(removedTag: Item["value"],item: Item, tags: Item["value"][]) => void
(value: string) => boolean
string[]
Tags for multiple mode
AutoCompleteTag composes Tag so you can pass all Tag props to change its style.
string
string
() => void
Input for AutoComplete
value.
AutoCompleteInput composes Input so you can pass all Input props to change its style.
type children = MaybeRenderProp<{
tags: Item & { onRemove: () => void }[];
}>;
callback that returns ReactNode
and is provided with tags in multiple
mode
e.g.
<AutoCompleteInput variant="filled">
{({ tags }) =>
tags.map((tag, tid) => (
<AutoCompleteTag key={tid} label={tag.label} onRemove={tag.onRemove} />
))
}
</AutoCompleteInput>
RefObject<HTMLInputElement>
<AutoComplete multiple creatable />
React.ReactNode | JSX
Wrapper for AutoCompleteGroup
and AutoCompleteItem
AutoCompleteList composes Box so you can pass all Box props to change its style.
Wrapper for collections of AutoCompleteItem
s
AutoCompleteGroup composes Box so you can pass all Box props to change its style.
This Composes your suggestions
AutoCompleteItem composes Flex so you can pass all Flex props to change its style.
val => val;
boolean
{
fontWeight: 'extrabold',
}
boolean
{
fontWeight: 'extrabold',
}
{
fontWeight: 'extrabold',
}
{
fontWeight: 'extrabold',
}
Used with the AutoComplete
component's creatable
prop, to allow users enter arbitrary values, not available in the provided options.
AutoCompleteCreatable composes Flex so you can pass all Flex props to change its style.
It also accepts a function as its children
prop which is provided with the current inputValue
.
type children = MaybeRenderProp<{ value: any }>;
ReactNode
or callback that returns ReactNode
e.g.
<AutoCompleteCreatable>
{({ value }) => <span>Add {value} to List</span>}
</AutoCompleteCreatable>
boolean;
When true, AutoCompleteCreatable
is shown even when the AutoCompleteInput
is empty
git clone https://github.com/anubra266/choc-autocomplete.git
yarn
cd example
yarn
Start the package server, and the example server
# root directory
yarn start
# example directory with (cd example)
yarn dev
Thanks goes to these wonderful people (emoji key):
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!