acerca de HTML

Referencia de etiquetas

Etiqueta select en HTML: listas de opciones y selección

La etiqueta <select> en HTML permite elegir una o varias opciones en un formulario. Úsala cuando las respuestas están definidas, como el nivel de un curso o los intereses de una inscripción: la persona selecciona alternativas disponibles en lugar de escribir una respuesta libre.

<label for="nivel">Nivel</label>
<select id="nivel" name="nivel" required>
  <option value="">Elige un nivel</option>
  <option value="basico">Básico</option>
  <option value="avanzado">Avanzado</option>
</select>

Resultado: aparece un selector con «Elige un nivel» como elección inicial. En este desplegable simple obligatorio, esa primera opción vacía no satisface required: hay que elegir Básico o Avanzado. El rótulo visible «Nivel» está asociado mediante for e id. Para probar el fragmento, sustituye todo el contenido de <body> del documento completo de abajo por estas líneas, retirando su script. En la consola puedes comprobar document.getElementById('nivel').reportValidity() antes y después de elegir.

Sintaxis y contexto válido

Escribe apertura y cierre: <select>…</select>. El elemento cabe donde se admite contenido de frase, por ejemplo dentro de un párrafo o de un formulario. Puede existir fuera de <form>; su asociación para obtener o enviar datos se explica en los atributos.

Empieza con el patrón tradicional: opciones de texto en <option>, directamente en el selector o agrupadas con <optgroup label="Nombre del grupo">. El grupo aporta un rótulo, no una respuesta seleccionable, y no se anidan grupos. Conservamos los cierres explícitos de las opciones para facilitar la lectura.

El modelo vigente de <select> también admite <hr>, elementos auxiliares de scripts, <noscript> y <div> con sus restricciones. Para un desplegable contempla un <button> inicial opcional, usado en la personalización que se muestra más adelante. Por tanto, «solo admite <option>» es una simplificación incorrecta. Un contenedor no reemplaza la función de <optgroup>.

Las opciones enriquecidas conservan reglas de contenido propias: no permiten insertar cualquier HTML ni controles interactivos arbitrarios dentro de ellas. Para aprender y mantener una alternativa sencilla, los dos primeros ejemplos usan opciones de texto.

Selección simple, selected y multiple

Sin multiple, solo se elige una opción. ¿Cómo elijo una opción por defecto? Coloca selected en esa <option>, no en <select>:

<option value="avanzado" selected>Avanzado</option>

En un selector simple marca como máximo una opción. En un desplegable simple sin ninguna marcada, normalmente queda seleccionada la primera habilitada. El atributo selected declara el estado predeterminado; al restablecer el formulario se recupera ese estado, aunque la persona haya elegido otra opción.

¿Sirve value="avanzado" en <select>? No fija la selección inicial: value no es un atributo de autoría del selector. Cada opción aporta su value; si lo omites, el dato se deriva de su texto. Para cambiar la selección mediante JavaScript usa la propiedad DOM HTMLSelectElement.value:

document.getElementById('nivel').value = 'avanzado';

Ese cambio modifica la selección actual, no el atributo selected. En un selector múltiple, .value devuelve solo el valor de la primera opción seleccionada; para obtenerlos todos usa selectedOptions o los datos del formulario.

Con multiple, se pueden elegir cero o más opciones. Si también es required, hay que seleccionar al menos una; esto no significa que deban elegirse todas. Cada opción seleccionada y habilitada aporta una entrada con el mismo name: por ejemplo, intereses=semantica&intereses=accesibilidad. No hace falta añadir [] al nombre por exigencia de HTML; algunas aplicaciones del servidor adoptan esa convención.

Opciones vacías, agrupación y datalist

<select> no tiene atributo placeholder. Para una selección simple requerida con tamaño de presentación uno, coloca primero una opción con value="", hija directa del selector, como en el ejemplo mínimo. El estándar define esa opción de indicación y su validación. Ponerla dentro de <optgroup> no produce el mismo caso; en una lista múltiple o con varias filas visibles, una opción vacía no cumple esa función especial.

Agrupa alternativas por una relación útil: «Introducción» y «Continuación» ayudan a localizar cursos. Un título de grupo no se envía como valor. Tampoco uses un separador visual como única explicación de una categoría.

¿Select y datalist son iguales? <select> restringe la elección a sus opciones. <datalist> ofrece sugerencias a un <input> que sigue permitiendo escribir otro valor, sujeto a las restricciones del propio campo. Para recoger una ciudad que no conoces de antemano, las sugerencias pueden ser adecuadas; para escoger uno de tres turnos disponibles, un selector evita respuestas ajenas a la lista.

Ejemplo práctico: curso e intereses

Guarda este documento como seleccion.html en UTF-8 y ábrelo en el navegador. Incluye todo el código necesario, sin servidor ni archivos adicionales. Es una inspección local: no hay envío ni persistencia de datos. El botón usa JavaScript para validar y mostrar los valores; selección y restablecimiento son funciones nativas.

<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Elegir un curso</title>
  </head>
  <body>
    <h1>Elegir un curso</h1>
    <form id="select-form">
      <p><label for="select-curso">Curso (obligatorio)</label></p>
      <select id="select-curso" name="curso" required>
        <option value="">Elige un curso</option>
        <optgroup label="Introducción">
          <option value="html" selected>Primeros pasos con HTML</option>
          <option value="css">Primeros pasos con CSS</option>
        </optgroup>
        <optgroup label="Continuación">
          <option value="formularios">Formularios accesibles</option>
          <option value="tablas">Tablas de datos</option>
        </optgroup>
      </select>

      <p><label for="select-intereses">Intereses (uno o varios)</label></p>
      <p id="select-ayuda">Puedes conservar varias elecciones.
        La combinación de teclas o el gesto depende de tu dispositivo.</p>
      <select id="select-intereses" name="intereses" multiple size="4"
              aria-describedby="select-ayuda">
        <option value="semantica" selected>Estructura semántica</option>
        <option value="estilos">Estilos</option>
        <option value="accesibilidad" selected>Accesibilidad</option>
        <option value="validacion">Validación de formularios</option>
      </select>

      <p>
        <button id="select-comprobar" type="button" disabled>Comprobar selección</button>
        <button type="reset">Restablecer</button>
      </p>
    </form>
    <p id="select-resultado" role="status">Todavía no se han inspeccionado los datos.</p>
    <noscript><p>Sin JavaScript puedes elegir y restablecer opciones.
      La inspección de datos está desactivada.</p></noscript>

    <script>
      const formulario = document.getElementById('select-form');
      const comprobar = document.getElementById('select-comprobar');
      const resultado = document.getElementById('select-resultado');

      comprobar.addEventListener('click', () => {
        if (!formulario.reportValidity()) return;
        const datos = new FormData(formulario);
        resultado.textContent = 'Curso: ' + datos.get('curso')
          + '. Intereses: ' + JSON.stringify(datos.getAll('intereses'));
      });
      formulario.addEventListener('reset', () => {
        resultado.textContent = 'Todavía no se han inspeccionado los datos.';
      });
      comprobar.disabled = false;
    </script>
  </body>
</html>
  1. Usa Tab para llegar al curso. Inicialmente está elegido HTML por selected; cambia a CSS con las flechas. Los grupos se muestran como encabezados entre opciones. La apertura del desplegable depende del sistema y del navegador.
  2. Llega a Intereses. En muchos equipos, Mayús más flechas amplía un rango; Ctrl más clic permite elecciones separadas en Windows y Comando más clic suele hacerlo en macOS. La selección separada por teclado varía entre navegadores. En móviles puede aparecer una interfaz distinta: prueba las instrucciones de tu plataforma, sin asumir que Mayús o Ctrl estén disponibles.
  3. Conserva Estructura semántica y Accesibilidad. Activa «Comprobar selección» con Enter o Espacio. Con CSS elegido, aparece Curso: css. Intereses: ["semantica","accesibilidad"]. Los intereses siguen el orden de las opciones, no el orden de los clics.
  4. Elige «Elige un curso» y comprueba de nuevo: reportValidity() devuelve false, el control recibe la indicación nativa y el resultado no se actualiza. FormData por sí solo no valida. Restablece para recuperar HTML y los dos intereses originales.
  5. Desactiva JavaScript y recarga: puedes recorrer los controles, elegir y restablecer. El aviso explica que la inspección está desactivada y su botón permanece deshabilitado. No se pierde la lista de alternativas.

FormData.getAll('intereses') devuelve todos los valores de ese nombre; get() devuelve solo el primero. Si no queda ningún interés seleccionado, getAll() devuelve []. Convertir directamente estos datos con Object.fromEntries() pierde las entradas repetidas: no lo uses para reunir la selección múltiple.

Si retiras multiple, los intereses admiten una sola elección; deja también como máximo una opción con selected en el HTML. Retirar size cambia la presentación predeterminada, no desactiva la selección múltiple. Retirar name excluye ese control de FormData. Cambiar los valores de las opciones cambia los datos, aunque el texto visible siga igual. Eliminar un selector elimina esa elección; dejar sus opciones sueltas no conserva el control. Si quitas los grupos y conservas las opciones directamente en <select>, continúan disponibles sin las categorías.

Atributos y accesibilidad

La referencia de atributos de MDN distingue estas funciones del selector:

  • name: nombre del dato, como curso. Sin nombre no aporta una entrada al envío normal ni a FormData.
  • required: exige una elección conforme a las reglas de validación; el ejemplo mínimo empieza pendiente de ella.
  • disabled: impide la interacción y excluye el control de los datos del formulario. No significa «solo lectura».
  • multiple: permite varias elecciones; sin él se admite una sola.
  • size: entero positivo que indica cuántas filas mostrar. Sin él, el tamaño de presentación predeterminado es uno en selección simple y cuatro en múltiple. No limita cuántas opciones se eligen.
  • autocomplete: indicación para el autocompletado, como country en un selector de país; no añade opciones.
  • form: ID de un <form> del mismo documento, útil para asociar un selector situado fuera de él. Si falta, se asocia al formulario antecesor, cuando existe.

required, disabled y multiple son booleanos: la presencia los activa. Por ejemplo, disabled="false" sigue deshabilitando; retira el atributo para habilitar. Un selector también puede quedar deshabilitado por un <fieldset disabled>; MDN explica esa herencia y la exclusión del envío. No hay atributo readonly aplicable a <select>.

autocomplete admite on, off y tokens adecuados al dato. Es una indicación, no una garantía de que el navegador recuerde una elección. id, class y lang son globales; appearance es CSS y .value es una propiedad JavaScript. No mezcles esas funciones.

Da un nombre visible con <label>, indica qué es obligatorio y asocia las instrucciones mediante aria-describedby cuando ayuden. Conserva foco visible y navegación nativa; no agregues role="menu" para convertirlo en un menú de navegación. El ejemplo anuncia la actualización con role="status", pero el texto exacto que oirá una persona depende de su lector de pantalla. La validación del navegador tampoco sustituye a la validación del servidor en una aplicación real.

Personalización progresiva con selectedcontent

El selector tradicional tiene soporte establecido; su aspecto y el CSS admitido en las opciones dependen del sistema. Para personalizar un desplegable simple, puedes conservar <select> y sus opciones y activar appearance: base-select. Un <button> como primer hijo puede contener <selectedcontent>, que refleja el contenido de la opción elegida. Ese botón pertenece a la interacción del selector, no es un botón independiente para enviar el formulario.

Para probar esta variante, sustituye el contenido de <body> del documento práctico por el siguiente fragmento, retirando su script. No necesita JavaScript:

<label for="select-formato">Formato del curso</label>
<select id="select-formato" name="formato" class="select-personalizable">
  <button>
    <selectedcontent></selectedcontent>
  </button>
  <option value="presencial">Presencial</option>
  <option value="distancia">A distancia</option>
</select>

Añade este CSS dentro de un <style> en <head>:

@supports (appearance: base-select) {
  .select-personalizable,
  .select-personalizable::picker(select) {
    appearance: base-select;
  }

  .select-personalizable {
    border: 2px solid #2459a6;
    padding: 0.5rem;
  }
}

En un navegador compatible se personaliza el control y el contenido seleccionado se refleja en el botón. Cambia de Presencial a A distancia con el teclado. Retira el CSS para provocar la presentación tradicional y comprueba que ambas opciones siguen disponibles. Los navegadores antiguos pueden descartar el marcado adicional al analizarlo: conserva texto útil y valores explícitos en las opciones para esa alternativa. No introduzcas enlaces o controles anidados esperando que funcionen como acciones dentro del selector. Consulta el patrón de personalización de MDN.

Compatibilidad revisada el 3 de octubre de 2026: Chrome documenta estas funciones de personalización desde la versión 135 en su presentación del selector personalizable. MDN sigue indicando disponibilidad limitada para este conjunto de funciones. El soporte de <select> tradicional no implica soporte de base-select, ::picker(select) y <selectedcontent>; comprueba esas funciones y la alternativa en tus navegadores objetivo. No se prometen estilos idénticos ni la misma interfaz móvil.

Errores frecuentes y etiquetas relacionadas

Si falta un valor en los datos, revisa primero name, la asociación con el formulario y si el control o la opción están deshabilitados. Si falta parte de una selección múltiple, comprueba que usas getAll() en lugar de get() o de una conversión que elimine nombres repetidos. Si la selección inicial no cambia, revisa selected en la opción: añadir value al selector no la fija.

No sustituyas el control por una colección de <div> sin implementar nombres, teclado, foco y estados. Si hay muy pocas alternativas y conviene verlas todas, botones de opción para una elección o casillas para varias pueden facilitar la decisión. Para una respuesta abierta con sugerencias, elige <datalist>.

Continúa con <option> para los valores y la selección predeterminada, y con <optgroup> para las categorías. <selectedcontent> aporta la representación de la elección en el patrón personalizable; no reemplaza al selector ni determina los datos enviados.