{
  "$schema": "https://mian.ro/schema/v2/registry.json",
  "schemaVersion": "2.0.0",
  "generatedAt": "2026-10-02T13:14:06.957Z",
  "id": "date-range",
  "name": "Date range",
  "category": "Forms",
  "description": "Pick a period for a report: presets for the common ranges and two dates for anything else.",
  "tags": [
    "date range",
    "period picker",
    "last 7 days",
    "last 30 days",
    "report period",
    "from to",
    "analytics filter",
    "dashboard filter"
  ],
  "requiresJs": true,
  "license": "LicenseRef-MIAN-1.0",
  "composition": {
    "role": null,
    "intents": [
      "date range picker",
      "report period",
      "last 30 days filter",
      "from and to dates"
    ],
    "prominence": null,
    "density": null,
    "worksAfter": [],
    "worksBefore": [],
    "alternatives": [
      "calendar",
      "filter-bar"
    ],
    "avoid": null
  },
  "url": "https://mian.ro/components/date-range",
  "markdownUrl": "https://mian.ro/ai/components/date-range.md",
  "classes": [
    {
      "name": "mn-daterange",
      "description": "The control. Add data-mn-daterange."
    },
    {
      "name": "data-mn-range",
      "description": "On a preset button: the number of days, ending today."
    },
    {
      "name": "mn-daterange-custom",
      "description": "The two date inputs."
    }
  ],
  "accessibility": [
    "Presets are toggle buttons (aria-pressed) in a labelled group.",
    "Both dates are native date inputs with their own labels, so they work with any keyboard and locale.",
    "Listen for mn:change; detail has from, to and days."
  ],
  "examples": [
    {
      "title": "Report period",
      "description": null,
      "html": "<div class=\"mn-daterange\" data-mn-daterange>\n  <div class=\"mn-toggle-group\" role=\"group\" aria-label=\"Period\"><button type=\"button\" data-mn-range=\"7\" aria-pressed=\"false\">7 days</button><button type=\"button\" data-mn-range=\"30\" aria-pressed=\"true\">30 days</button><button type=\"button\" data-mn-range=\"90\" aria-pressed=\"false\">90 days</button></div>\n  <div class=\"mn-daterange-custom\"><input class=\"mn-input mn-input-sm\" type=\"date\" aria-label=\"From\"><span>to</span><input class=\"mn-input mn-input-sm\" type=\"date\" aria-label=\"To\"></div>\n</div>"
    }
  ],
  "css": ".mn-daterange { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; min-width: 0; }\n.mn-daterange-custom { display: flex; align-items: center; gap: .4rem; color: var(--mn-muted); font-size: var(--mn-text-sm); }\n.mn-daterange-custom .mn-input { width: auto; min-width: 8.5rem; }",
  "js": "/* <div class=\"mn-daterange\" data-mn-daterange>\n     <div class=\"mn-toggle-group\" role=\"group\" aria-label=\"Period\">\n       <button type=\"button\" data-mn-range=\"7\" aria-pressed=\"true\">7 days</button> …\n     </div>\n     <div class=\"mn-daterange-custom\"><input type=\"date\" aria-label=\"From\"> to <input type=\"date\" aria-label=\"To\"></div>\n   </div>\n   A preset fills both dates (ending today); editing a date clears the preset.\n   Emits mn:change { from, to, days } with ISO dates. */\nconst isoDay = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\nfunction setRange(scope, days, announce) {\n  const [from, to] = scope.querySelectorAll('input[type=\"date\"]');\n  const end = new Date(), start = new Date();\n  start.setDate(end.getDate() - (days - 1));\n  if (from && to) { from.value = isoDay(start); to.value = isoDay(end); }\n  scope.querySelectorAll('[data-mn-range]').forEach((b) => b.setAttribute('aria-pressed', String(Number(b.dataset.mnRange) === days)));\n  if (announce) emit(scope, 'change', { from: isoDay(start), to: isoDay(end), days });\n}\nregister('date-range', (root) => each(root, '[data-mn-daterange]', 'Range', (scope) => {\n  const on = scope.querySelector('[data-mn-range][aria-pressed=\"true\"]');\n  if (on) setRange(scope, Number(on.dataset.mnRange), false);\n  scope.addEventListener('click', (e) => { const b = e.target.closest('[data-mn-range]'); if (b && scope.contains(b)) setRange(scope, Number(b.dataset.mnRange), true); });\n  scope.addEventListener('change', (e) => {\n    if (e.target.type !== 'date') return;\n    const [from, to] = scope.querySelectorAll('input[type=\"date\"]');\n    if (from.value && to.value && from.value > to.value) (e.target === from ? to : from).value = e.target.value;\n    scope.querySelectorAll('[data-mn-range]').forEach((b) => b.setAttribute('aria-pressed', 'false'));\n    if (from.value && to.value) emit(scope, 'change', { from: from.value, to: to.value, days: Math.round((new Date(to.value) - new Date(from.value)) / 864e5) + 1 });\n  });\n}));",
  "install": {
    "css": "https://mian.ro/dist/mian.css",
    "js": "https://mian.ro/dist/mian.js",
    "registryItem": "https://mian.ro/r/date-range.json"
  }
}
