Please use Desktop to view and interact with components
Components300msspring
Expanding Search Dock
Minimal search icon that expands into full input with blur
searchexpanddockinputblur
Useto navigate between components
Preview
Code
TypeScript + React
'use client'
import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Search, X } from 'lucide-react'
export function ExpandingSearchDock() {
const [isExpanded, setIsExpanded] = useState(false)
const [query, setQuery] = useState('')
return (
<div className="relative">
<AnimatePresence mode="wait">
{!isExpanded ? (
<motion.button
key="icon"
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0, opacity: 0 }}
onClick={() => setIsExpanded(true)}
className="flex h-12 w-12 items-center justify-center rounded-full border border-border bg-card transition-colors hover:bg-muted"
>
<Search className="h-5 w-5" />
</motion.button>
) : (
<motion.form
key="input"
initial={{ width: 48, opacity: 0 }}
animate={{ width: 320, opacity: 1 }}
exit={{ width: 48, opacity: 0 }}
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
onSubmit={(e) => e.preventDefault()}
className="relative"
>
<motion.div
initial={{ backdropFilter: 'blur(0px)' }}
animate={{ backdropFilter: 'blur(12px)' }}
className="relative flex items-center gap-2 overflow-hidden rounded-full border border-border bg-card/80 backdrop-blur-md"
>
<div className="ml-4">
<Search className="h-4 w-4 text-muted-foreground" />
</div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
autoFocus
className="h-12 flex-1 bg-transparent pr-4 text-sm outline-none placeholder:text-muted-foreground"
/>
<motion.button
type="button"
onClick={() => {
setIsExpanded(false)
setQuery('')
}}
initial={{ scale: 0 }}
animate={{ scale: 1 }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className="mr-2 flex h-8 w-8 items-center justify-center rounded-full hover:bg-muted"
>
<X className="h-4 w-4" />
</motion.button>
</motion.div>
</motion.form>
)}
</AnimatePresence>
</div>
)
}
How to Use
- 1Install Framer Motion:
npm install framer-motion - 2Copy the code from above
- 3Paste it into your project and customize as needed
- 4Colors are customizable via Tailwind CSS classes. The default theme uses dark mode colors defined in your globals.css file