{
  "name": "dialog",
  "title": {
    "es": "Diálogo",
    "en": "Dialog"
  },
  "summary": {
    "es": "Ventana modal para una tarea corta o una confirmación.",
    "en": "Modal window for a short task or a confirmation."
  },
  "category": "overlays",
  "status": "stable",
  "nivel": "componentes",
  "updated": "2026-09-29",
  "license": "MIT",
  "page": "https://componentes-lovat.vercel.app/c/dialog/",
  "requires": [
    "button",
    "text-field"
  ],
  "files": [
    {
      "type": "html",
      "url": "https://componentes-lovat.vercel.app/raw/dialog/dialog.html",
      "content": "<button class=\"c-btn c-btn--outline\" type=\"button\" commandfor=\"dlg-profile\" command=\"show-modal\">Editar perfil</button>\n<button class=\"c-btn c-btn--destructive\" type=\"button\" commandfor=\"dlg-delete\" command=\"show-modal\">Eliminar cuenta</button>\n\n<dialog class=\"c-dialog\" id=\"dlg-profile\" aria-labelledby=\"dlg-profile-title\" aria-describedby=\"dlg-profile-desc\" closedby=\"any\">\n  <form class=\"c-dialog__form\" method=\"dialog\">\n    <div class=\"c-dialog__header\">\n      <h2 class=\"c-dialog__title\" id=\"dlg-profile-title\">Editar perfil</h2>\n      <p class=\"c-dialog__description\" id=\"dlg-profile-desc\">Cambia tus datos y guarda cuando termines.</p>\n    </div>\n    <div class=\"c-dialog__panel\">\n      <div class=\"c-field\"><label class=\"c-label\" for=\"dlg-name\">Nombre</label><span class=\"c-input\"><input class=\"c-input__field\" id=\"dlg-name\" value=\"Ada Lovelace\" autofocus></span></div>\n    </div>\n    <div class=\"c-dialog__footer\">\n      <button class=\"c-btn c-btn--ghost\" value=\"cancel\" formnovalidate>Cancelar</button>\n      <button class=\"c-btn c-btn--primary\" value=\"save\">Guardar</button>\n    </div>\n    <button class=\"c-btn c-btn--ghost c-btn--icon c-dialog__close\" type=\"button\" commandfor=\"dlg-profile\" command=\"close\" aria-label=\"Cerrar\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg></button>\n  </form>\n</dialog>\n\n<dialog class=\"c-dialog\" id=\"dlg-delete\" role=\"alertdialog\" aria-labelledby=\"dlg-delete-title\" aria-describedby=\"dlg-delete-desc\">\n  <form class=\"c-dialog__form\" method=\"dialog\">\n    <div class=\"c-dialog__header\">\n      <h2 class=\"c-dialog__title\" id=\"dlg-delete-title\">¿Eliminar tu cuenta?</h2>\n      <p class=\"c-dialog__description\" id=\"dlg-delete-desc\">Se borran tus proyectos y no se puede deshacer.</p>\n    </div>\n    <div class=\"c-dialog__footer\">\n      <button class=\"c-btn c-btn--outline\" value=\"cancel\" autofocus>Cancelar</button>\n      <button class=\"c-btn c-btn--destructive\" value=\"delete\">Eliminar</button>\n    </div>\n  </form>\n</dialog>\n"
    },
    {
      "type": "css",
      "url": "https://componentes-lovat.vercel.app/raw/dialog/dialog.css",
      "content": "/* dialog · Componentes (MIRÓ Labs). Diseño de coss ui (MIT, © coss.com, antes Origin UI).\n   Generado por tools/build_css.py desde dialog.tw.json. No editar a mano. Necesita tokens.css. */\n.c-dialog__close{position:absolute;inset-inline-end:calc(var(--spacing)*2);top:calc(var(--spacing)*2)}\n.c-dialog{display:flex}\n.c-dialog__header{display:flex}\n.c-dialog__footer{display:flex}\n.c-dialog{max-height:100%;min-height:calc(var(--spacing)*0);width:100%;max-width:var(--container-lg);min-width:calc(var(--spacing)*0);transform-origin:50%;flex-direction:column}\n.c-dialog__header{flex-direction:column}\n.c-dialog__footer{flex-direction:column-reverse}\n.c-dialog__header{gap:calc(var(--spacing)*2)}\n.c-dialog__footer{gap:calc(var(--spacing)*2)}\n.c-dialog{border-radius:var(--radius-2xl);border-style:var(--tw-border-style);border-width:1px;background-color:var(--popover)}\n.c-dialog__header{padding:calc(var(--spacing)*6)}\n.c-dialog__panel{padding:calc(var(--spacing)*6)}\n.c-dialog__footer{padding-inline:calc(var(--spacing)*6)}\n.c-dialog__panel{padding-top:calc(var(--spacing)*1)}\n.c-dialog__footer{padding-top:calc(var(--spacing)*4);padding-bottom:calc(var(--spacing)*6)}\n.c-dialog__description{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}\n.c-dialog__title{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1;line-height:1;--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}\n.c-dialog__description{color:var(--muted-foreground)}\n.c-dialog{color:var(--popover-foreground);--tw-shadow-alpha:5%;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000000d),0 4px 6px -4px var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}\n@supports (color:lab(0% 0 0)){\n.c-dialog{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,lab(0% 0 0/.05)),0 4px 6px -4px var(--tw-shadow-color,lab(0% 0 0/.05))}\n}\n.c-dialog{transition-property:scale,opacity,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s;--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out);will-change:transform;--tw-outline-style:none;outline-style:none}\n.c-dialog:not(:is(.dark *)){background-clip:padding-box}\n.c-dialog:before{content:var(--tw-content);pointer-events:none;content:var(--tw-content);position:absolute;content:var(--tw-content);inset:calc(var(--spacing)*0);content:var(--tw-content);border-radius:calc(var(--radius-2xl) - 1px);content:var(--tw-content);--tw-shadow:0 1px var(--tw-shadow-color,#0000000a)}\n@supports (color:color-mix(in lab, red, red)){\n.c-dialog:before{--tw-shadow:0 1px var(--tw-shadow-color,color-mix(in oklab,var(--color-black)4%,transparent))}\n}\n.c-dialog:before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}\n@media not all and (min-width:40rem){\n.c-dialog{max-width:none;transform-origin:bottom;border-radius:0;border-inline-style:var(--tw-border-style);border-inline-width:0;border-top-style:var(--tw-border-style);border-top-width:1px;border-bottom-style:var(--tw-border-style);border-bottom-width:0}\n.c-dialog__header{padding-bottom:calc(var(--spacing)*4)}\n.c-dialog:before{content:var(--tw-content);display:none;content:var(--tw-content);border-radius:0}\n}\n@media (min-width:40rem){\n.c-dialog__footer{flex-direction:row;justify-content:flex-end;border-bottom-right-radius:calc(var(--radius-2xl) - 1px);border-bottom-left-radius:calc(var(--radius-2xl) - 1px)}\n}\n.c-dialog:is(.dark *):before{content:var(--tw-content);--tw-shadow:0 -1px var(--tw-shadow-color,#ffffff0f)}\n@supports (color:color-mix(in lab, red, red)){\n.c-dialog:is(.dark *):before{--tw-shadow:0 -1px var(--tw-shadow-color,color-mix(in oklab,var(--color-white)6%,transparent))}\n}\n.c-dialog:is(.dark *):before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}\n/* propio */\n.c-dialog{position:fixed;padding:0;margin:auto;max-height:calc(100dvh - 2rem);width:calc(100% - 2rem);color:var(--popover-foreground);opacity:0;scale:.98;transition:opacity .2s ease-in-out,scale .2s ease-in-out,translate .2s ease-in-out,overlay .2s allow-discrete,display .2s allow-discrete}\n.c-dialog[open]{opacity:1;scale:1}\n@starting-style{.c-dialog[open]{opacity:0;scale:.98}}\n.c-dialog::backdrop{background:color-mix(in oklab,#000 32%,transparent);backdrop-filter:blur(4px);opacity:0;transition:opacity .2s,overlay .2s allow-discrete,display .2s allow-discrete}\n.c-dialog[open]::backdrop{opacity:1}\n@starting-style{.c-dialog[open]::backdrop{opacity:0}}\n@media (width < 40rem){.c-dialog{width:100%;max-width:none;margin:auto 0 0;scale:1;translate:0 1rem}.c-dialog[open]{translate:0 0}@starting-style{.c-dialog[open]{translate:0 1rem}}}\n.c-dialog__close{position:absolute}\n.c-dialog__form{display:contents}\nhtml:has(.c-dialog[open]:modal){overflow:hidden}\n"
    },
    {
      "type": "js",
      "url": "https://componentes-lovat.vercel.app/raw/dialog/dialog.js",
      "content": "/* Diálogo: respaldo para navegadores sin commandfor ni closedby.\n   Con soporte nativo, este archivo no hace nada. */\n(function () {\n  const C = (window.Componentes = window.Componentes || {});\n  const hasCommand = 'command' in HTMLButtonElement.prototype;\n  const hasClosedBy = 'closedBy' in HTMLDialogElement.prototype;\n\n  function open(dialog) { try { if (!dialog.open) dialog.showModal(); } catch (e) { console.warn('[dialog]', e); } }\n  function close(dialog, value) { try { dialog.close(value); } catch (e) { console.warn('[dialog]', e); } }\n\n  if (!hasCommand) {\n    document.addEventListener('click', (e) => {\n      const btn = e.target.closest?.('button[commandfor]');\n      if (!btn) return;\n      const dialog = document.getElementById(btn.getAttribute('commandfor'));\n      if (!(dialog instanceof HTMLDialogElement)) return;\n      const cmd = btn.getAttribute('command');\n      if (cmd === 'show-modal') open(dialog);\n      else if (cmd === 'close' || cmd === 'request-close') close(dialog);\n    });\n  }\n\n  // closedby=\"any\": clic en el fondo cierra. Se mide el rectángulo, no el target,\n  // para que soltar el ratón fuera tras seleccionar texto dentro no cierre.\n  if (!hasClosedBy) {\n    document.addEventListener('pointerdown', (e) => {\n      const d = e.target;\n      if (!(d instanceof HTMLDialogElement) || !d.open || d.getAttribute('closedby') !== 'any') return;\n      const r = d.getBoundingClientRect();\n      const inside = e.clientX >= r.left && e.clientX <= r.right && e.clientY >= r.top && e.clientY <= r.bottom;\n      if (!inside) close(d);\n    });\n  }\n\n  C.dialog = { open, close };\n})();\n"
    },
    {
      "type": "standalone",
      "url": "https://componentes-lovat.vercel.app/r/dialog.html"
    }
  ],
  "tokensFile": "https://componentes-lovat.vercel.app/tokens.css",
  "darkTheme": "add class 'dark' to <html>",
  "contexto": "ambos",
  "densidad": "media",
  "tono": "sobria",
  "states": [
    "closed",
    "open"
  ],
  "use": {
    "es": [
      "Para confirmar algo irreversible.",
      "Para una tarea corta."
    ],
    "en": [
      "To confirm something irreversible.",
      "For a short task."
    ]
  },
  "avoid": {
    "es": [
      "Para avisar que algo salió bien: usa un aviso."
    ],
    "en": [
      "To say something worked: use a toast."
    ]
  },
  "a11y": {
    "roles": [
      "dialog",
      "alertdialog"
    ],
    "keyboard": [
      {
        "keys": "Esc",
        "es": "Cierra",
        "en": "Closes"
      },
      {
        "keys": "Tab",
        "es": "Recorre solo el diálogo",
        "en": "Cycles within the dialog"
      }
    ],
    "notes": {
      "es": [
        "<dialog> con showModal(): el resto de la página queda inerte.",
        "El foco vuelve al botón que lo abrió.",
        "Se abre con commandfor; dialog.js da respaldo donde no existe."
      ],
      "en": [
        "<dialog> with showModal(): the rest of the page is inert.",
        "Focus returns to the opening button.",
        "Opens with commandfor; dialog.js is the fallback."
      ]
    },
    "test": {
      "es": [
        "Abre «Editar perfil» y pulsa Esc: el foco vuelve al botón."
      ],
      "en": [
        "Open “Edit profile” and press Esc: focus returns to the button."
      ]
    }
  },
  "issues": {
    "es": [],
    "en": []
  },
  "credits": [
    {
      "source": "coss ui (MIT) · dialog.tsx",
      "url": "https://coss.com/ui"
    },
    {
      "source": "W3C WAI-ARIA APG, Dialog (Modal)",
      "url": "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/"
    }
  ],
  "changes": [
    {
      "date": "2026-09-29",
      "es": "Diseño de coss ui en HTML, CSS y JS sin dependencias",
      "en": "coss ui design in dependency-free HTML, CSS and JS"
    }
  ],
  "partes": [],
  "pieza": "https://componentes-lovat.vercel.app/r/dialog.html"
}
