Search
Search lets people enter a keyword or phrase to get relevant information
Usage
Search is a navigation method that allows people to quickly find information across an app. Users input a query into the search bar or text field of the search view and then see related results.
Instalation
Copy and paste the following code into your project.
'use client'
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cn } from '@/lib/utils'
const SearchBarRoot = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
className={cn(
'relative flex h-14 w-full min-w-[360px] items-center rounded-xl bg-surfaceContainerHigh',
className
)}
{...props}
ref={ref}
/>
))
SearchBarRoot.displayName = 'SearchBarRoot'
const SearchBarInput = React.forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement> & {
asChild?: boolean
}
>(({ className, asChild, ...props }, ref) => {
const Comp = asChild ? Slot : 'input'
return (
<Comp
ref={ref}
type="search"
className={cn(
'h-full w-full grow bg-transparent px-4 text-body-lg text-onSurface outline-none placeholder:text-body-lg placeholder:text-onSurfaceVariant disabled:pointer-events-none disabled:cursor-not-allowed disabled:text-onSurface/38 disabled:placeholder:text-onSurface/38',
className
)}
{...props}
/>
)
})
SearchBarInput.displayName = 'SearchBarInput'
const SearchBarLeftSection = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
'flex shrink-0 items-center gap-2 pl-4 text-onSurface',
className
)}
{...props}
/>
))
SearchBarLeftSection.displayName = 'SearchBarLeftSection'
const SearchBarRightSection = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
'flex shrink-0 items-center gap-2 pr-4 text-onSurface',
className
)}
{...props}
/>
))
SearchBarRightSection.displayName = 'SearchBarRightSection'
const SearchViewContainer = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
'w-full origin-top animate-zoom-in-y rounded-b-xl border-t border-outline bg-surfaceContainerHigh',
className
)}
{...props}
/>
))
const SearchBar = Object.assign(SearchBarRoot, {
Input: SearchBarInput,
LeftSection: SearchBarLeftSection,
RightSection: SearchBarRightSection,
ViewContainer: SearchViewContainer,
})
export {
SearchBar,
SearchBarInput,
SearchBarLeftSection,
SearchBarRightSection,
}
Update the import paths to match your project setup.
Examples
Search bar with a leading and trailing icons
search
import { Avatar } from '@/components/ui/avatar'
import { Icon } from '@/components/ui/icon'
import { IconButton } from '@/components/ui/icon-button'
import { SearchBar } from '@/components/ui/search'
export const SearchExample = () => {
return (
<div className="flex-center bg-background w-full rounded-md p-4">
<div className="flex-center w-full max-w-sm">
<SearchBar>
<SearchBar.LeftSection>
<Icon symbol="search" />
</SearchBar.LeftSection>
<SearchBar.Input placeholder="Search your library" />
<SearchBar.RightSection className="pr-2">
<IconButton variant="standard">
<Icon symbol="mic" />
</IconButton>
<IconButton variant="standard">
<Avatar className="h-[30px]">
<Avatar.Image src="https://github.com/jepricreations.png" />
</Avatar>
</IconButton>
</SearchBar.RightSection>
</SearchBar>
</div>
</div>
)
}
Search view
Search view, which can display dynamic suggestions, is the focused state of search bar.
import { useRef, useState } from 'react'
import { CommandInput } from 'cmdk'
import { cn } from '@/lib/utils'
import { Avatar } from '@/components/ui/avatar'
import { Command } from '@/components/ui/command'
import { Icon } from '@/components/ui/icon'
import { IconButton } from '@/components/ui/icon-button'
import { SearchBar } from '@/components/ui/search'
const Contact = (id: number, name: string, pic: string) => ({ id, name, pic })
const contacts = [
Contact(1, 'Jepri', 'https://github.com/jepricreations.png'),
Contact(
2,
'Alex',
'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?q=80&w=2980&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
),
Contact(
3,
'Nikita',
'https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=3087&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
),
Contact(
4,
'Riccardo',
'https://images.unsplash.com/photo-1610186594416-2c7c0131e35d?q=80&w=3087&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
),
Contact(
5,
'Mina',
'https://images.unsplash.com/photo-1549351512-c5e12b11e283?q=80&w=2187&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
),
]
const historyItems = ['Peanut', 'End of school year', 'Renee']
export const SearchViewExample = () => {
const inputRef = useRef<HTMLInputElement>(null)
const [isOpen, setOpen] = useState(false)
return (
<Command className="bg-transparent">
<SearchBar
className={cn(
'transition-[border-radius] duration-100',
isOpen && 'rounded-b-none'
)}
>
<SearchBar.LeftSection className="pl-2">
<IconButton
variant="standard"
className={cn(
'animate-in fade-in-20 zoom-in-50',
isOpen ? 'hidden' : 'grid'
)}
>
<Icon symbol="menu" />
</IconButton>
<IconButton
variant="standard"
className={cn(
'animate-in fade-in-20 zoom-in-50',
isOpen ? 'grid' : 'hidden'
)}
>
<Icon symbol="arrow_back" />
</IconButton>
</SearchBar.LeftSection>
<SearchBar.Input asChild>
<CommandInput
ref={inputRef}
placeholder="Search replies"
onFocus={() => setOpen(true)}
onBlur={() => setOpen(false)}
/>
</SearchBar.Input>
<SearchBar.RightSection className="pr-2">
<IconButton variant="standard">
<Icon symbol="more_vert" />
</IconButton>
</SearchBar.RightSection>
</SearchBar>
{isOpen && (
<SearchBar.ViewContainer>
<Command.List>
<Command.Group>
{historyItems.map((item) => (
<Command.Item key={item} value={item}>
<Icon symbol="history" />
<p>{item}</p>
</Command.Item>
))}
</Command.Group>
</Command.List>
<div className="p-4">
<p className="text-label-lg mb-2">Contacts</p>
<div className="flex items-center gap-4">
{contacts.map(({ id, name, pic }) => (
<div key={id} className="flex flex-col items-center gap-1">
<Avatar>
<Avatar.Image src={pic} />
<Avatar.Fallback className="text-label-md">
{name.charAt(0).toUpperCase()}
</Avatar.Fallback>
</Avatar>
<span className="text-label-md">{name}</span>
</div>
))}
</div>
</div>
</SearchBar.ViewContainer>
)}
</Command>
)
}