HTML e CSS: Criando uma caixa de seleção personalizada
html-css
Quando o assunto é desenvolvimento web, frequentemente precisamos personalizar elementos de interface para melhorar a experiência do usuário e integrar o design visual do site. Neste artigo, vamos criar um componente de seleção (dropdown) personalizado que não só parece bom mas também é acessível.
Estruturando o HTML inicial Comece por definir a estrutura básica do seu componente de seleção. Vamos utilizar um input tipo checkbox para controlar a visibilidade da lista de opções e ícones para melhorar a experiencia de usuário. Aqui usamos a biblioteca de ícones lucide-react: 👉 https://lucide.dev/guide/packages/lucide
<div class="select"> <div id="category-select"> <label for="options-view-button">Categoria</label> <input type="checkbox" id="options-view-button" /> <div id="select-button"> <div id="selected-value">Selecione a categoria</div> <div id="chevrons"> <i data-lucide="chevron-down"></i> <i data-lucide="chevron-up"></i> </div> </div> </div> </div> <script src="https://unpkg.com/lucide@latest"></script>
Aplicando CSS para Estilização A estilização é crucial para garantir que o componente de seleção não só funcione bem, mas também tenha uma boa aparência. Aqui está o CSS básico para começar:
* { margin: 0; padding: 0; box-sizing: border-box; } .select { padding: 6rem; } #category-select label { font-size: 0.75rem; letter-spacing: 0.0225rem; } #select-button { margin-top: 0.5rem; display: flex; padding: 0.75rem; align-items: center; justify-content: space-between; border-radius: 0.375rem; border: 1px solid #252529; background-color: #17171a; }
Com isso você terá esse resultado 👇
notion image
Agora vamos estilizar a parte interna do nosso input com mais CSS dando mais sentido a essa caixa de seleção, até porque aqueles dois ícones não fazem sentido juntos. Sem muito mistério vamos pro CSS:
#selected-value { color: #afabb6; font-size: 0.875rem; letter-spacing: 0.02625rem; } #chevrons svg { width: 1rem; height: 1rem; } #chevrons { color: #afabb6; } #chevrons [data-lucide='chevron-up'] { display: none; }
Resultado👇
notion image
Agora vamos explodir nossa cabeça com mais um pouco de CSS, a ideia é dá a nossa caixa de seleção mais vida e funcionalidades:
#options-view-button:focus + #select-button, #options-view-button:checked + #selected-button { outline: 1px solid #a881e6; } #category-select:has(#options-view-button:checked) label, #options-view-button:checked + #select-button #chevrons [data-lucide='chevron-down'] { color: #a881e6; } #options-view-button:checked + #select-button #chevrons [data-lucide='chevron-down'] { display: none; } #options-view-button:checked + #select-button #chevrons [data-lucide='chevron-up'] { display: block; }
Com isso adicionamos estilos condicionais ao componente de seleção personalizado. Quando o checkbox é focado ou marcado, o botão de seleção é destacado com uma borda. Além disso, a cor dos ícones de seta muda e a seta para baixo é ocultada enquanto a seta para cima é mostrada, indicando que o menu de seleção está ativo ou expandido. Resultado 👇
notion image
Com Um pouco mais de CSS, vamos controlar comportamento visual do checkbox representado pelo #options-view-button dentro do nosso componente de seleção customizado:
#category-select { position: relative; } #options-view-button { all: unset; position: absolute; inset: 0; cursor: pointer; z-index: 3; }
Embora o checkbox seja invisível, você vai perceber que toda a área do #category-select funcione como um botão interativo que, quando clicado, pode exibir ou esconder outros elementos, como uma lista de categorias, indicada pelos ícones de setas para cima e para baixo. Isso acontece porque estamos usando a propriedade position e seus valores: relative e absolute Resultado 👇
notion image
 
Vamos construir as opções de dentro do nosso componente de seleção. Aqui está aqui está o trecho do HTML, repita algumas vezes e mude os icones, label e value como desejar:
<ul id="options"> <li class="option"> <input type="radio" name="category" value="vegetable" data-label="Legume" /> <i data-lucide="carrot"></i> <span class="label">Legumes</span> <i data-lucide="check"></i> </li> <li class="option"> <input type="radio" name="category" value="bakery" data-label="Padaria" /> <i data-lucide="sandwich"></i> <span class="label">Pães</span> <i data-lucide="check"></i> </li> </ul>
Após fazer isso você terá um resultado parecido com esse:
notion image
Vamos estilizar?
#options { margin-top: 0.25rem; border-radius: 0.375rem; background: #17171a; } .option { display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem; border-bottom: 1px solid #252529; } .option .label { color: #fbf9fe; } .option svg { width: 1rem; height: 1rem; }
Com isso facilitamos a identificação das opções por parte do usuário e permitimos uma navegação mais intuitiva e agradável visualmente 😉
notion image
Hmmm, porém acredito que podemos melhorar, vamos jogar o último icone (o check) para o canto direito? Bem simples:
#option svg:last-child { margin-left: auto; color: #a881e6; }
Aqui usamos o pseudo-elemento last-child para pegar o último svg de cada <li>
Ainda sobre CSS, que tal darmos feedbacks imediatos aos usuários que interagirem com nosso componente?
.option svg:last-child { margin-left: auto; color: #A881E6; } .option:has(input:checked), .option:hover { border-bottom: 1px solid #252529; background-color: #252529; } .option:has(input:focus) { outline: 1px solid #A881E6; } .option [data-lucide="check"] { display: none; } .option:has(input:checked) [data-lucide="check"] { display: block; }
Resultado:
notion image
E se você usar os teclas de navegação do seu teclado você vai que a acessibilidade está presente, testa aí.
E, após aplicar a propriedade position com valor relative na classe .option agora vamos deixar nossos input de tipo radio absoluto em relação ao option:
.option input[type="radio"] { all: unset; position: absolute; inset: 0; cursor: pointer; }
Olha a mágica 👇
notion image
Vou colocar algumas cores no ícones:
.option:nth-child(1) { color: #BB9F3A; } .option:nth-child(2) { color: #8CAD51; } .option:nth-child(3) { color: #DB5BBF; } .option:nth-child(4) { color: #E07B67; } .option:nth-child(5) { color: #7B94CB; }
notion image
Nesse caso, quando usamos usando o pseudo-classe :nth-child cada regra CSS aplica uma cor única ao conteúdo de cada elemento .option com base na sua ordem no contêiner pai.
O próximo passo agora é fazer com que a partir do estado da nossa caixa de seleção os nossos inputs do tipo radio altere a visibilidade e a cor. Ah, mas antes de tudo, vá no identificador #options e defina um propriedade display: none; para que os nossos inputs radio não sejam visíveis.
Após isso:
#category-select:has(#options-view-button:checked) + #options { display: block; } .select:has(.option input:checked) #category-select label { color: #A881E6; } .select:has(.option input:checked) #category-select { color: #FBF9FE; }
Nas regras CSS que definimos aqui usam o pseudo-classe :has para estilizar elementos baseando-se no estado de seus elementos filhos, que é muito útil quando precisamos manipular a aparência dos elementos dependendo das interações do usuário.
notion image
 
Com isso finalizamos a parte visual de um componente de seleção personalizado. Aqui fizemos passo a passo para oferecer uma base sólida para criar um componente de seleção personalizado que não apenas se integra esteticamente com o design do seu site, mas também acessibilidade. Experimente adicionar mais estilos e funcionalidades conforme necessário para atender às suas necessidades específicas. Com essas habilidades, você pode melhorar significativamente a interação do usuário em seu site.

Aprenda programação do zero e DE GRAÇA

No Discover você vai descomplicar a programação, aprender a criar seu primeiro site com a mão na massa e iniciar sua transição de carreira.

COMECE A ESTUDAR AGORA