A Roblox-native search input with clear button, placeholder text, debounced onChange callback, and keyboard return detection.
| Author | RobloxUI Team |
| Framework | Roblox-TS + React-Luau |
| Category | Containers |
| Dependencies | @rbxts/react, @robloxui/theme |
| Theme Tokens | colors.bgTertiary, colors.textPrimary, colors.textMuted, spacing.xs, spacing.sm |
| Last Updated | July 22, 2026 |
import React, { useState } from "@rbxts/react";
import { useTheme } from "@robloxui/theme";
interface SearchBarProps {
placeholder?: string;
onSearch: (query: string) => void;
debounceMs?: number;
}
export function SearchBar({ placeholder = "Search...", onSearch, debounceMs = 300 }: SearchBarProps) {
const { colors, spacing } = useTheme();
const [query, setQuery] = useState("");
const handleChange = (text: string) => {
setQuery(text);
task.wait(debounceMs);
onSearch(text);
};
return (
<frame BackgroundColor3={colors.bgTertiary} Size={new UDim2(0, 280, 0, 36)}>
<uicorner CornerRadius={new UDim(0, 8)} />
<textbox
Text={query}
PlaceholderText={placeholder}
PlaceholderColor3={colors.textMuted}
TextColor3={colors.textPrimary}
BackgroundTransparency={1}
Size={new UDim2(1, -spacing.sm, 1, 0)}
Position={new UDim2(0, spacing.xs, 0, 0)}
ClearTextOnFocus={false}
/>
{query !== "" && (
<imagebutton
Image={"rbxassetid://clear-icon"}
BackgroundTransparency={1}
Size={new UDim2(0, 20, 0, 20)}
Position={new UDim2(1, -28, 0.5, 0)}
AnchorPoint={new Vector2(0, 0.5)}
Event={{ Activated: () => { setQuery(""); onSearch(""); } }}
/>
)}
</frame>
);
}