In this blog post, we will walk through creating a Chip and Chip Input component in React. These components are commonly used in modern web applications for tagging, filtering, and input selection.
Chip Component
The Chip component is a small, interactive element that represents an input, attribute, or action. It is a versatile component that can be used in a variety of ways.
Here is the code for our Chip component:
import React from 'react'
import PropTypes from 'prop-types'
import { Label } from './ui/label'
import { IconX } from '@tabler/icons-react'
import { getProfileIcon } from '@/lib/helpers/common'
const imageProps = {
width: 20,
height: 20,
}
const avatarStyles = 'w-[20px] h-[20px]'
const Chip = ({ label, color, containerClass, labelClass, isDelete, isImage, onDelete, chipStyles, chipImage }) => {
return (
<div
className={`px-2 ${color} rounded justify-center items-center gap-1 inline-flex ${chipStyles} ${containerClass}`}
>
<div className="justify-center items-center gap-1 flex">
{isImage && getProfileIcon(chipImage, imageProps, label, avatarStyles, 'text-sm')}
<Label className={`text-zinc-600 text-xs font-medium ${labelClass}`}>{label}</Label>
</div>
{isDelete && (
<button onClick={onDelete}>
<IconX size={16} stroke={2} color={'red'} />
</button>
)}
</div>
)
}
Chip.propTypes = {
label: PropTypes.string.isRequired,
isDelete: PropTypes.bool,
onDelete: PropTypes.func,
color: PropTypes.string,
chipStyles: PropTypes.string,
isImage: PropTypes.bool,
chipImage: PropTypes.string,
containerClass: PropTypes.string,
labelClass: PropTypes.string,
}
export default Chip
On the Right side you can see chips with different titles and you can also make it profile tags and show user images and avatars into it!
Chip Input Component
The Chip Input component is a text input that can contain multiple "chips" as input. It is useful for tagging, multi-select, or input suggestions.
Here is the code for our Chip Input component:
import React, { useState, useRef } from 'react'
import Chip from './chip'
import PropTypes from 'prop-types'
function ChipsInput({ chips, setChips, chipColor }) {
const [inputValue, setInputValue] = useState('')
const [suggestions, setSuggestions] = useState(['Person', 'User'])
const [removedSuggestions, setRemovedSuggestions] = useState([])
const inputRef = useRef()
const handleInputChange = (event) => {
setInputValue(event.target.value)
}
const handleDeleteChip = (chipToDelete) => {
setChips(chips.filter((chip) => chip !== chipToDelete))
if (removedSuggestions.includes(chipToDelete)) {
setSuggestions((prevSuggestions) => [...prevSuggestions, chipToDelete])
setRemovedSuggestions((prevRemoved) => prevRemoved.filter((item) => item !== chipToDelete))
}
inputRef.current.focus()
}
const handleInputKeyDown = (event) => {
if (event.key === 'Enter') {
event.preventDefault()
const newChip = inputValue.trim()
if (newChip !== '') {
setChips([...chips, newChip])
setInputValue('')
}
} else if (event.key === 'Backspace' && inputValue === '') {
const lastChip = chips[chips.length - 1]
handleDeleteChip(lastChip)
}
}
const handleSuggestionClick = (suggestion) => {
setChips([...chips, suggestion])
setSuggestions((prevSuggestions) => prevSuggestions.filter((prevSuggestion) => prevSuggestion !== suggestion))
setRemovedSuggestions((prevRemoved) => [...prevRemoved, suggestion])
setInputValue('')
}
return (
<div className="relative">
<div className="flex flex-wrap gap-2 min-h-10 items-center bg-fieldsBg p-2 rounded">
{chips.map((chip) => (
<Chip
key={chip}
containerClass="h-[26px]"
label={chip}
isDelete={true}
color={chipColor}
onDelete={() => handleDeleteChip(chip)}
/>
))}
<input
ref={inputRef}
type="text"
value={inputValue}
onChange={handleInputChange}
onKeyDown={handleInputKeyDown}
className="flex-grow bg-fieldsBg text-sm outline-none"
/>
</div>
{!!suggestions.length && inputValue && (
<div className="absolute left-0 mt-1 w-full bg-white rounded shadow z-10">
{!!suggestions.filter((suggestion) => suggestion.toLowerCase().includes(inputValue.toLowerCase())).length &&
inputValue && (
<div className="absolute left-0 mt-1 w-full bg-white border rounded shadow z-10">
{suggestions
.filter((suggestion) => suggestion.toLowerCase().includes(inputValue.toLowerCase()))
.map((suggestion) => (
<button
key={suggestion}
onClick={() => handleSuggestionClick(suggestion)}
className="p-2 hover:bg-gray-200 cursor-pointer w-full text-left"
>
{suggestion}
</button>
))}
</div>
)}
</div>
)}
</div>
)
}
ChipsInput.propTypes = {
chips: PropTypes.arrayOf(PropTypes.string).isRequired,
setChips: PropTypes.func.isRequired,
chipColor: PropTypes.string.isRequired,
}
export default ChipsInput
Here you can see two chip inputs with different background chip color and cross icon to remove it and can also remove it through backspace๐
That's it for now, folks! ๐ I hope you found this post useful and it helps you in your coding journey. Remember, practice is key when it comes to mastering programming. Keep coding and stay curious! ๐ป๐
If you have any questions or feedback, feel free to leave a comment below. I'd love to hear from you! ๐
Thank you for reading! If you enjoyed this post, please consider giving it a ๐งก or ๐ฆ to help more people find it.
Happy coding! ๐
๐ Get in touch: Ayesha Munir
๐ฅ Connect: Linkedin | Facebook | Instagram
Top comments (0)