The SearchButton
component is a React-based UI element that allows users to initiate a search action. This component is styled with Tailwind CSS and uses Framer Motion for smooth animations. It provides a visually appealing search interaction with animations for opening and closing the search modal, as well as dynamic transitions for when the user types a query.
Here's a breakdown of how the component works, including its functionality and key sections of the code.
The component performs the following tasks:
Search Button Display:
SearchButton
renders a button with an icon and label.Search Modal Animation:
Search String Display:
The SearchButton
component is structured into several key parts:
The component uses two useState
hooks to manage the following states:
openSearch
: Boolean state to determine if the search modal is visible.searchString
: Stores the search query that the user types into the input field.
const [openSearch, setOpenSearch] = useState(false);
const [searchString, setSearchString] = useState("");
This is the main clickable button that users interact with to open the search modal. It includes an icon and a label. When clicked, it sets the openSearch
state to true
, triggering the modal to appear.
<button
onClick={() => {
setOpenSearch(true);
}}
>
<div className=" px-4 py-2 rounded-full ring-2 ring-foreground opacity-50 hover:opacity-100 duration-300 transition-all ease-in-out flex items-center gap-2">
<div className=" text-sm">SearchButton</div>
<div>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-search">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
</div>
</div>
</button>
The modal is rendered only when openSearch
is true
. It is animated into view using Framer Motion. The modal features a translucent backdrop, and the modal content slides in with a transition. Clicking outside the modal (on the backdrop) closes it by setting openSearch
to false
.
<AnimatePresence mode="wait">
{openSearch && (
<motion.div
key={openSearch ? "searchisOpen" : "searchisClose"}
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
exit={{
opacity: 0,
}}
className=" fixed z-40 h-full w-full top-0 left-0 flex items-center justify-center"
>
<div
onClick={() => {
setOpenSearch(false);
}}
className=" bg-background/60 backdrop-blur-md w-full h-full absolute z-20 "
/>
</motion.div>
)}
</AnimatePresence>
This is the main component of the modal, where users type their search query. The input field is styled to have a search icon on the left, and as the user types, the input field displays the current search query. If the searchString
is not empty, a message dynamically displays the current search term.
<motion.div
key={openSearch ? "searchisOpen" : "searchisClose"}
initial={{
opacity: 0,
y: 50,
}}
animate={{
opacity: 1,
y: 0,
transition: {
delay: 0.4,
ease: [0.25, 1, 0.5, 1],
},
}}
exit={{
opacity: 0,
y: 50,
transition: {
ease: [0.5, 0, 0.75, 0],
},
}}
className=" p-5 rounded-md bg-foreground text-background relative max-w-md w-full z-30 -mt-24"
>
<div className="relative">
<div className=" absolute left-0 top-1/2 -translate-y-1/2 ">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="lucide lucide-search"
>
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
</div>
<input
placeholder="Search..."
value={searchString}
onChange={(e) => setSearchString(e.target.value)}
className=" focus-visible:outline-none bg-foreground pl-8 w-full py-1 text-xl font-mono "
type="text"
/>
</div>
</motion.div>
As users type, a dynamic message displays the current search string. The animation is controlled using Framer Motion's AnimatePresence
and motion.div
. This part of the component is only shown if the searchString
is not empty.
<AnimatePresence mode="wait">
{searchString == "" ? null : (
<motion.div
key={searchString == "" ? "empty" : "filled"}
initial={{
minHeight: "0rem",
opacity: 0,
}}
animate={{
minHeight: "11rem",
opacity: 1,
transition: {
duration: 0.6,
ease: [0.25, 1, 0.5, 1],
},
}}
exit={{
minHeight: "0rem",
opacity: 0,
transition: {
duration: 0.6,
ease: [0.5, 0, 0.75, 0],
},
}}
className=" flex text-sm opacity-75 items-center justify-center py-3"
>
<motion.p
key={searchString == "" ? "empty" : "filled"}
initial={{
y: -50,
}}
animate={{
y: 0,
transition: {
duration: 0.6,
ease: [0.25, 1, 0.5, 1],
},
}}
exit={{
y: -50,
transition: {
duration: 0.6,
ease: [0.5, 0, 0.75, 0],
},
}}
>
searching for {searchString}
</motion.p>
</motion.div>
)}
</AnimatePresence>
To use this SearchButton
component, you can simply import it and place it within your React component tree:
import SearchButton from "./path-to-SearchButton";
function App() {
return (
<div>
<SearchButton />
</div>
);
}
export default App;
The SearchButton
component offers a clean and interactive way for users to perform searches. Its animation-powered design makes the interaction feel modern, while the use of Tailwind CSS ensures a responsive layout. By integrating Framer Motion, the component provides smooth transitions, improving the overall user experience.