Cómo construir un Multiselect Dropdown en 4 Frameworks modernos

Cómo construir un Multiselect Dropdown en 4 Frameworks modernos

Artículospor Luis

Vamos a construir un componente multiselect desde cero usando React y Tailwind CSS, que nos permitirá seleccionar múltiples opciones desde un dropdown y mostrar en consola las opciones seleccionadas. Empezaremos con React ya que es lo que más hemos visto hasta ahora.

Paso 1: Crear la estructura base del componente

Primero vamos a crear el layout base del componente usando sólo HTML y clases de Tailwind. Esto nos permite enfocarnos primero en el diseño sin preocuparnos por la lógica todavía.

Creamos un archivo: MultiSelectDropdown.tsx Y pegamos esta estructura:

export default function MultiSelectDropdown() {
  return (
    <div className="w-60 m-auto">
      <button
        type="button"
        className="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
      >
        Dropdown button
        <svg
          className="w-2.5 h-2.5 ml-3"
          viewBox="0 0 10 6"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            d="M1 1L5 5L9 1"
            stroke="currentColor"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
          />
        </svg>
      </button>

      {/* Dropdown visible por ahora */}
      <div className="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm dark:bg-gray-700">
        <ul className="p-3 space-y-3 text-sm text-gray-700 dark:text-gray-200">
          <li>
            <label className="flex items-center gap-2">
              <input type="checkbox" />
              React
            </label>
          </li>
          <li>
            <label className="flex items-center gap-2">
              <input type="checkbox" />
              Vue
            </label>
          </li>
        </ul>
      </div>
    </div>
  );
}

¿Qué hicimos aquí?

  • Creamos un contenedor de ancho fijo centrado.

  • Agregamos un botón con estilos de Tailwind (bg-blue-700, rounded-lg, etc.).

  • Insertamos una lista de opciones de ejemplo.

  • Todo el diseño es estático todavía, sin funcionalidad.

Paso 2: Manejar la apertura y cierre del dropdown

Ahora vamos a hacer que el dropdown se oculte o muestre cuando hacemos clic en el botón.

import { useState } from "react";

export default function MultiSelectDropdown() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="w-60 m-auto">
      <button
        type="button"
        onClick={() => setIsOpen((prev) => !prev)}
        className="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
      >
        Dropdown button
        <svg
          className="w-2.5 h-2.5 ml-3"
          viewBox="0 0 10 6"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            d="M1 1L5 5L9 1"
            stroke="currentColor"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
          />
        </svg>
      </button>

      {isOpen && (
        <div className="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm dark:bg-gray-700">
          <ul className="p-3 space-y-3 text-sm text-gray-700 dark:text-gray-200">
            <li>
              <label className="flex items-center gap-2">
                <input type="checkbox" />
                React
              </label>
            </li>
            <li>
              <label className="flex items-center gap-2">
                <input type="checkbox" />
                Vue
              </label>
            </li>
          </ul>
        </div>
      )}
    </div>
  );
}

¿Qué aprendemos aquí?

  • React usa useState para manejar el estado de apertura del menú.

  • Con {isOpen && (...)} mostramos u ocultamos el dropdown de forma condicional.

  • Esto ya nos permite ver el menú al hacer clic, y ocultarlo al hacer clic de nuevo.

Paso 3: Crear opciones dinámicas

Ahora definimos una lista de opciones para renderizarlas dinámicamente. Así podemos cambiar fácilmente las opciones más adelante sin repetir código (Por el momento dentro del componente pero se puede fácilmente pasar como prop).

const options = [
  { label: "React", value: "react" },
  { label: "Vue", value: "vue" },
  { label: "Svelte", value: "svelte" },
  { label: "Solid", value: "solid" },
  { label: "Angular", value: "angular" },
];

Y en lugar de escribir <li> manualmente, iteramos con .map():

<ul className="p-3 space-y-3 text-sm text-gray-700 dark:text-gray-200">
  {options.map((option) => (
    <li key={option.value}>
      <label className="flex items-center gap-2">
        <input type="checkbox" />
        {option.label}
      </label>
    </li>
  ))}
</ul>

Paso 4: Guardar y manejar las opciones seleccionadas

Ahora implementamos la lógica para guardar las selecciones. Creamos una nueva variable de estado llamada selected que guardará un array con los valores seleccionados.

Además, queremos que cada vez que se seleccione o deseleccione algo, se haga un console.log() del array actualizado. Para evitar logs duplicados, lo haremos con useEffect.

import { useState, useEffect } from "react";

export default function MultiSelectDropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState<string[]>([]);

  // Este efecto imprime en consola cada vez que cambia la selección
  useEffect(() => {
    console.log("Seleccionadas:", selected);
  }, [selected]);

  const handleChange = (value: string) => {
    setSelected((prev) =>
      prev.includes(value)
        ? prev.filter((v) => v !== value)
        : [...prev, value]
    );
  };

  const options = [
    { label: "React", value: "react" },
    { label: "Vue", value: "vue" },
    { label: "Svelte", value: "svelte" },
    { label: "Solid", value: "solid" },
    { label: "Angular", value: "angular" },
  ];

  return (
    <div className="w-60 m-auto">
      <button
        onClick={() => setIsOpen((prev) => !prev)}
        type="button"
        className="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
      >
        Dropdown button
        <svg className="w-2.5 h-2.5 ml-3" /* ... */ />
      </button>

      {isOpen && (
        <div className="z-10 w-full mt-2 block bg-white rounded-lg shadow-sm">
          <ul className="p-3 space-y-3 text-sm text-gray-700">
            {options.map((option) => (
              <li key={option.value}>
                <label className="flex items-center gap-2">
                  <input
                    type="checkbox"
                    checked={selected.includes(option.value)}
                    onChange={() => handleChange(option.value)}
                  />
                  {option.label}
                </label>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

Resultado

Ya tenemos un componente 100% funcional en React:

  • Visualmente estilizado con Tailwind.

  • Dropdown desplegable al clic.

  • Permite seleccionar y deseleccionar múltiples opciones.

  • Imprime en consola las opciones seleccionadas sin duplicados.

 

Multiselect Dropdown en Vue 3 + Tailwind + TypeScript

Aquí replicamos el mismo componente de React, pero usando Vue 3, Composition API, TypeScript y Tailwind. Lo haremos desde cero, en pasos simples y comentados.

  • Mostrará un botón para desplegar un menú con opciones.

  • Permitirá seleccionar múltiples opciones (checkboxes).

  • Al seleccionar/deseleccionar, actualizará un array reactivo.

  • Imprimirá en consola las opciones seleccionadas (sin duplicados).

  • Usará Tailwind CSS para estilos.

 

Paso 1: Crear la estructura del componente

Creamos el archivo:

src/components/MultiSelectDropdown.vue

Y comenzamos con la estructura mínima:

<template>
  <div class="w-60 m-auto">
    <button
      type="button"
      class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
    >
      Dropdown button
      <svg
        class="w-2.5 h-2.5 ml-3"
        viewBox="0 0 10 6"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M1 1L5 5L9 1"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        />
      </svg>
    </button>

    <div class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm">
      <ul class="p-3 space-y-3 text-sm text-gray-700">
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            React
          </label>
        </li>
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            Vue
          </label>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
// Lógica vendrá después
</script>

¿Qué hicimos aquí?

  • Creamos la estructura visual: un botón y un dropdown con dos opciones fijas.

  • Usamos Tailwind para el diseño (botón azul, checkbox alineado).

  • No hay interactividad aún: ni apertura/cierre, ni selección.

Este paso sirve para tener el esqueleto visual listo antes de agregar la lógica.

Paso 2: Mostrar/Ocultar el dropdown con ref()

Queremos que el dropdown solo se muestre cuando hagamos clic en el botón. Para eso:

  • Creamos una variable reactiva llamada isOpen

  • Usamos v-if="isOpen" para mostrar el menú

  • Alternamos el valor con un método toggleDropdown()

Actualizamos el componente así:

<template>
  <div class="w-60 m-auto">
    <!-- Botón que abre/cierra el dropdown -->
    <button
      type="button"
      @click="toggleDropdown"
      class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
    >
      Dropdown button
      <svg
        class="w-2.5 h-2.5 ml-3"
        viewBox="0 0 10 6"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M1 1L5 5L9 1"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        />
      </svg>
    </button>

    <!-- Mostramos el dropdown solo si isOpen es true -->
    <div
      v-if="isOpen"
      class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
    >
      <ul class="p-3 space-y-3 text-sm text-gray-700">
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            React
          </label>
        </li>
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            Vue
          </label>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const isOpen = ref(false)

const toggleDropdown = () => {
  isOpen.value = !isOpen.value
}
</script>

¿Qué aprendimos aquí?

  • ref(false) crea una variable reactiva en Vue.

  • Usamos v-if="isOpen" para mostrar el menú condicionalmente.

  • Al hacer clic en el botón, toggleDropdown() invierte su valor (true / false).

Ya tenemos la interacción básica lista. ¡Se ve como un dropdown real!

Paso 3: Mostrar opciones desde un array con v-for

Hasta ahora, las opciones están “quemadas” en el HTML. Vamos a moverlas a un array para que el componente sea dinámico y reusable.

1. Creamos un array de opciones en el <script setup>

Usamos TypeScript para tipar las opciones:

interface Option {
  label: string
  value: string
}

const options: Option[] = [
  { label: 'React', value: 'react' },
  { label: 'Vue', value: 'vue' },
  { label: 'Svelte', value: 'svelte' },
  { label: 'Solid', value: 'solid' },
  { label: 'Angular', value: 'angular' }
]

2. Reemplazamos los <li> fijos por un v-for

Actualizamos el template:

<ul class="p-3 space-y-3 text-sm text-gray-700">
  <li v-for="option in options" :key="option.value">
    <label class="flex items-center gap-2">
      <input type="checkbox" />
      {{ option.label }}
    </label>
  </li>
</ul>

¿Qué logramos aquí?

  • El componente ahora usa un array tipado con Option[], lo que facilita reusarlo.

  • Con v-for, renderizamos tantas opciones como queramos sin duplicar código.

  • Vue se encarga de mantener la eficiencia del DOM con :key="option.value".

Paso 4: Manejar selección múltiple (checkboxes)

Ahora queremos que:

  • Cada checkbox represente una opción seleccionable.

  • Las opciones seleccionadas se guarden en un array selected.

  • Si ya está seleccionada, se deseleccione (toggle).

  • Se imprima en consola cada vez que el array cambie.

1. Creamos el estado selected

En el <script setup>:

import { ref, watch } from 'vue'

const selected = ref<string[]>([])

2. Creamos una función para agregar o quitar selecciones

const toggleSelection = (value: string) => {
  if (selected.value.includes(value)) {
    selected.value = selected.value.filter(v => v !== value)
  } else {
    selected.value.push(value)
  }
}

3. Escuchamos los cambios con watch (como useEffect en React)

Usamos :checked y @change para enlazar con el estado:

<input
  type="checkbox"
  :checked="selected.includes(option.value)"
  @change="toggleSelection(option.value)"
/>

Resultado

Ahora el componente:

  • Permite seleccionar múltiples opciones.

  • Guarda las seleccionadas en un array.

  • Hace console.log() al cambiar la selección.

 

Multiselect Dropdown en Svelte + Tailwind + TypeScript

Paso 1: Estructura HTML + Tailwind base

Vamos a comenzar por construir solo la estructura visual estática del componente, sin lógica aún. El objetivo es ver cómo se verá el dropdown, el botón y las opciones con checkboxes, usando únicamente HTML y Tailwind CSS.

Código inicial: MultiSelectDropdown.svelte

<script lang="ts">
  // lógica vendrá después
</script>

<div class="w-60 m-auto">
  <!-- Botón para abrir el dropdown -->
  <button
    type="button"
    class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
  >
    Dropdown button
    <svg
      class="w-2.5 h-2.5 ml-3"
      viewBox="0 0 10 6"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M1 1L5 5L9 1"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
  </button>

  <!-- Dropdown (visible todo el tiempo por ahora) -->
  <div
    class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
  >
    <ul class="p-3 space-y-3 text-sm text-gray-700">
      <li>
        <label class="flex items-center gap-2">
          <input type="checkbox" />
          React
        </label>
      </li>
      <li>
        <label class="flex items-center gap-2">
          <input type="checkbox" />
          Vue
        </label>
      </li>
    </ul>
  </div>
</div>

¿Qué tenemos hasta ahora?

  • Un botón con diseño responsivo (w-full, bg-blue-700, hover, rounded-lg).

  • Un ícono de flecha hacia abajo (svg).

  • Un menú tipo dropdown con dos opciones de ejemplo (React, Vue) como <li>.

  • Cada opción es un <label> que contiene un checkbox y un texto.

Paso 2: Mostrar/Ocultar el dropdown con una variable reactiva

Ahora vamos a hacer que el dropdown se abra y cierre al hacer clic en el botón, usando reactividad en Svelte con let.

¿Cómo lo haremos?

  • Creamos una variable isOpen con let

  • Alternamos su valor al hacer clic en el botón

  • Mostramos el dropdown solo si isOpen === true usando {#if}

Código actualizado

<script lang="ts">
  let isOpen = false;

  function toggleDropdown() {
    isOpen = !isOpen;
  }
</script>

<div class="w-60 m-auto">
  <!-- Botón con evento on:click -->
  <button
    type="button"
    on:click={toggleDropdown}
    class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
  >
    Dropdown button
    <svg
      class="w-2.5 h-2.5 ml-3"
      viewBox="0 0 10 6"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M1 1L5 5L9 1"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
  </button>

  <!-- Mostrar dropdown solo si isOpen es true -->
  {#if isOpen}
    <div
      class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
    >
      <ul class="p-3 space-y-3 text-sm text-gray-700">
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            React
          </label>
        </li>
        <li>
          <label class="flex items-center gap-2">
            <input type="checkbox" />
            Vue
          </label>
        </li>
      </ul>
    </div>
  {/if}
</div>

¿Qué aprendimos aquí?

  • En Svelte, let crea variables reactivas automáticamente.

  • on:click={toggleDropdown} es la forma de escuchar eventos.

  • {#if ...} es como v-if en Vue o un render condicional en React ({isOpen && (...)}).

 

Paso 3: Mostrar las opciones dinámicamente con {#each}

Hasta ahora, las opciones (React, Vue) están escritas directamente en el HTML. Ahora vamos a moverlas a un array tipado para que el componente sea dinámico y escalable.

1. Creamos el array de opciones en el <script>

interface Option {
  label: string;
  value: string;
}

const options: Option[] = [
  { label: 'React', value: 'react' },
  { label: 'Vue', value: 'vue' },
  { label: 'Svelte', value: 'svelte' },
  { label: 'Solid', value: 'solid' },
  { label: 'Angular', value: 'angular' },
];

Option es una interfaz que usamos para tipar las opciones. Esto es posible gracias a que activaste TypeScript

2. Reemplazamos los <li> fijos por {#each}

<ul class="p-3 space-y-3 text-sm text-gray-700">
  {#each options as option (option.value)}
    <li>
      <label class="flex items-center gap-2">
        <input type="checkbox" />
        {option.label}
      </label>
    </li>
  {/each}
</ul>

¿Qué logramos?

  • Las opciones ya no están duplicadas manualmente.

  • Podemos fácilmente agregar, quitar o pasar las opciones como props después.

  • Cada opción se representa con un checkbox y su label.

Paso 4: Manejar selección múltiple y mostrarla en consola

Queremos que el componente:

  1. Permita seleccionar múltiples opciones (con checkboxes).

  2. Guarde las opciones seleccionadas en un array.

  3. Haga console.log() del array cada vez que cambie.

¿Cómo lo haremos?

  • Creamos un array reactivo selected: string[].

  • Usamos bind:checked para vincular cada checkbox con el estado.

  • O mejor: manejamos el on:change manualmente, como hicimos en Vue y React (para control total).

  • Imprimimos con $: console.log(...) que es como watch o useEffect.

1. Creamos selected y toggleSelection()

let selected: string[] = [];

function toggleSelection(value: string) {
  if (selected.includes(value)) {
    selected = selected.filter((v) => v !== value);
  } else {
    selected = [...selected, value];
  }
}

// log reactivo
$: console.log('Seleccionadas:', selected);

2. Actualizamos los checkboxes

En cada input, usamos:

<input
  type="checkbox"
  checked={selected.includes(option.value)}
  on:change={() => toggleSelection(option.value)}
/>

¿Qué logramos?

  • El dropdown ya permite selección múltiple.

  • Los checkboxes reflejan el estado real.

  • Cada cambio en selected hace un console.log() sin duplicados.

  • Comportamiento igual al de React y Vue

Multiselect Dropdown en Angular + Tailwind + TypeScript

Paso 1: Estructura HTML + Tailwind base

Primero, creamos solo la estructura visual del componente, sin lógica aún. Esto nos permite ver el diseño del botón y el menú desplegable.

1. Crear el componente

Desde la terminal, en el proyecto Angular:

ng generate component components/multi-select-dropdown

Esto creará 4 archivos dentro de src/app/components/multi-select-dropdown:

  • multi-select-dropdown.component.ts

  • multi-select-dropdown.component.html

  • multi-select-dropdown.component.css

  • multi-select-dropdown.component.spec.ts

 

2. Usar el componente en app.component.html

Edita el archivo src/app/app.component.html y agrega:

<app-multi-select-dropdown></app-multi-select-dropdown>

3. Estructura HTML base en multi-select-dropdown.component.html

Pegamos la estructura visual básica con Tailwind:

<div class="w-60 m-auto">
  <!-- Botón que abre el dropdown -->
  <button
    type="button"
    class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
  >
    Dropdown button
    <svg
      class="w-2.5 h-2.5 ml-3"
      viewBox="0 0 10 6"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M1 1L5 5L9 1"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
  </button>

  <!-- Dropdown visible por ahora (sin lógica) -->
  <div
    class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
  >
    <ul class="p-3 space-y-3 text-sm text-gray-700">
      <li>
        <label class="flex items-center gap-2">
          <input type="checkbox" />
          React
        </label>
      </li>
      <li>
        <label class="flex items-center gap-2">
          <input type="checkbox" />
          Vue
        </label>
      </li>
    </ul>
  </div>
</div>

Resultado esperado

Si recargas http://localhost:4200, deberías ver:

  • Un botón azul que dice “Dropdown button”

  • Un dropdown con dos opciones (React y Vue)

  • Estilo limpio con Tailwind

Paso 2: Mostrar/Ocultar el dropdown con una variable en el componente

Queremos que el dropdown:

  • Se muestre al hacer clic en el botón.

  • Se oculte al volver a hacer clic.

¿Cómo lo haremos?

  1. Creamos una propiedad booleana isOpen en el .ts.

  2. Hacemos toggle con un método toggleDropdown().

  3. En el HTML, usamos *ngIf="isOpen" para mostrar/ocultar el menú.

1. Agregar lógica en el archivo .ts

Edita multi-select-dropdown.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-multi-select-dropdown',
  templateUrl: './multi-select-dropdown.component.html',
  styleUrls: ['./multi-select-dropdown.component.css'],
})
export class MultiSelectDropdownComponent {
  isOpen = false;

  toggleDropdown(): void {
    this.isOpen = !this.isOpen;
  }
}

2. Conectar el botón al método

Edita multi-select-dropdown.component.html:

<!-- Botón con (click) -->
<button
  type="button"
  (click)="toggleDropdown()"
  class="text-white justify-between w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center"
>
  Dropdown button
  <svg
    class="w-2.5 h-2.5 ml-3"
    viewBox="0 0 10 6"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path
      d="M1 1L5 5L9 1"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    />
  </svg>
</button>

3. Mostrar el dropdown condicionalmente

Reemplaza el div del dropdown así:

<div
  *ngIf="isOpen"
  class="z-10 w-full mt-2 block bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
>
  <ul class="p-3 space-y-3 text-sm text-gray-700">
    <li>
      <label class="flex items-center gap-2">
        <input type="checkbox" />
        React
      </label>
    </li>
    <li>
      <label class="flex items-center gap-2">
        <input type="checkbox" />
        Vue
      </label>
    </li>
  </ul>
</div>

Resultado

Ahora al hacer clic en el botón:

  • El menú aparece y desaparece.

  • El estado lo maneja isOpen con un simple toggle.

Paso 3: Mostrar las opciones dinámicamente desde un array

Hasta ahora, las opciones (React, Vue) están escritas directamente en el HTML. Vamos a moverlas a un array tipado en TypeScript y usar *ngFor para renderizarlas dinámicamente.

1. Declarar la interfaz y el array de opciones

Edita multi-select-dropdown.component.ts:

interface Option {
  label: string;
  value: string;
}

export class MultiSelectDropdownComponent {
  isOpen = false;

  options: Option[] = [
    { label: 'React', value: 'react' },
    { label: 'Vue', value: 'vue' },
    { label: 'Svelte', value: 'svelte' },
    { label: 'Solid', value: 'solid' },
    { label: 'Angular', value: 'angular' }
  ];

  toggleDropdown(): void {
    this.isOpen = !this.isOpen;
  }
}

2. Usar *ngFor para renderizar el listado en el HTML

En multi-select-dropdown.component.html, reemplaza los <li> fijos por:

<ul class="p-3 space-y-3 text-sm text-gray-700">
  <li *ngFor="let option of options">
    <label class="flex items-center gap-2">
      <input type="checkbox" />
      {{ option.label }}
    </label>
  </li>
</ul>

¿Qué logramos?

  • Las opciones ahora se gestionan desde el .ts, de forma escalable.

  • Podemos cambiar las opciones fácilmente o cargarlas desde un API más adelante.

  • El template está más limpio, sin duplicación.

Paso 4: Manejar selección múltiple con checkboxes

Queremos que:

  1. Cada vez que se seleccione o deseleccione una opción, actualicemos un array.

  2. El array contenga los value de las opciones seleccionadas.

  3. Usemos console.log() para mostrar el estado en tiempo real.

¿Cómo lo haremos?

  • Creamos selected: string[] = [] en el componente.

  • Usamos (change) en cada checkbox para manejar la selección.

  • Usamos [checked] para marcar el estado del checkbox.

  • Imprimimos en consola cada vez que cambia la lista.

1. Agrega el estado y función en el .ts

selected: string[] = [];

toggleSelection(value: string): void {
  if (this.selected.includes(value)) {
    this.selected = this.selected.filter(v => v !== value);
  } else {
    this.selected.push(value);
  }

  console.log('Seleccionadas:', this.selected);
}

2. Actualiza el input en el HTML

Modifica el input dentro del *ngFor así:

<input
  type="checkbox"
  [checked]="selected.includes(option.value)"
  (change)="toggleSelection(option.value)"
/>

Resultado

Ahora tu componente:

  • Permite seleccionar múltiples opciones.

  • Guarda la selección actualizada en this.selected.

  • Muestra el array actualizado en consola cada vez que haces clic.

 

Cierre del post:

🎯 ¿Qué hicimos?

Construimos el mismo componente multiselect dropdown visualmente consistente en:

Framework Enfoque Lenguaje Estado JSX / Template Observaciones
React Hooks (useState, useEffect) TypeScript useState JSX Familiar y flexible. Control explícito.
Vue 3 Composition API + ref() + watch TypeScript ref, watch Plantilla declarativa Reactividad clara y directa. Fácil binding.
Svelte Variables reactivas (let, $:) TypeScript Local vars + auto-reactividad Template HTML puro Sintaxis más limpia y mínima. Muy ergonómico.
Angular Component Class + *ngIf + (change) TypeScript Clases + propiedades Template estructurado Verboso pero robusto. Ideal en equipos grandes.

¿Qué aprendimos?

  • Todos los frameworks modernos permiten construir componentes dinámicos y accesibles.

  • Aunque el resultado visual es el mismo, cada ecosistema tiene su propio “ritmo”:

    • React son ideales si te gusta el control imperativo y JSX.

    • Vue y Svelte son más declarativos y expresivos.

    • Angular prioriza estructura, reglas y escalabilidad.

 

¿Cuál fue más simple?

  • En cuanto a cantidad de código y claridad inmediata, Svelte y Vue 3 se sintieron más livianos.

  • React ofrecieron control fino y granularidad, ideales para lógica compleja.

  • Angular fue el más verboso, pero también el más estricto y mantenible para proyectos grandes.

¿Dónde usar este patrón?

Un componente como este es útil en:

  • Formularios de filtro avanzados

  • Paneles de administración

  • Dashboards

  • Apps móviles con diseño adaptativo

Conclusión

Construir un componente funcional, accesible y visualmente uniforme en diferentes frameworks es una excelente forma de:

  • Aprender sus fortalezas y diferencias

  • Comparar enfoques reactivos

  • Evaluar la curva de entrada y el esfuerzo de mantenimiento

Como desarrolladores, saber trabajar en más de un entorno nos hace más versátiles y estratégicos.

-- ¿Quieres recibir mi newsletter? --

No te pierdas de aprender:

Mi newsletter mensual viene con una dosis de inspiración, recursos para descargar, consejos de desarrollo rápidos y los mismos recursos que aprendo.