SearchBar
A search input with icon, clear button, and optional cancel action.
Web preview — components render natively on iOS & Android
import { SearchBar } from "@/components/ui/search-bar";
function MyScreen() {
const [query, setQuery] = useState("");
return (
<SearchBar
value={query}
onChangeText={setQuery}
onClear={() => setQuery("")}
/>
);
}Installation#
npx @aniui/cli add search-barUsage#
search-screen.tsx
import { SearchBar } from "@/components/ui/search-bar";
function MyScreen() {
const [query, setQuery] = useState("");
return (
<SearchBar
value={query}
onChangeText={setQuery}
onClear={() => setQuery("")}
/>
);
}Sizes#
Three sizes to fit different layouts.
Web preview — components render natively on iOS & Android
<SearchBar size="sm" placeholder="Small search..." />
<SearchBar size="md" placeholder="Medium search..." />
<SearchBar size="lg" placeholder="Large search..." />With Cancel Button#
Show a cancel button when the search bar is focused (iOS pattern).
Web preview — components render natively on iOS & Android
const [query, setQuery] = useState("");
const [focused, setFocused] = useState(false);
<SearchBar
value={query}
onChangeText={setQuery}
onClear={() => setQuery("")}
onFocus={() => setFocused(true)}
showCancel={focused}
onCancel={() => { setQuery(""); setFocused(false); }}
/>Custom Icon#
Pass any React element via the icon prop. The icon size adjusts automatically based on the size variant (sm: 14, md: 16, lg: 20).
custom-icon.tsx
import { Ionicons } from "@expo/vector-icons";
<SearchBar
icon={<Ionicons name="search" size={18} color="#71717a" style={{ marginRight: 8 }} />}
value={query}
onChangeText={setQuery}
onClear={() => setQuery("")}
/>Props#
PropTypeDefault
size"sm" | "md" | "lg""md"valuestring—onChangeText(text: string) => void—iconReact.ReactNodesearch icononClear() => void—showCancelbooleanfalseonCancel() => void—placeholderstring"Search..."classNamestring—Accessibility#
TextInputwithaccessibilityRoleand search icon.- Clear button has
accessibilityLabelfor screen readers.
Source#
components/ui/search-bar.tsx
import React from "react";
import { View, TextInput, Pressable, Text } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const searchBarVariants = cva(
"flex-row items-center rounded-lg bg-muted px-3 min-h-12",
{
variants: {
size: {
sm: "min-h-10 px-2.5",
md: "min-h-12 px-3",
lg: "min-h-14 px-4",
},
},
defaultVariants: { size: "md" },
}
);
const iconSizes = { sm: 14, md: 16, lg: 20 } as const;
export interface SearchBarProps
extends Omit<React.ComponentPropsWithoutRef<typeof TextInput>, "placeholderTextColor">,
VariantProps<typeof searchBarVariants> {
className?: string;
icon?: React.ReactNode;
onClear?: () => void;
showCancel?: boolean;
onCancel?: () => void;
}
export function SearchBar({ size = "md", className, value, icon, onClear, showCancel, onCancel, ...props }: SearchBarProps) {
const iconSize = iconSizes[size ?? "md"];
return (
<View className="flex-row items-center gap-2">
<View className={cn(searchBarVariants({ size }), className)}>
<View className="mr-2">
{icon ?? <Text style={{ fontSize: iconSize, color: "#71717a" }}>\u2315</Text>}
</View>
<TextInput
className="flex-1 text-base text-foreground p-0"
placeholderTextColor="#71717a"
placeholder="Search..."
value={value}
accessibilityRole="search"
{...props}
/>
{value ? (
<Pressable onPress={onClear} className="ml-1 h-5 w-5 items-center justify-center rounded-full bg-muted-foreground/20" accessible={true} accessibilityRole="button" accessibilityLabel="Clear search">
<Text className="text-xs text-muted-foreground">\u2715</Text>
</Pressable>
) : null}
</View>
{showCancel && (
<Pressable onPress={onCancel} accessible={true} accessibilityRole="button">
<Text className="text-base text-primary">Cancel</Text>
</Pressable>
)}
</View>
);
}