Catálogo · Todo el sitio
Consentimiento para cookies
Pregunta una vez al visitante si el sitio puede usar cookies opcionales, muestra Aceptar y Rechazar uno junto al otro y recuerda la respuesta.
Encaja mejor en: cualquier sitio — cuando el sitio usa cookies opcionales
Ejemplo
El aviso de cookies de una bodega, con las dos opciones de respuesta y la elección de qué cookies permitir.
Este componente pregunta y registra una respuesta. No hace que un sitio cumpla la normativa: tú decides qué se guarda, tú redactas la información y tus scripts deben respetar la respuesta.
The example is live: until you answer it, it shows as a band at the bottom of this window, as it would on your site. Its answer is stored under its own key, luz-consent-demo, so it does not count as an answer for this site; the button above shows it again. This site lists that key on Privacy and storage.
Without JavaScript the banner and its button stay hidden.
Problemas conocidos
Sin JavaScript, el aviso no se muestra: no hay nada que responder, porque tampoco se ejecutan los scripts propios del sitio. Si el servidor establece cookies opcionales sin un script, debe pedir el consentimiento de otra forma.
- La respuesta es un registro en el navegador del visitante: el servidor no puede leerla, si borras los datos del sitio volverá a preguntarte y no prueba el consentimiento (art. 7(1) del RGPD); conserva el tuyo, por ejemplo desde un listener de
luz:consent. - En una ventana de menos de 30 rem (480 px) de alto, el aviso queda en el flujo, al principio de la página, y no fijo, así que la página baja cuando aparece.
- El estado guardado se oculta cuando el foco sale del aviso hacia la página, pero no al hacer clic en una zona vacía. Usa el botón Cerrar.
- No se ha probado con un lector de pantalla.
Código
Copiar el marcado
import "@luz-ds/catalog/components/cookie-consent.css";
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/cookie-consent.min.css" integrity="sha384-3DpxiYNab6T75OC8KW1K3HQokA+ljECduzmcDg+3OmGFTOOA0q90YnafFfrMkIvx" crossorigin="anonymous">
Justo después del enlace para saltar al contenido, antes de un anuncio y de la cabecera de la página (la cabecera del sitio o la cabecera de periódico, por ejemplo): aparece en la parte inferior de la ventana, pero es lo primero en el orden de lectura y de Tab. Hay una casilla por cada categoría de cookies opcionales; su value es el nombre de la categoría.
catalog.min.js carga el archivo propio del aviso, cookie-consent.min.js, cuando el navegador está inactivo; una página sin catalog.min.js carga ese archivo por su cuenta.
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/catalog.min.js"></script>
<a class="luz-skip-link" href="#main">Skip to main content</a>
<luz-cookie-consent>
<section class="luz-cookie-consent" data-luz-consent aria-labelledby="consent-title" hidden>
<div data-luz-consent-ask>
<h2 class="luz-cookie-consent__title" id="consent-title">Cookies on Bodega Albar</h2>
<p>We use cookies that this site needs to work. We would also like to count the visits
to each page, to decide which pages to update. <a href="/cookies/">Read the cookie policy</a>.</p>
<form class="o-actions">
<button class="luz-btn luz-btn--primary" type="submit" value="all">Accept optional cookies</button>
<button class="luz-btn luz-btn--primary" type="submit" value="none">Reject optional cookies</button>
</form>
<details class="luz-cookie-consent__choices">
<summary>Choose which cookies to allow</summary>
<form class="o-stack">
<fieldset class="luz-fieldset">
<legend>Optional cookies</legend>
<div class="luz-check-group">
<label class="luz-check-item"><input type="checkbox" value="analytics"> Measuring visits</label>
<label class="luz-check-item"><input type="checkbox" value="marketing"> Adverts on other sites</label>
</div>
</fieldset>
<div class="o-actions">
<button class="luz-btn luz-btn--secondary" type="submit">Save my choices</button>
</div>
</form>
</details>
</div>
<div data-luz-consent-done tabindex="-1" hidden>
<p>Your choice is saved. You can change it at any time on the
<a href="/cookies/">cookie policy</a> page.</p>
<button class="luz-btn luz-btn--secondary" type="button" data-luz-consent-close>Close</button>
</div>
</section>
</luz-cookie-consent>
<header>…</header>
<!-- On the cookie policy page -->
<button class="luz-btn luz-btn--outline" type="button" data-luz-consent-open hidden>Change cookie settings</button>
Tus scripts leen la respuesta y esperan a que haya una nueva. Carga un script opcional solo para una categoría que la persona visitante haya aceptado:
import { getConsent } from "@luz-ds/catalog/cookie-consent";
const granted = (answer) => answer?.granted.includes("analytics");
if (granted(getConsent())) startMeasuring();
document.addEventListener("luz:consent", (event) => {
if (granted(event.detail)) startMeasuring();
// Withdrawn: the simplest correct answer is to reload the page
else location.reload();
});
Variantes y opciones
No hay variantes. Los puntos de extensión son atributos data-luz-consent-*.
| Clase o atributo | Efecto |
|---|---|
.luz-cookie-consent | El aviso: una franja fija en la parte inferior de la ventana, de ancho completo y como máximo de media altura, con desplazamiento interno y el texto en la columna de la cabecera, en sans serif. En ventanas de menos de 30 rem de alto, se muestra en el flujo. Mantén hidden: el script lo muestra |
.luz-cookie-consent | Su encabezado, en sans serif; da nombre a la región del aviso mediante aria-labelledby |
.luz-cookie-consent | El <details> con las categorías, debajo de los dos botones |
<luz-cookie-consent> | El elemento personalizado que define el módulo. Al conectarse, enlaza el aviso que contiene |
data-luz-consent | En <section>: el aviso. data-luz-consent-days es opcional y define cuánto dura una respuesta (180 días por defecto, 395 como máximo); data-luz-consent-key define la clave de almacenamiento (debe empezar por luz-) y data-luz-consent-policy la versión de la política mostrada (32 caracteres como máximo: letras, números, ., _ o -), que se guarda con la respuesta |
data-luz-consent-ask, data-luz-consent-done | La pregunta y el mensaje de confirmación que la sustituye. El mensaje tiene tabindex="-1": recibe el foco |
data-luz-consent-close | En un botón dentro del mensaje de confirmación: oculta el aviso y devuelve el foco al botón que lo abrió, al primer botón data-luz-consent-open o a <main>. El mensaje también se oculta cuando el foco sale hacia la página |
value="all", value="none" | En los botones de envío: Aceptar permite todas las categorías y Rechazar, ninguna. Un botón de envío con otro valor o sin valor permite las categorías marcadas en su formulario |
data-luz-consent-open | En cualquier botón con hidden: se reserva su espacio, el script lo muestra y permite volver a abrir el aviso con la respuesta guardada marcada |
--luz-consent-h | El script lo establece en :root mientras se muestra el aviso: su altura. La página, .o-main y .luz-sidebar reservan ese espacio al final y desplazan lo que Tab alcanza para que quede por encima del aviso |
Cómo funciona
CSS de @luz-ds/catalog, dos formularios nativos y un archivo propio, @luz-ds/catalog/cookie-consent (dist/cookie-consent.min.js, menos de 1 kB comprimido), que define <luz-cookie-consent>. catalog.min.js lo carga cuando el navegador está inactivo y solo en páginas con <luz-cookie-consent>, así que las demás páginas no lo cargan.
Si añades un aviso después de cargar la página, debes importar el archivo a mano; aunque haya dos copias en una página, el elemento solo se define una vez.
- Cuándo pregunta: cuando no hay una respuesta guardada, cuando ha caducado o cuando el aviso ofrece una categoría que no se incluyó al guardar la respuesta. Entonces aparece como una franja en la parte inferior de la ventana, sin desplazar la página: no atrapa ni recibe el foco. La página le reserva espacio al final y desplaza lo que Tab alcanza para que quede por encima del aviso; así puedes leerla y usarla antes de responder.
- La respuesta: Aceptar permite todas las categorías; Rechazar, ninguna; Guardar mis opciones, las marcadas. Al pulsar Enter en una casilla se guardan las marcadas, nunca todas. Escape no es una respuesta: no ocurre nada. El mensaje de confirmación sustituye a la pregunta, recibe el foco y se lee. Desaparece al pulsar su botón Cerrar o cuando el foco sale del aviso hacia la página; el foco se queda donde haya ido.
- Dónde se guarda: en el
localStoragedel navegador, bajoluz-consent, como JSON:{"version":1,"expires":…,"asked":["analytics","marketing"],"granted":["analytics"],"given":"2026-11-01T10:00:00.000Z","policy":"v2"}, conexpiresen milisegundos desde 1970,givenla hora de la respuesta ypolicysolo cuando el aviso la tiene. Una respuesta nueva se fusiona en el registro que ya hay: las categorías que este aviso no ofrece (las de un contenido incrustado, por ejemplo) conservan su estado. No se guarda en una cookie: esta se enviaría al servidor con cada solicitud y no debería hacer falta una cookie para preguntar por ellas. No se guardan datos personales ni sale nada del navegador. Un valor mal formado cuenta como si no hubiera respuesta. Si el almacenamiento está bloqueado, la respuesta sirve para esa página y la siguiente vuelve a preguntar. - Tus scripts:
getConsent()devuelve la respuesta guardada,{ asked, granted, expires }, onull. Cada respuesta nueva envía el eventoluz:consentadocument, condetail{ asked, granted, withdrawn, expires, given, policy }:withdrawnlista lo que estaba concedido antes y ya no lo está, para que puedas borrar lo que guardaron esas categorías. Los nombres de categoría empiezan por una letra minúscula y pueden contener letras minúsculas, números o guiones; hasta 32 caracteres. - Cambiar la respuesta: es tan fácil como darla. Un botón con
data-luz-consent-openen la página de la política de cookies vuelve a mostrar el aviso. Pon un único aviso en cada página: todos esos botones lo abren. - El script no escribe ningún texto: todas las palabras están en tu marcado, en el idioma de la página.
Sin JavaScript
El aviso y el botón para volver a mostrarlo permanecen ocultos mediante el atributo hidden. Sin un script no se ejecutan los scripts propios del sitio, así que no hay nada que preguntar y los botones que no funcionarían no se muestran.
Incluye un enlace a la política de cookies en el pie de página de todas las páginas, para que siempre se pueda consultar.
Teclado y ARIA
- Orden: el enlace para saltar al contenido sigue siendo el primero, para que quienes vuelvan puedan ir directamente al contenido. El aviso va después, antes de la cabecera, aunque se muestre abajo: enlace a la política, Aceptar, Rechazar y, por último, el botón que abre las categorías.
- Teclas: Enter o Espacio en un botón; Espacio marca una casilla. Escape no hace nada: no oculta el aviso.
- Punto de referencia: un
<section>con el nombre de su encabezado es una región, que aparece entre los puntos de referencia antes que el punto de referencia de la cabecera. No es un diálogo: no bloquea la página, así que no necesitarole="dialog". - Foco: ninguno al cargar la página. Tras responder, el foco pasa al mensaje de confirmación; después de pulsar el botón para volver a mostrarlo, pasa al aviso. Cerrar lo devuelve a ese botón, al primero de ellos o a
<main>, nunca al principio de la página.
El contraste y el foco están en la pestaña Diseño.
Diseño
Cuándo usarlo
Úsalo si tu sitio instala cookies o guarda en el navegador datos que no necesita para funcionar, como los de medición de visitas o publicidad: la legislación de la UE y el Reino Unido exige el consentimiento del visitante antes de hacerlo.
Cuándo no usarlo
No lo uses si el sitio solo instala las cookies necesarias para funcionar (de sesión, del carrito) o solo guarda una elección que hizo el visitante, como el idioma o el color, y no la usa para nada más: no requieren consentimiento. Explícalo en la política de cookies y no muestres ningún aviso.
- No lo uses como una barrera que oculte o bloquee la página hasta que el visitante responda.
- No lo uses para anunciar noticias u ofertas: para eso tienes el anuncio.
Sustituye a un script de consentimiento de terceros. No reemplaza nada de LUZ.
Qué hacer y qué no
Cómo escribir el contenido
Explica en una frase, con palabras sencillas, qué necesita el sitio, qué quiere usar y por qué. Nombra el encabezado con el nombre del sitio: «Cookies en Bodega Albar».
- Redacta los botones como una acción y su objeto: «Aceptar las cookies opcionales», «Rechazar las cookies opcionales»; nunca «OK», «Entendido» o «De acuerdo».
- Nombra cada categoría por lo que hace y para quién: «Medir las visitas», «Anuncios en otros sitios», no «Rendimiento» ni «Segmentación».
- Enlaza la política de cookies por su nombre y explica en el mensaje de confirmación dónde se puede cambiar la respuesta.
Contraste y foco
El aviso es una franja con colores atenuados; sus botones y categorías son de core.
| Parte | Color sobre el fondo | Claro | Oscuro | Alto contraste | Mínimo necesario |
|---|---|---|---|---|---|
Encabezado y texto | --luz-text-primary on --luz-surface-muted | 15.8:1 | 15.1:1 | 20.1:1 | 4.5:1 |
Enlace a la política de cookies | --luz-brand-primary on --luz-surface-muted | 5.6:1 | 7.7:1 | 13.5:1 | 4.5:1 |
Aceptar y Rechazar | --luz-text-on-fill on --luz-brand-fill | 6.0:1 | 4.9:1 | 14.1:1 | 4.5:1 |
Borde de Aceptar y Rechazar | --luz-brand-fill on --luz-surface-muted | 5.6:1 | 3.5:1 | 13.5:1 | 3:1 |
Categorías y su botón | --luz-text-primary on --luz-surface | 16.5:1 | 14.0:1 | 21.0:1 | 4.5:1 |
Borde de la casilla | --luz-outline on --luz-input-bg | 4.5:1 | 3.4:1 | 21.0:1 | 3:1 |
Anillo de foco en la franja | --luz-focus-ring on --luz-surface-muted | 5.6:1 | 7.7:1 | 20.1:1 | 3:1 |
Calculado a partir de los valores de los tokens de cada modo, redondeado hacia abajo. El mínimo es el de WCAG 2.2 AA: 4,5:1 para el texto y 3:1 para los anillos de foco, los bordes y los límites.
- Foco: contorno de 2 px de core,
--luz-focus-ring, en el enlace, los botones y las casillas. - Aceptar y Rechazar tienen el mismo aspecto: ni el color ni el tamaño dan prioridad a una opción.
- Las categorías marcadas muestran una marca de verificación, no solo un relleno.
Tokens que usa
Los 11 tokens que las reglas de components/cookie-consent.css del catálogo leen para el aviso, agrupados por familia; los botones, el cuadro de categorías y las casillas son de core. Cada familia enlaza a su página, con los valores de todos los modos. En Figma son variables con los mismos nombres: consulta Tokens en Figma.
- Spacing and sizing
--luz-space-xs,--luz-space-md,--luz-space-xl- Typography
--luz-font-sans,--luz-text-md,--luz-text-lg- Layers
--luz-z-toast- Layout and breakpoints
--luz-content-max
El teclado y ARIA están en la pestaña Código.