DebounceInput
freeDebounceInput wraps Input with a configurable delay so onChange fires only after the user stops typing.
Preview
Dark
Debounced value: —
import { useState } from 'react';
import DebounceInput from '@/components/composites/DebounceInput';
export default function UsageDemo() {
const [value, setValue] = useState('');
return (
<div className="flex flex-col gap-2">
<DebounceInput
placeholder="Type something…"
wait={300}
onChange={(e) => setValue(e.target.value)}
/>
<p className="text-sm text-muted-foreground">
Debounced value: {value || '—'}
</p>
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add DebounceInputExamples
Sizes
Preview
Dark
import DebounceInput from '@/components/composites/DebounceInput';
export default function SizesDemo() {
return (
<div className="flex flex-col gap-2">
<DebounceInput size="sm" placeholder="Small" wait={300} />
<DebounceInput placeholder="Default" wait={300} />
<DebounceInput size="lg" placeholder="Large" wait={300} />
</div>
);
}Disabled
Preview
Dark
import DebounceInput from '@/components/composites/DebounceInput';
export default function DisabledDemo() {
return (
<div className="flex flex-col gap-2">
<DebounceInput disabled placeholder="Disabled input" wait={300} />
<DebounceInput
readOnly
value="Read-only value"
placeholder="Disabled input"
wait={300}
/>
</div>
);
}Search Filter
Preview
Dark
- Apple
- Avocado
- Banana
- Blueberry
- Cherry
- Cranberry
- Grape
- Grapefruit
- Kiwi
- Lemon
- Lime
- Mango
- Orange
- Papaya
- Peach
- Pineapple
- Plum
- Raspberry
- Strawberry
- Watermelon
import { useMemo, useState } from 'react';
import DebounceInput from '@/components/composites/DebounceInput';
const FRUITS = [
'Apple', 'Avocado', 'Banana', 'Blueberry',
'Cherry', 'Cranberry', 'Grape', 'Grapefruit',
'Kiwi', 'Lemon', 'Lime', 'Mango',
'Orange', 'Papaya', 'Peach', 'Pineapple',
'Plum', 'Raspberry', 'Strawberry', 'Watermelon',
];
export default function SearchFilterDemo() {
const [query, setQuery] = useState('');
const results = useMemo(() => {
if (!query) return FRUITS;
const lower = query.toLowerCase();
return FRUITS.filter((f) => f.toLowerCase().includes(lower));
}, [query]);
return (
<div className="flex flex-col gap-2">
<DebounceInput
placeholder="Search fruits…"
wait={200}
onChange={(e) => setQuery(e.target.value)}
/>
<ul className="max-h-60 overflow-y-auto border rounded-card divide-y divide-border">
{results.map((f) => (
<li key={f} className="p-2">
{f}
</li>
))}
{results.length === 0 && (
<li className="p-2 text-muted-foreground">No results</li>
)}
</ul>
</div>
);
}API
| Prop | Description | Type | Default |
|---|---|---|---|
wait | Debounce delay in milliseconds before onChange fires. | number | 500 |
value | Controlled input value. | string | — |
placeholder | Placeholder text. | string | — |
disabled | Disables the input. | boolean | false |
size | Layout size variant. | 'sm' | 'default' | 'lg' | 'default' |
onChange | Called after the debounce delay with the native change event. | (e: ChangeEvent<HTMLInputElement>) => void | — |