React - Building Chip and Chip Input Component from Scratch
Tags: javascript, react, webdev, programming
Published: 2024-03-02 19:06:35

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 for tags](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7fn77mogwxcvhoqhhrc.png)


---

**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🙌
![Chip input](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nti5we6u23xsc2baqzx0.png)


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](ayeshadev.com)
👥 Connect: [Linkedin ](https://www.linkedin.com/in/ayesha-m-a2895b205/) | [Facebook ](https://www.facebook.com/profile.php?id=100095293729900)| [Instagram](https://www.instagram.com/ayes.hamunir98/)

---