# Modal & Toast

> Diálogos modales y notificaciones efímeras.

Categoría: Feedback · Solar v0.8.0

Usa este HTML tal cual, con Tailwind y ccs-tailwind-config.js cargados (ver https://utiliza.me/solar/instalacion.html).

## Confirmación

```html
<button type="button" commandfor="modal-eliminar" command="show-modal" class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium text-ccs-error hover:bg-ccs-error-soft focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:text-ccs-dark-error dark:hover:bg-ccs-dark-error-fill/10 dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Eliminar miembro</button>

<dialog id="modal-eliminar" aria-labelledby="modal-eliminar-titulo" aria-describedby="modal-eliminar-texto" class="relative w-11/12 max-w-md p-0 rounded-ccs bg-white text-ccs-ink shadow-ccs backdrop:bg-ccs-ink/60 dark:bg-ccs-dark-surface dark:text-ccs-dark-text dark:ring-1 dark:ring-ccs-dark-line">
  <form method="dialog" class="p-6">
    <div class="flex items-start gap-4 pr-10">
      <span class="w-10 h-10 rounded-ccs grid place-items-center shrink-0 bg-ccs-error-soft text-ccs-error dark:bg-ccs-dark-error-fill/10 dark:text-ccs-dark-error"><iconify-icon icon="solar:trash-bin-trash-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></span>
      <div class="flex-1 min-w-0 pt-2">
        <h2 id="modal-eliminar-titulo" class="text-base font-semibold">¿Eliminar a este miembro del comité?</h2>
        <p id="modal-eliminar-texto" class="text-sm text-ccs-slate mt-1 dark:text-ccs-dark-text-2">No se puede deshacer. Le avisaremos por correo.</p>
      </div>
    </div>
    <div class="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
      <button type="submit" value="cancelar" autofocus class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium hover:border-ccs-blue hover:text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:hover:border-ccs-dark-text dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Cancelar</button>
      <button type="submit" value="eliminar" class="h-10 px-4 rounded-ccs bg-ccs-error-fill text-white text-sm font-medium hover:bg-ccs-error-fill-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:bg-ccs-dark-error-fill dark:hover:bg-ccs-dark-error-fill-hover dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Eliminar miembro</button>
    </div>
  
    <button type="submit" value="cancelar" formnovalidate aria-label="Cerrar" class="absolute top-4 right-4 w-10 h-10 rounded-ccs grid place-items-center text-ccs-slate hover:bg-ccs-hover hover:text-ccs-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue dark:text-ccs-dark-text-2 dark:hover:bg-ccs-dark-hover dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent transition active:scale-95 motion-reduce:active:scale-100"><iconify-icon icon="solar:close-circle-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></button>
  </form>
</dialog>
```

## Con formulario

```html
<button type="button" commandfor="modal-contacto" command="show-modal" class="h-10 px-4 rounded-ccs bg-ccs-blue text-white text-sm font-medium hover:bg-ccs-blue-mid shadow-ccs-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:bg-ccs-blue-mid dark:hover:bg-ccs-blue dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Agregar contacto</button>

<dialog id="modal-contacto" aria-labelledby="modal-contacto-titulo" class="ccs-backdrop-blur relative w-11/12 max-w-xl p-0 rounded-ccs bg-white text-ccs-ink shadow-ccs open:flex open:flex-col max-sm:m-0 max-sm:h-full max-sm:max-h-full max-sm:w-full max-sm:max-w-full max-sm:rounded-none dark:bg-ccs-dark-surface dark:text-ccs-dark-text dark:ring-1 dark:ring-ccs-dark-line">
  <form method="dialog" class="flex flex-col min-h-0">
    <div class="flex items-center justify-between gap-3 px-6 py-4 border-b border-ccs-line dark:border-ccs-dark-line">
      <h2 id="modal-contacto-titulo" class="text-ccs-h3 pr-10">Agregar contacto</h2>
    </div>
    <div class="ccs-corte-scroll flex-1 min-h-0 overflow-y-auto px-6 py-6 space-y-6">
      <div>
        <label for="c-nombre" class="block text-sm font-medium mb-1.5">Nombre y apellido</label>
        <input type="text" id="c-nombre" name="nombre" required autofocus autocomplete="off" class="w-full h-11 px-4 rounded-lg border border-ccs-line-strong bg-white focus:border-ccs-blue focus:ring-2 focus:ring-ccs-blue/15 outline-none text-sm dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:focus:border-ccs-dark-accent dark:focus:ring-ccs-dark-accent/25" />
      </div>
      <div>
        <label for="c-cargo" class="block text-sm font-medium mb-1.5">Cargo</label>
        <div class="relative">
          <select id="c-cargo" name="cargo" class="w-full h-11 pl-4 pr-10 rounded-lg border border-ccs-line-strong bg-white focus:border-ccs-blue focus:ring-2 focus:ring-ccs-blue/15 outline-none text-sm appearance-none dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:focus:border-ccs-dark-accent dark:focus:ring-ccs-dark-accent/25"><option>Gerente general</option><option>Gerente comercial</option><option>Jefe de área</option><option>Otro</option></select>
          <iconify-icon icon="solar:alt-arrow-down-bold" class="absolute right-3 top-3.5 text-[16px] text-ccs-slate pointer-events-none dark:text-ccs-dark-text-2" aria-hidden="true"></iconify-icon>
        </div>
      </div>
      <div>
        <label for="c-correo" class="block text-sm font-medium mb-1.5">Correo</label>
        <input type="email" id="c-correo" name="correo" required class="w-full h-11 px-4 rounded-lg border border-ccs-line-strong bg-white focus:border-ccs-blue focus:ring-2 focus:ring-ccs-blue/15 outline-none text-sm dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:focus:border-ccs-dark-accent dark:focus:ring-ccs-dark-accent/25" />
      </div>
      <div>
        <label for="c-telefono" class="block text-sm font-medium mb-1.5">Teléfono <span class="font-normal text-ccs-slate dark:text-ccs-dark-text-2">(opcional)</span></label>
        <input type="tel" id="c-telefono" name="telefono" inputmode="tel" placeholder="+56 9 1234 5678" class="w-full max-w-xs h-11 px-4 rounded-lg border border-ccs-line-strong bg-white focus:border-ccs-blue focus:ring-2 focus:ring-ccs-blue/15 outline-none text-sm dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:focus:border-ccs-dark-accent dark:focus:ring-ccs-dark-accent/25" />
      </div>
      <div>
        <label for="c-rut" class="block text-sm font-medium mb-1.5">RUT</label>
        <input type="text" id="c-rut" name="rut" required placeholder="12.345.678-5" aria-describedby="c-rut-ayuda" class="w-full max-w-xs h-11 px-4 rounded-lg border border-ccs-line-strong bg-white focus:border-ccs-blue focus:ring-2 focus:ring-ccs-blue/15 outline-none text-sm dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:focus:border-ccs-dark-accent dark:focus:ring-ccs-dark-accent/25" />
        <div id="c-rut-ayuda" class="text-xs text-ccs-slate mt-1.5 dark:text-ccs-dark-text-2">Con guion y dígito verificador.</div>
      </div>
      <fieldset>
        <legend class="text-sm font-medium mb-2.5">Temas de interés <span class="font-normal text-ccs-slate dark:text-ccs-dark-text-2">(opcional)</span></legend>
        <div class="space-y-2.5 text-sm">
          <label class="flex items-center gap-3 cursor-pointer"><input type="checkbox" name="temas" class="ccs-check w-4 h-4 rounded border border-ccs-line-strong bg-white text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:text-ccs-blue-mid"/>Eventos y capacitaciones</label>
          <label class="flex items-center gap-3 cursor-pointer"><input type="checkbox" name="temas" class="ccs-check w-4 h-4 rounded border border-ccs-line-strong bg-white text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:text-ccs-blue-mid"/>Estudios sectoriales</label>
          <label class="flex items-center gap-3 cursor-pointer"><input type="checkbox" name="temas" class="ccs-check w-4 h-4 rounded border border-ccs-line-strong bg-white text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:text-ccs-blue-mid"/>Boletín semanal</label>
          <label class="flex items-center gap-3 cursor-pointer"><input type="checkbox" name="temas" class="ccs-check w-4 h-4 rounded border border-ccs-line-strong bg-white text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface dark:border-ccs-dark-line-strong dark:bg-ccs-dark-surface dark:text-ccs-blue-mid"/>Comités de trabajo</label>
        </div>
      </fieldset>
    </div>
    <div class="flex flex-col-reverse gap-2 px-6 py-4 border-t border-ccs-line sm:flex-row sm:justify-end dark:border-ccs-dark-line">
      <button type="submit" value="cancelar" formnovalidate class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium hover:border-ccs-blue hover:text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:hover:border-ccs-dark-text dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Cancelar</button>
      <button type="submit" value="guardar" class="h-10 px-4 rounded-ccs bg-ccs-blue text-white text-sm font-medium hover:bg-ccs-blue-mid shadow-ccs-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:bg-ccs-blue-mid dark:hover:bg-ccs-blue dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Agregar contacto</button>
    </div>
  
    <button type="submit" value="cancelar" formnovalidate aria-label="Cerrar sin guardar" class="absolute top-4 right-4 w-10 h-10 rounded-ccs grid place-items-center text-ccs-slate hover:bg-ccs-hover hover:text-ccs-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue dark:text-ccs-dark-text-2 dark:hover:bg-ccs-dark-hover dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent transition active:scale-95 motion-reduce:active:scale-100"><iconify-icon icon="solar:close-circle-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></button>
  </form>
</dialog>
```

## Informativo

```html
<button type="button" commandfor="modal-aviso" command="show-modal" class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium hover:border-ccs-blue hover:text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:hover:border-ccs-dark-text dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Ver aviso</button>

<dialog id="modal-aviso" closedby="any" aria-labelledby="modal-aviso-titulo" aria-describedby="modal-aviso-texto" class="relative w-11/12 max-w-md p-0 rounded-ccs bg-white text-ccs-ink shadow-ccs backdrop:bg-ccs-ink/60 dark:bg-ccs-dark-surface dark:text-ccs-dark-text dark:ring-1 dark:ring-ccs-dark-line">
  <form method="dialog" class="p-6">
    <div class="flex items-start gap-4 pr-10">
      <span class="w-10 h-10 rounded-ccs grid place-items-center shrink-0 bg-ccs-blue/10 text-ccs-blue dark:bg-ccs-dark-accent/10 dark:text-ccs-dark-accent"><iconify-icon icon="solar:info-circle-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></span>
      <div class="flex-1 min-w-0 pt-2">
        <h2 id="modal-aviso-titulo" class="text-base font-semibold">La memoria 2025 ya está publicada</h2>
        <p id="modal-aviso-texto" class="text-sm text-ccs-slate mt-1 dark:text-ccs-dark-text-2">La encuentras en Documentos del comité. Te avisaremos cuando esté la versión en inglés.</p>
      </div>
    </div>
    <div class="mt-6 flex justify-end">
      <button type="submit" value="ok" autofocus class="h-10 px-4 rounded-ccs bg-ccs-blue text-white text-sm font-medium hover:bg-ccs-blue-mid shadow-ccs-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:bg-ccs-blue-mid dark:hover:bg-ccs-blue dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Entendido</button>
    </div>
  
    <button type="submit" value="cerrar" aria-label="Cerrar" class="absolute top-4 right-4 w-10 h-10 rounded-ccs grid place-items-center text-ccs-slate hover:bg-ccs-hover hover:text-ccs-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue dark:text-ccs-dark-text-2 dark:hover:bg-ccs-dark-hover dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent transition active:scale-95 motion-reduce:active:scale-100"><iconify-icon icon="solar:close-circle-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></button>
  </form>
</dialog>
```

## Acción forzada

```html
<button type="button" commandfor="modal-sesion" command="show-modal" class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium hover:border-ccs-blue hover:text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:hover:border-ccs-dark-text dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Simular sesión por expirar</button>

<dialog id="modal-sesion" closedby="none" aria-labelledby="modal-sesion-titulo" aria-describedby="modal-sesion-texto" class="w-11/12 max-w-md p-0 rounded-ccs bg-white text-ccs-ink shadow-ccs backdrop:bg-ccs-ink/60 dark:bg-ccs-dark-surface dark:text-ccs-dark-text dark:ring-1 dark:ring-ccs-dark-line">
  <form method="dialog" class="p-6">
    <div class="flex items-start gap-4 pr-10">
      <span class="w-10 h-10 rounded-ccs grid place-items-center shrink-0 bg-ccs-warning-soft text-ccs-warning dark:bg-ccs-dark-warning-fill/10 dark:text-ccs-dark-warning"><iconify-icon icon="solar:clock-circle-bold" class="text-[24px]" aria-hidden="true"></iconify-icon></span>
      <div class="flex-1 min-w-0 pt-2">
        <h2 id="modal-sesion-titulo" class="text-base font-semibold">Tu sesión se cierra en 2 minutos</h2>
        <p id="modal-sesion-texto" class="text-sm text-ccs-slate mt-1 dark:text-ccs-dark-text-2">Por seguridad cerramos las sesiones inactivas. Si sigues conectado, no pierdes lo que tengas sin guardar.</p>
      </div>
    </div>
    <div class="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
      <button type="submit" value="salir" class="h-10 px-4 rounded-ccs border border-ccs-line-strong text-sm font-medium hover:border-ccs-blue hover:text-ccs-blue focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:border-ccs-dark-line-strong dark:hover:border-ccs-dark-text dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Cerrar sesión</button>
      <button type="submit" value="seguir" autofocus class="h-10 px-4 rounded-ccs bg-ccs-blue text-white text-sm font-medium hover:bg-ccs-blue-mid shadow-ccs-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue focus-visible:ring-offset-2 dark:bg-ccs-blue-mid dark:hover:bg-ccs-blue dark:focus-visible:ring-ccs-dark-accent dark:focus-visible:ring-offset-ccs-dark-surface transition active:scale-95 motion-reduce:active:scale-100">Seguir conectado</button>
    </div>
  </form>
</dialog>
```

## Toast

```html
<div class="relative h-80 rounded-ccs border border-ccs-line bg-ccs-bg p-6 dark:border-ccs-dark-line dark:bg-ccs-dark-overlay">
<div role="region" aria-label="Avisos" class="absolute bottom-6 right-6 left-6 space-y-3 sm:left-auto sm:w-96">
  <div role="status" class="rounded-ccs bg-ccs-ink text-white p-4 shadow-ccs flex items-center gap-3 dark:bg-ccs-dark-surface dark:ring-1 dark:ring-ccs-dark-line">
    <span class="w-7 h-7 rounded-full grid place-items-center shrink-0 bg-ccs-success-fill dark:bg-ccs-dark-success-fill"><iconify-icon icon="solar:check-circle-bold" class="text-[16px] text-white" aria-hidden="true"></iconify-icon></span>
    <div class="flex-1 min-w-0">
      <p class="text-sm font-medium">Documento guardado</p>
      <p class="text-xs text-white/70 dark:text-ccs-dark-text-2">Memoria 2025 · hace 1 segundo</p>
    </div>
    <button type="button" aria-label="Cerrar aviso" class="w-10 h-10 -my-2 -mr-2 rounded-ccs grid place-items-center shrink-0 text-white/70 hover:bg-white/10 hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white dark:text-ccs-dark-text-2 dark:hover:bg-ccs-dark-hover dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent transition active:scale-95 motion-reduce:active:scale-100"><iconify-icon icon="solar:close-circle-bold" class="text-[20px]" aria-hidden="true"></iconify-icon></button>
  </div>
  <div role="status" class="rounded-ccs bg-white border border-ccs-line p-4 shadow-ccs-sm flex items-center gap-3 dark:border-ccs-dark-line dark:bg-ccs-dark-surface">
    <span class="w-7 h-7 rounded-full grid place-items-center shrink-0 bg-ccs-blue/10 text-ccs-blue dark:bg-ccs-dark-accent/10 dark:text-ccs-dark-accent"><iconify-icon icon="solar:chat-round-dots-bold" class="text-[16px]" aria-hidden="true"></iconify-icon></span>
    <div class="flex-1 min-w-0">
      <p class="text-sm font-medium">Nuevo mensaje del comité</p>
      <p class="text-xs text-ccs-slate dark:text-ccs-dark-text-2">Hace 3 minutos</p>
    </div>
    <button type="button" aria-label="Cerrar aviso" class="w-10 h-10 -my-2 -mr-2 rounded-ccs grid place-items-center shrink-0 text-ccs-slate hover:bg-ccs-hover hover:text-ccs-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ccs-blue dark:text-ccs-dark-text-2 dark:hover:bg-ccs-dark-hover dark:hover:text-ccs-dark-text dark:focus-visible:ring-ccs-dark-accent transition active:scale-95 motion-reduce:active:scale-100"><iconify-icon icon="solar:close-circle-bold" class="text-[20px]" aria-hidden="true"></iconify-icon></button>
  </div>
</div>
</div>
```

## Guía: Cuándo usar

- Modal: una decisión o un dato que hace falta antes de seguir. Si no bloquea la tarea, no va en un modal.

- Confirmación: solo para lo que no se puede deshacer. El título es la pregunta y el botón principal repite la acción ("Eliminar miembro", no "Aceptar").
- El rojo se gana, no se reparte. El botón va en rojo cuando el modal frena una pérdida que la persona no buscaba — cerrar sin guardar, descartar un borrador, sobrescribir algo. Cuando ya eligió deliberadamente la acción destructiva y el modal solo le pide confirmarla, el rojo no agrega información: repite lo que ella acaba de pedir y, de tanto verlo, deja de significar algo. En ese caso basta el botón principal normal, con el verbo exacto. El ejemplo de acá va en rojo porque además es irreversible y afecta a otra persona.

- Con formulario: para pocos campos ligados a la página de fondo. Un formulario largo o de varios pasos va en su propia página.

- Informativo: algo que hay que ver, no decidir. Un solo botón. Si no interrumpe la tarea, probablemente sea un toast o una alerta en la página.

- Acción forzada: solo cuando no existe una opción neutra — una sesión que expira, un consentimiento que hay que aceptar o rechazar, una decisión legal. Siempre con al menos dos salidas visibles. Nunca para forzar una suscripción, tapar contenido ni evitar que alguien se vaya.

- Contenido largo va en otra parte. Un contrato, un documento o cualquier texto que obligue a desplazarse no va en un modal: los botones quedan fuera de vista y la página de atrás, que suele hacer falta, queda tapada. Si hay que leerlo sin salir de la página, usa un Panel lateral; si es un documento en sí mismo, dale su propia página.

- Toast: confirma algo que ya pasó. Sin acciones importantes: lo que hay que decidir no va en un toast.

## Guía: Comportamiento

Solar no entrega JavaScript para estos componentes: el modal funciona con HTML del navegador y el toast lo muestra tu proyecto. Lo que sigue es lo que debe pasar, lo programes como lo programes.

- Abrir: el botón lleva commandfor="id-del-modal" y command="show-modal". No necesita script.

- Cerrar: los botones van dentro de <form method="dialog">; Esc también cierra, sin configurar nada. Cancelar y × llevan formnovalidate para cerrar aunque falten datos.

- Clic en el fondo: solo cierra el Informativo, que no pide nada (closedby="any"). En la confirmación y en el formulario no se usa: un clic distraído descarta la decisión o borra lo escrito, sin aviso ni deshacer. La Acción forzada va más allá con closedby="none": deja fuera también Esc, y solo sus botones la cierran — por eso no lleva ×.

- Foco: al abrir, parte en la acción segura (autofocus en Cancelar) o en el primer campo; no sale del modal con Tab, y al cerrar vuelve al botón que lo abrió.

- Fondo: dos recetas, según cuánto contexto necesite conservar quien decide. Oscura (backdrop:bg-ccs-ink/60) en la confirmación: la pregunta se basta sola y reconocer la página de atrás ayuda a ubicarse. Con desenfoque (clase ccs-backdrop-blur de ccs-ui-kit.css) en el formulario: la tarea es larga y el fondo solo hace ruido; con transparencia reducida activada, la regla quita el desenfoque y sube la opacidad sola. Si lo de atrás es parte de la respuesta —filtros sobre una tabla, confirmar algo que se mira—, va la oscura, nunca el desenfoque.

- Scroll: mientras el modal está abierto, la página de atrás no se desplaza y el scroll de adentro no se encadena con el de afuera (reglas en ccs-ui-kit.css). Los altos máximos van en dvh, no en vh: en el celular, vh cuenta la barra del navegador como si no existiera y deja los botones fuera de la pantalla. Cuando el cuerpo corta, el contenido se desvanece en sus últimos 32 px (clase ccs-corte-scroll) y el desvanecido desaparece al llegar al final, para que la última línea se lea nítida. En pantallas bajo 640 px, el modal con formulario pasa a ocupar toda la pantalla (max-sm:m-0 max-sm:h-full max-sm:max-h-full max-sm:w-full max-sm:max-w-full max-sm:rounded-none), igual que el Header y el Buscador.

- Nombre: aria-labelledby apunta al título; en la confirmación, aria-describedby apunta al texto. La × lleva aria-label y mide 40 px.
- La × va al final del marcado. Visualmente sigue arriba a la derecha (absolute top-4 right-4 dentro de un <dialog> con relative), pero en el HTML es el último elemento del formulario. Así, quien usa un lector de pantalla llega primero al título y al contenido —que es lo que explica para qué se abrió el modal— y no al botón de cerrar. El orden visual no cambia, y el foco inicial sigue puesto a mano con autofocus, así que tampoco cambia por dónde se empieza.

- Toast: cada aviso con role="status", para que se anuncie sin mover el foco. Se queda al menos 5 segundos, no se va mientras tiene el cursor o el foco, y se puede cerrar.

Por qué: En iOS, el desplazamiento táctil se salta overflow: hidden: la página de atrás se mueve igual. Si tu proyecto lo necesita, fija el cuerpo guardando la posición y restáurala al cerrar:

// beforetoggle y toggle no suben por el DOM: se escuchan en cada <dialog>.
// Y el scroll se devuelve en toggle, no en beforetoggle: antes de que el
// modal se cierre, la regla overflow:hidden sigue activa y el navegador
// ignora el scrollTo.
var y = 0;
document.querySelectorAll('dialog').forEach(function (d) {
  d.addEventListener('beforetoggle', function (e) {
    if (e.newState !== 'open') return;
    y = window.scrollY;
    document.body.style.position = 'fixed';
    document.body.style.top = -y + 'px';
    document.body.style.width = '100%';
  });
  d.addEventListener('toggle', function (e) {
    if (e.newState !== 'closed') return;
    document.body.style.position = '';
    document.body.style.top = '';
    document.body.style.width = '';
    window.scrollTo(0, y);
  });
});

El modal nativo (<dialog> con showModal) ya bloquea el resto de la página, atrapa el foco y cierra con Esc. Hacerlo con un div obliga a programar todo eso, y es donde suelen fallar los modales.

## Guía: Navegadores antiguos

commandfor funciona desde Chrome 135, Firefox 144 y Safari 26.2 (diciembre de 2025), y closedby desde Chrome 134, Firefox 141 y Safari 26.2. Si tu proyecto debe abrir y cerrar el modal en versiones anteriores, agrega este respaldo; en los navegadores nuevos no hace nada.

if (!('commandForElement' in HTMLButtonElement.prototype)) {
  document.addEventListener('click', function (e) {
    var b = e.target.closest('[commandfor][command="show-modal"]');
    if (b) document.getElementById(b.getAttribute('commandfor')).showModal();
  });
}
// Clic en el fondo y Esc (respaldo de closedby): con el modal
// a pantalla completa, el clic solo cae en el <dialog> mismo si fue
// sobre el fondo, no sobre el contenido.
if (!('closedBy' in HTMLDialogElement.prototype)) {
  document.addEventListener('click', function (e) {
    var d = e.target;
    if (d instanceof HTMLDialogElement && d.open && d.getAttribute('closedby') === 'any') d.close('cancelar');
  });
  document.addEventListener('cancel', function (e) {
    if (e.target.getAttribute('closedby') === 'none') e.preventDefault();
  });
}
