Skip to main content

Search

O componente Search é um campo de entrada especializado para buscas que inclui um ícone de lupa e um botão de limpar opcional. É ideal para funcionalidades de busca em listas, catálogos e navegação.

Importação

import { Search } from '@useblu/ocean-react';

Importação específica (recomendado para tree-shaking)

import { Search } from '@useblu/ocean-react/Search';

Importação de tipos TypeScript

import type { SearchInputProps } from '@useblu/ocean-react';

// Uso em componente customizado
const MySearch: React.FC<{ onSearch: (term: string) => void }> = ({
onSearch,
}) => {
const [searchTerm, setSearchTerm] = React.useState('');

const handleSearch = (value: string) => {
setSearchTerm(value);
onSearch(value);
};

return (
<Search
placeholder="Buscar..."
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
/>
);
};

Playground Interativo

Explore o componente Search no playground interativo do Storybook. Use os controles para testar o placeholder e o estado disabled:

Documentação Completa

Para documentação técnica detalhada, exemplos de uso e API completa, consulte o Storybook do Search.

No Storybook você encontrará:

  • Controles interativos para testar placeholder e disabled
  • API gerada automaticamente com tipagem completa
  • Exemplos visuais de todas as variantes e estados
  • Playground para experimentação rápida

Uso básico

<Search placeholder="Buscar..." />

Com valor controlado

Exemplo de Search com valor controlado:

Estados

O Search suporta diferentes estados visuais:

Interativo

Exemplo de Search com funcionalidade de busca:

API

Props

PropTipoPadrãoDescrição
placeholderstring-Texto de placeholder do campo de busca
disabledbooleanfalseDesabilita o campo de busca

Nota: O componente Search aceita todas as props nativas de um elemento <input> HTML, mas apenas placeholder e disabled são expostos como controles no Storybook para simplicidade.

Classes CSS

O componente utiliza as seguintes classes CSS que podem ser customizadas:

ClasseDescrição
.ods-searchContainer principal do Search
.ods-search--filledModificador quando há valor no campo
.ods-search--disabledModificador para campo desabilitado
.ods-search__adornmentContainer do ícone de lupa
.ods-search__cleanBotão de limpar

Acessibilidade

  • ✅ Suporte completo a navegação por teclado
  • ✅ Estados de foco visíveis
  • ✅ Atributos ARIA apropriados
  • ✅ Suporte a screen readers
  • ✅ Contraste adequado em todos os estados

Boas práticas

  • Use placeholder descritivo para orientar o usuário
  • Implemente debounce para buscas em tempo real
  • Forneça feedback visual durante a busca
  • Use id único para acessibilidade
  • Use disabled quando a busca não estiver disponível

Melhores práticas

✅ Faça

  • Use para funcionalidades de busca
  • Implemente debounce para buscas em tempo real
  • Forneça feedback visual durante a busca
  • Use placeholder descritivo
  • Implemente busca case-insensitive
  • Use id único para acessibilidade
  • Use disabled quando apropriado

❌ Não faça

  • Não use para campos de entrada genéricos (use Input)
  • Não implemente busca sem debounce
  • Não ignore estados de loading
  • Não use placeholder muito longo
  • Não ignore feedback de "nenhum resultado"
  • Não use para campos de senha ou dados sensíveis
  • Não ignore o estado disabled quando apropriado

Casos de uso comuns

Busca simples

function SimpleSearch() {
const [searchTerm, setSearchTerm] = React.useState('');

return (
<Search
placeholder="Buscar produtos..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
id="search-products"
/>
);
}

Busca com debounce

function DebouncedSearch() {
const [searchTerm, setSearchTerm] = React.useState('');
const [isSearching, setIsSearching] = React.useState(false);

const debouncedSearch = React.useCallback(
React.useMemo(
() =>
debounce((term: string) => {
setIsSearching(true);
// Simular busca
setTimeout(() => {
console.log('Buscando por:', term);
setIsSearching(false);
}, 500);
}, 300),
[]
)
);

const handleSearch = (value: string) => {
setSearchTerm(value);
debouncedSearch(value);
};

return (
<Search
placeholder="Buscar com debounce..."
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
id="debounced-search"
/>
);
);
}

Busca em lista

function ListSearch() {
const [searchTerm, setSearchTerm] = React.useState('');
const [filteredItems, setFilteredItems] = React.useState(items);

const items = ['React', 'TypeScript', 'JavaScript', 'Node.js', 'Next.js'];

const handleSearch = (value: string) => {
setSearchTerm(value);
const filtered = items.filter((item) =>
item.toLowerCase().includes(value.toLowerCase())
);
setFilteredItems(filtered);
};

return (
<div>
<Search
placeholder="Filtrar lista..."
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
id="filter-list"
/>

<ul>
{filteredItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>

{filteredItems.length === 0 && searchTerm && (
<p>Nenhum resultado encontrado para "{searchTerm}"</p>
)}
</div>
);
}

Busca com validação

function ValidatedSearch() {
const [searchTerm, setSearchTerm] = React.useState('');
const [error, setError] = React.useState('');

const handleSearch = (value: string) => {
setSearchTerm(value);

if (value.length < 3 && value.length > 0) {
setError('Digite pelo menos 3 caracteres');
} else {
setError('');
}
};

return (
<Search
placeholder="Buscar (mínimo 3 caracteres)..."
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
id="validated-search"
/>
);
}

Busca desabilitada

function DisabledSearch() {
return (
<Search placeholder="Busca indisponível" disabled id="disabled-search" />
);
}

Busca básica

function BasicSearch() {
return (
<div>
<Search placeholder="Buscar no site..." />
<Search placeholder="Buscar desabilitado..." disabled />
</div>
);
}

Busca com resultado em tempo real

function RealTimeSearch() {
const [searchTerm, setSearchTerm] = React.useState('');
const [results, setResults] = React.useState<string[]>([]);
const [isLoading, setIsLoading] = React.useState(false);

const handleSearch = async (value: string) => {
setSearchTerm(value);

if (value.length >= 2) {
setIsLoading(true);
// Simular busca assíncrona
setTimeout(() => {
const mockResults = [
'Resultado 1',
'Resultado 2',
'Resultado 3',
].filter((item) => item.toLowerCase().includes(value.toLowerCase()));
setResults(mockResults);
setIsLoading(false);
}, 300);
} else {
setResults([]);
}
};

return (
<div>
<Search
placeholder="Buscar em tempo real..."
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
id="realtime-search"
/>

{results.length > 0 && (
<div>
{results.map((result, index) => (
<div key={index}>{result}</div>
))}
</div>
)}
</div>
);
}