{
  "$schema": "https://mian.ro/schema/v2/registry.json",
  "schemaVersion": "2.0.0",
  "generatedAt": "2026-10-02T13:14:06.957Z",
  "id": "bulk-actions",
  "name": "Bulk actions",
  "category": "Data display",
  "description": "A bar that appears when rows are selected, the count, actions for the selection, and a way out, with select-all.",
  "tags": [
    "bulk actions",
    "selection bar",
    "batch actions",
    "multi select",
    "table selection",
    "admin",
    "archive selected",
    "delete selected"
  ],
  "requiresJs": true,
  "license": "LicenseRef-MIAN-1.0",
  "composition": {
    "role": null,
    "intents": [
      "bulk actions",
      "select rows",
      "batch edit",
      "archive selected",
      "selection toolbar"
    ],
    "prominence": null,
    "density": null,
    "worksAfter": [],
    "worksBefore": [],
    "alternatives": [],
    "avoid": null
  },
  "url": "https://mian.ro/components/bulk-actions",
  "markdownUrl": "https://mian.ro/ai/components/bulk-actions.md",
  "classes": [
    {
      "name": "mn-bulk",
      "description": "The scope: wraps the table (or list) and the bar. Add data-mn-bulk."
    },
    {
      "name": "mn-bulkbar",
      "description": "The bar; hidden until something is selected."
    },
    {
      "name": "data-mn-bulk-all",
      "description": "On the header checkbox: selects every row; shows indeterminate for some."
    },
    {
      "name": "data-mn-bulk-count",
      "description": "Where the number of selected rows is written."
    }
  ],
  "accessibility": [
    "The count is announced (the bar is role=\"status\" for its first line) when the selection changes.",
    "The header checkbox is labelled “Select all” and reports mixed selection as indeterminate.",
    "Destructive bulk actions name the number (“Delete 3”) and use a confirm dialog or an undo toast."
  ],
  "examples": [
    {
      "title": "Selectable table",
      "description": null,
      "html": "<div class=\"mn-bulk\" data-mn-bulk>\n  <div class=\"mn-bulkbar\" hidden><p role=\"status\"><strong data-mn-bulk-count>0</strong> selected</p><div class=\"mn-row\"><button class=\"mn-btn mn-btn-sm mn-btn-outline\" type=\"button\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 4v12M7 11l5 5 5-5\"/><path d=\"M4 16v3a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-3\"/></svg> Export</button><button class=\"mn-btn mn-btn-sm mn-btn-outline\" type=\"button\">Mark paid</button><button class=\"mn-btn mn-btn-sm mn-btn-outline mn-danger\" type=\"button\">Void</button></div></div>\n  <div class=\"mn-table-wrap\"><table class=\"mn-table mn-table-compact\">\n    <thead><tr><th scope=\"col\" style=\"width:2.5rem\"><input class=\"mn-checkbox\" type=\"checkbox\" data-mn-bulk-all aria-label=\"Select all invoices\"></th><th scope=\"col\">Invoice</th><th scope=\"col\">Customer</th><th scope=\"col\" class=\"mn-num\">Amount</th></tr></thead>\n    <tbody>\n      <tr><td><input class=\"mn-checkbox\" type=\"checkbox\" aria-label=\"Select INV-2041\"></td><td>INV-2041</td><td>Halden & Co</td><td class=\"mn-num\">€1,240.00</td></tr>\n      <tr><td><input class=\"mn-checkbox\" type=\"checkbox\" aria-label=\"Select INV-2040\"></td><td>INV-2040</td><td>Orbital GmbH</td><td class=\"mn-num\">€380.50</td></tr>\n      <tr><td><input class=\"mn-checkbox\" type=\"checkbox\" aria-label=\"Select INV-2039\"></td><td>INV-2039</td><td>Kestrel Ltd</td><td class=\"mn-num\">€4,900.00</td></tr>\n      <tr><td><input class=\"mn-checkbox\" type=\"checkbox\" aria-label=\"Select INV-2038\"></td><td>INV-2038</td><td>Marrow SRL</td><td class=\"mn-num\">€96.00</td></tr>\n    </tbody></table></div>\n</div>"
    }
  ],
  "css": ".mn-bulk { display: grid; gap: .6rem; min-width: 0; }\n.mn-bulkbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; padding: .5rem .5rem .5rem .9rem; border-radius: var(--mn-radius-box); background: var(--mn-fg); color: var(--mn-bg); animation: var(--mn-enter, none); }\n.mn-bulkbar[hidden] { display: none; }\n.mn-bulkbar p { margin: 0; font-size: var(--mn-text-sm); font-variant-numeric: tabular-nums; }\n.mn-bulkbar .mn-btn { --_bg: transparent; background: transparent; color: var(--mn-bg); border-color: color-mix(in oklab, var(--mn-bg) 35%, transparent); box-shadow: none; }\n.mn-bulkbar .mn-btn:hover { background: color-mix(in oklab, var(--mn-bg) 14%, transparent); }\n.mn-bulkbar .mn-btn:focus-visible { outline-color: var(--mn-bg); }\n.mn-bulk tr:has(> td > input:checked) > td { background: color-mix(in oklab, var(--mn-primary) 8%, transparent); }",
  "js": "/* <div class=\"mn-bulk\" data-mn-bulk> <div class=\"mn-bulkbar\" hidden>…\n   <strong data-mn-bulk-count></strong>…</div> <table>…<input type=\"checkbox\"\n   data-mn-bulk-all>…row checkboxes…</table></div>\n   Shows the bar while rows are selected, writes the count, keeps the\n   select-all box checked / indeterminate. Emits mn:change { count }. */\ndocument.addEventListener('change', (e) => {\n  const scope = e.target.closest('[data-mn-bulk]');\n  if (!scope || e.target.type !== 'checkbox') return;\n  const all = scope.querySelector('[data-mn-bulk-all]');\n  const rows = [...scope.querySelectorAll('tbody input[type=\"checkbox\"], .mn-list input[type=\"checkbox\"]')].filter((x) => !x.disabled);\n  if (e.target === all) rows.forEach((x) => { x.checked = all.checked; });\n  const count = rows.filter((x) => x.checked).length;\n  if (all) { all.checked = count > 0 && count === rows.length; all.indeterminate = count > 0 && count < rows.length; }\n  const bar = scope.querySelector('.mn-bulkbar');\n  if (bar) bar.hidden = count === 0;\n  scope.querySelectorAll('[data-mn-bulk-count]').forEach((n) => { n.textContent = count.toLocaleString(); });\n  emit(scope, 'change', { count });\n});",
  "install": {
    "css": "https://mian.ro/dist/mian.css",
    "js": "https://mian.ro/dist/mian.js",
    "registryItem": "https://mian.ro/r/bulk-actions.json"
  }
}
