Criando um ComboBox com imagem
Se você deseja aumentar a interatividade e melhorar o design dos seus formulários na web, aprender como criar um ComboBox com imagens usando HTML, CSS e JavaScript é um excelente passo. Embora o HTML sozinho não permita adicionar imagens diretamente nas opções de uma caixa de seleção, com a combinação de CSS e JavaScript é possível exibir imagens junto ao texto em cada opção, tornando o formulário mais visual e atraente. Neste tutorial, mostraremos um exemplo prático de como criar um ComboBox com imagens de forma simples e eficaz.
Primeiro, vamos criar um select (ComboBox) tradicional e adicionar um atributo data a cada option
com a URL da imagem que será exibida. Esse atributo personalizado permitirá vincular uma imagem a cada opção do ComboBox.
<select name="pais" id="pais" style="display:none">
<option value="BRA" data-image="imgs/BRA.png">Brasil</option>
<option value="ARG" data-image="imgs/ARG.png">Argentina</option>
<option value="URU" data-image="imgs/URU.png" selected>Uruguai</option>
</select>
Agora vamos para o JavaScript, onde iremos criar uma classe. O objetivo dessa classe é receber o ID do elemento <select>
com suas options
, ocultar esse select
e, em seguida, criar dinamicamente um novo ComboBox utilizando divs
que exibem as opções com imagens. Quando uma opção é selecionada no ComboBox personalizado com a imagem, o valor correspondente é automaticamente atualizado no select
oculto. Esse processo melhora a experiência visual e mantém a funcionalidade do formulário original.
class ComboImage{
constructor(comboId) {
this.combo = document.getElementById(comboId);
this.combo.style.display="none";
this.comboContainer = document.createElement("div");
this.comboContainer.className = "combo-image";
this.combo.after(this.comboContainer);
this._initDisplay();
this.comboContainerOptions = document.createElement("div");
this.comboContainerOptions.className = "combo-image-options";
this.comboContainerOptions.style.display = "none";
this.comboContainerOptions.style.width = this.comboContainerDisplay.offsetWidth+'px';
console.log(this.comboContainerDisplay.offsetWidth )
this._loadOptions();
this.comboContainer.appendChild(this.comboContainerOptions);
}
_initDisplay() {
this.comboContainerDisplay = document.createElement("div");
this.comboContainerDisplay.className = "combo-image-display";
this.comboContainer.appendChild(this.comboContainerDisplay);
const selected = this.combo.options[this.combo.selectedIndex];
this.comboContainerDisplay.innerHTML = `<img src="${selected.dataset.image}"> ${selected.text}`;
this.comboContainerDisplay.addEventListener("click", () => {
this._toggleOption();
});
}
_loadOptions() {
Array.prototype.forEach.call( this.combo.options, (elemento) => {
const divOption = document.createElement("div");
const img = document.createElement("img");
img.src = elemento.dataset.image;
divOption.appendChild(img);
divOption.appendChild(document.createTextNode(elemento.text));
divOption.addEventListener("click", (ev) => {
this._selectOption(elemento);
});
this.comboContainerOptions.appendChild(divOption);
})
}
_toggleOption() {
this.comboContainerOptions.style.display = this.comboContainerOptions.style.display =='none'
? "block"
: "none";
}
_selectOption(elemento) {
this.combo.value = elemento.value;
this.comboContainerDisplay.innerHTML = `<img src="${elemento.dataset.image}"> ${elemento.text}`;
this.comboContainerOptions.style.display = "none";
}
}
Como vimos o código Javascript utiliza algumas classes CSS então vamos a elas:
Como visto anteriormente, o código JavaScript utiliza algumas classes CSS para estilizar o ComboBox personalizado. Agora, vamos detalhar essas classes.
body {
font-family: Arial, Helvetica, sans-serif;
}
.combo-image img{
width: 24px;
}
.combo-image-display{
border: 1px solid #CCC;
border-radius: 3px;
padding: 5px;
cursor: pointer;
width: 100%;
display: flex;
gap: 5px;
}
.combo-image-display::after{
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></svg>');
float: right;
width: 18px;
height: 18px;
margin-left: auto;
}
.combo-image-options{
border: 1px solid #CCC;
border-radius: 3px;
padding: 5px;
position: absolute;
background-color: #FFF;
width: 100%;
}
.combo-image-options > div{
padding: 5px;
cursor: pointer;
display: flex;
gap: 5px;
}
.combo-image-options > div:hover{
background-color: #CCC;
}
.combo-image-options img{
width: 24px;
}
Veja um exemplo online
ComboBox com Imagem com AlpineJS e Tailwind
Seguindo essa abordagem anterior, podemos utilizar o Tailwind CSS para aplicar os estilos e Alpine.js para carregar o JavaScript. Vamos a um exemplo prático: primeiro, criaremos o arquivo combo-image.js
para implementar a funcionalidade JavaScript.
function comboImage(el){
const comboElement = el;
comboElement.classList.add("hidden");
const comboContainer = document.createElement("div");
comboElement.after(comboContainer);
const optionSelected = comboElement.options[comboElement.selectedIndex];
const comboContainerDisplay = document.createElement("div");
comboContainerDisplay.className = "flex w-full gap-2 p-1 border rounded-sm cursor-pointer";
comboContainerDisplay.className += " after:content-['▾'] after:right after:ml-auto ";
comboContainerDisplay.innerHTML = `
<img src="${optionSelected.dataset.image}" class="w-8">
${optionSelected.text}`;
comboContainer.appendChild(comboContainerDisplay);
const comboContainerOptions = document.createElement("div");
comboContainerOptions.className = 'absolute hidden w-full p-2 bg-white border rounded-sm';
comboContainerOptions.style.width = comboContainerDisplay.offsetWidth+'px';
Array.prototype.forEach.call(comboElement.options, (elemento) => {
const divOption = document.createElement("div");
divOption.className = "flex gap-2 p-1 cursor-pointer hover:bg-gray-100";
const img = document.createElement("img");
img.src = elemento.dataset.image ?? "";
img.className = "w-8"
divOption.appendChild(img);
divOption.appendChild(document.createTextNode(elemento.text));
divOption.addEventListener("click", (ev) => {
comboContainerDisplay.innerHTML = `
<img src="${elemento.dataset.image}" class="w-8">
${elemento.text}
`;
comboContainerOptions.classList.toggle('hidden');
comboElement.value = elemento.value;
comboElement.dispatchEvent(new Event('change'));
});
comboContainerOptions.appendChild(divOption);
})
comboContainer.appendChild(comboContainerOptions);
comboContainerDisplay.addEventListener("click", () => {
comboContainerOptions.classList.toggle('hidden')
});
}
export default comboImage;
Agora, basta integrar o código como um plugin do Alpine.js para ativar a funcionalidade no seu projeto.
import comboImage from './combo-image.js';
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.directive('combo-image', comboImage);
Alpine.start();
Agora só precisamos carregar o plugin no elemento HTML select
que desejamos ter o combobox com imagens.
<select name="pais" id="pais" x-data x-combo-image>
<option value="BRA" data-image="imgs/BRA.png">Brasil</option>
<option value="ARG" data-image="imgs/ARG.png">Argentina</option>
<option value="URU" data-image="imgs/URU.png" selected>Uruguai</option>
</select>
Veja um exemplo online.
Bom esse é um exemplo simples que não deve ser muito dificil adaptar para a sua necessidade.