🔎 Search Bar in React
Tags: react, webdev, tutorial, beginners
Published: 2023-02-08 16:37:43

...so, recently i've been needing a SearchBar component for my React Web Applications and i've kept postponing having a generic one that i can use in all my projects, but no more!

btw, this is also _my first blog post_ to [dev.to](https://dev.to/dorletz)

## Let's get started!

also if you'd like you can clone this project on [github](https://github.com/doruletzz/search-bar) or check it out on [stackblitz](https://stackblitz.com/edit/react-ts-j5ehry?file=index.tsx)

#### Step 1: Initialize Project
Before we get started, we need to initialize a react application, we will use [vite](http://vitejs.dev) & [npm](npmjs.com), but feel free to use whatever tools you'd like.

Pick React with Typescript:
```
npm create vite@latest search-bar
cd search-bar
npm install
npm run dev
```

Next we delete all other files in `src/*` except `src/App.tsx` & `src/main.tsx`

And we edit `App.tsx` to look something like this:
```
// src/App.tsx

export const App = () => {
	return <>Hello World</>	
};

export default App;
```

#### Step 2: SearchBar and Card components

Next up we create the 2 needed components, inside src/components/* for our application: `<SearchBar/>` & `<Card/>`

```
// src/components/Card/index.tsx

import { CardComponent } from './CardComponent';

const Card = CardComponent;

export default Card;

// src/components/Card/CardComponent.tsx

import React, { ReactNode } from 'react';

type CardComponentProps = {
	title: string;
	subtitle: string;
	slug?: string;
	children: ReactNode;
};

export const CardComponent = ({
	title,
	subtitle,
	slug,
	children,
}: CardComponentProps) => {
	return (
		<div id={slug} className='card'>
			<h6 className='title'>{title}</h6>
			{subtitle && <p className='subtitle'>{subtitle}</p>}
			<hr />
			{children && <div className='content'>{children}</div>}
		</div>
	);
};

```

And we have our `<Card/>` component. We create the SearchBar in a similar way, with something like this:

```
// src/components/SearchBar/index.tsx
import { SearchBarComponent } from './SearchBarComponent';

const SearchBar = SearchBarComponent;

export default SearchBar;

// src/components/SearchBar/SearchBarComponent.tsx
import React, { ChangeEvent, Dispatch, SetStateAction } from 'react';

type SearchBarComponentProps = {
	label?: string;
	inputText: string;
	setInputText: Dispatch<SetStateAction<string>>;
};

export const SearchBarComponent = ({
	label,
	inputText,
	setInputText,
}: SearchBarComponentProps) => {
	const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
		const { value } = e.target;
		setInputText(value);
	};

	return (
		<div className='search-bar'>
			<label>{label}</label>
			<input value={inputText} onChange={handleChange} />
		</div>
	);
};
```

And we are done, we've created our needed components.

## Step 3: Tying it all together

Finally we are going to use a state that will be passed inside of the SearchBar components

We update App.tsx to look something like this:

```
// src/App.tsx
import React, { ReactNode, useState } from 'react';
import Card from './components/Card';
import SearchBar from './components/SearchBar';

type CardData = {
	title: string;
	subtitle: string;
	content: ReactNode;
};
// const data : CardData[] = ...

export const App = () => {
	const [searchText, setSearchText] = useState('');

	const filterCard = (e: CardData) =>
		e.title.toLowerCase().includes(searchText.toLowerCase());

	return (
		<>
			<SearchBar
				label='SEARCH'
				inputText={searchText}
				setInputText={setSearchText}
			/>
			<div className='card-container'>
				{mockData.filter(filterCard).map((data, index) => (
					<Card
						key={index}
						title={data.title}
						subtitle={data.subtitle}
					>
						{data.content}
					</Card>
				))}
			</div>
		</>
	);
};

``` 

Step 4 (extra): Styling it all

First we style the layout, meaning `App.tsx` by creating a App.css

```
// src/App.tsx

...
import './App.css';
...

// src/App.css

.search-bar {
    margin: 2rem auto;
    max-width: 80rem;
}

.card-container {
    display: flex;
    flex-wrap: wrap;

    gap: 2rem;

    max-width: 80rem;
    margin: auto;
}

.card-container > .card {
    flex-basis: 30%;
}
```

Next up we style the SearchBar:

```
// src/components/SearchBar/SearchBarComponent.tsx
...
import './SearchBarComponent.css';
...
// src/components/SearchBar/SearchBarComponent.css
.search-bar {
    position: relative;
    max-width: 42rem;
}

.search-bar > input {
    width: 100%;
    padding: 0.75rem;
    padding-top: 1.75rem;

    background-color: var(--card-color);
    color: var(--text-color-900);

    font-size: 1.125rem;
    border: none;   
    border-radius: 0.5rem;
}

.search-bar > label {
    position: absolute;
    top: 0.5rem;
    left: 0.75rem;  
    font-size: 0.75rem;
    color: var(--text-color-800);
}
```

& Finally we do the Card:

```
// src/components/Card/CardComponent.tsx
...
import './CardComponent.css';
...

// src/components/Card/CardComponent.css
.card { 
    background-color: var(--card-color);
    aspect-ratio: 4/5;
    
    display: flex;
    flex-direction: column;
    gap: 0.5rem;

    border-radius: 1rem;
    padding: 2rem;
}

.card > .title {
    color: var(--text-color-900);
    font-size: 1.5rem;
    font-weight: bold;
    
    margin: 0;

    overflow: hidden;
    text-overflow: ellipsis;
}


.card > .subtitle {
    color: var(--text-color-800);
    text-transform: uppercase;
    font-size: 1rem;
    
    margin: 0;

    overflow: hidden;
    text-overflow: ellipsis;
}

.card > hr {
    background-color: var(--text-color-800);
    
    width: 2rem;
    height: 0.05rem;

    margin: 0;
    border: none;
    margin-right: 100%;
}

.card > .content {
    color: var(--text-color-900);
    flex-grow: 1;
        
    overflow: hidden;
    text-overflow: ellipsis;
}
```

And so we've created our SearchBar React Component.