{
  "$schema": "https://mian.ro/schema/v2/registry.json",
  "schemaVersion": "2.0.0",
  "generatedAt": "2026-10-02T13:14:06.957Z",
  "id": "loader",
  "name": "Loader",
  "category": "Feedback",
  "description": "Eight loading indicators, dots, bars, wave, grid, pulse, orbit, ring and a top-of-page line, in the current colour.",
  "tags": [
    "loader",
    "loading",
    "spinner",
    "busy",
    "progress",
    "activity indicator",
    "dots",
    "equalizer",
    "skeleton",
    "wait"
  ],
  "requiresJs": false,
  "license": "LicenseRef-MIAN-1.0",
  "composition": {
    "role": null,
    "intents": [
      "loading animation",
      "page loader",
      "loading dots",
      "progress line"
    ],
    "prominence": null,
    "density": null,
    "worksAfter": [],
    "worksBefore": [],
    "alternatives": [
      "spinner",
      "skeleton"
    ],
    "avoid": null
  },
  "url": "https://mian.ro/components/loader",
  "markdownUrl": "https://mian.ro/ai/components/loader.md",
  "classes": [
    {
      "name": "mn-loader",
      "description": "The loader, with one variant class. Size with mn-loader-sm / -lg or --_s; colour with a colour role or currentColor."
    },
    {
      "name": "mn-loader-dots · -bars · -wave · -grid",
      "description": "Need child <i> elements: 3 dots, 5 bars, 5 wave, 9 grid."
    },
    {
      "name": "mn-loader-pulse · -ring",
      "description": "No children."
    },
    {
      "name": "mn-loader-orbit",
      "description": "Two <i> children."
    },
    {
      "name": "mn-loader-line",
      "description": "A full-width line for the top of a page or a card."
    }
  ],
  "accessibility": [
    "Give the loader role=\"status\" and an aria-label (“Loading invoices”), or put visible text next to it.",
    "Under prefers-reduced-motion every loader slows to a gentle 3-second cycle.",
    "For waits over a few seconds, prefer a progress bar with a value, or a skeleton."
  ],
  "examples": [
    {
      "title": "Loaders",
      "description": "Large size. Each takes the colour of a colour role or of the text around it.",
      "html": "<span class=\"mn-loader mn-loader-lg mn-loader-dots\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-bars\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i><i></i><i></i></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-wave mn-accent\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i><i></i><i></i></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-grid\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-pulse mn-info\" role=\"status\" aria-label=\"Loading\"></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-orbit\" role=\"status\" aria-label=\"Loading\"><i></i><i></i></span>\n<span class=\"mn-loader mn-loader-lg mn-loader-ring mn-success\" role=\"status\" aria-label=\"Loading\"></span>"
    },
    {
      "title": "Sizes and a line",
      "description": null,
      "html": "<div class=\"mn-stack\" style=\"max-width:24rem\">\n  <div class=\"mn-row\" style=\"--mn-gap:1.25rem\"><span class=\"mn-loader mn-loader-dots mn-loader-sm\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i></span><span class=\"mn-loader mn-loader-dots\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i></span><span class=\"mn-loader mn-loader-dots mn-loader-lg\" role=\"status\" aria-label=\"Loading\"><i></i><i></i><i></i></span></div>\n  <div class=\"mn-card\"><span class=\"mn-loader mn-loader-line\" role=\"status\" aria-label=\"Loading invoices\"></span><div class=\"mn-card-body mn-muted\">Loading invoices…</div></div>\n</div>"
    }
  ],
  "css": ".mn-loader { --_s: 1.5rem; position: relative; display: inline-flex; align-items: center; justify-content: center; gap: calc(var(--_s) * .14); width: var(--_s); height: var(--_s); color: var(--_c, var(--mn-primary)); vertical-align: middle; flex: none; }\n.mn-loader-sm { --_s: 1rem; } .mn-loader-lg { --_s: 2.5rem; }\n.mn-loader > i { display: block; flex: none; background: currentColor; }\n/* dots */\n.mn-loader-dots { width: calc(var(--_s) * 1.8); }\n.mn-loader-dots > i { width: calc(var(--_s) * .3); height: calc(var(--_s) * .3); border-radius: 50%; animation: mn-ld-bounce 1s ease-in-out infinite; }\n/* bars (equaliser) */\n.mn-loader-bars > i { width: calc(var(--_s) * .13); height: 100%; border-radius: 2px; transform-origin: 50% 100%; animation: mn-ld-eq 1s ease-in-out infinite; }\n/* wave */\n.mn-loader-wave { width: calc(var(--_s) * 2); }\n.mn-loader-wave > i { width: calc(var(--_s) * .22); height: calc(var(--_s) * .22); border-radius: 50%; animation: mn-ld-wave 1.2s ease-in-out infinite; }\n.mn-loader > i:nth-child(2) { animation-delay: .12s; } .mn-loader > i:nth-child(3) { animation-delay: .24s; } .mn-loader > i:nth-child(4) { animation-delay: .36s; } .mn-loader > i:nth-child(5) { animation-delay: .48s; }\n/* grid of nine squares */\n.mn-loader-grid { display: inline-grid; grid-template-columns: repeat(3, 1fr); gap: calc(var(--_s) * .08); }\n.mn-loader-grid > i { width: 100%; aspect-ratio: 1; border-radius: 2px; animation: mn-ld-fade 1.2s ease-in-out infinite; }\n.mn-loader-grid > i:nth-child(3n+2) { animation-delay: .15s; } .mn-loader-grid > i:nth-child(3n) { animation-delay: .3s; }\n.mn-loader-grid > i:nth-child(n+4) { animation-delay: .2s; } .mn-loader-grid > i:nth-child(n+7) { animation-delay: .4s; }\n/* pulse */\n.mn-loader-pulse::before, .mn-loader-pulse::after { content: \"\"; position: absolute; inset: 0; border-radius: 50%; background: currentColor; animation: mn-ld-pulse 1.6s cubic-bezier(.2, .6, .4, 1) infinite; }\n.mn-loader-pulse::after { animation-delay: .8s; }\n/* orbit */\n.mn-loader-orbit { border-radius: 50%; box-shadow: inset 0 0 0 2px color-mix(in oklab, currentColor 20%, transparent); animation: mn-spin 1.1s linear infinite; }\n.mn-loader-orbit > i { position: absolute; top: calc(var(--_s) * -.08); left: 50%; width: calc(var(--_s) * .26); height: calc(var(--_s) * .26); margin-left: calc(var(--_s) * -.13); border-radius: 50%; }\n.mn-loader-orbit > i + i { top: auto; bottom: calc(var(--_s) * -.08); opacity: .45; }\n/* ring with a fading tail */\n.mn-loader-ring { border-radius: 50%; background: conic-gradient(from 0deg, transparent 10%, currentColor); -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px)); mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px)); animation: mn-spin .9s linear infinite; }\n/* top-of-page line */\n.mn-loader-line { display: block; width: 100%; height: 3px; overflow: hidden; border-radius: 999px; background: color-mix(in oklab, currentColor 16%, transparent); }\n.mn-loader-line::after { content: \"\"; position: absolute; top: 0; bottom: 0; width: 35%; border-radius: inherit; background: currentColor; animation: mn-ld-line 1.3s cubic-bezier(.6, 0, .4, 1) infinite; }\n@keyframes mn-ld-bounce { 0%, 80%, 100% { transform: scale(.5); opacity: .45; } 40% { transform: scale(1); opacity: 1; } }\n@keyframes mn-ld-eq { 0%, 100% { transform: scaleY(.3); } 50% { transform: scaleY(1); } }\n@keyframes mn-ld-wave { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(calc(var(--_s) * -.35)); } }\n@keyframes mn-ld-fade { 0%, 100% { opacity: .2; transform: scale(.8); } 50% { opacity: 1; transform: scale(1); } }\n@keyframes mn-ld-pulse { from { transform: scale(0); opacity: .8; } to { transform: scale(1); opacity: 0; } }\n@keyframes mn-ld-line { from { left: -35%; } to { left: 100%; } }\n@media (prefers-reduced-motion: reduce) {\n  .mn-loader, .mn-loader > i, .mn-loader::before, .mn-loader::after { animation-duration: 3s !important; }",
  "js": null,
  "install": {
    "css": "https://mian.ro/dist/mian.css",
    "js": null,
    "registryItem": "https://mian.ro/r/loader.json"
  }
}
