{
  "patterns": [
    {
      "id": "action-feedback",
      "intent": "Transient confirmation after a completed action, with an optional undo affordance",
      "match": [
        "toast",
        "snackbar",
        "action feedback",
        "confirmation message",
        "undo toast"
      ],
      "compose": {
        "component": "Toast",
        "props": {
          "variant": "{param:variant}"
        },
        "slots": {
          "body": [
            "{content:message}"
          ],
          "action": [
            {
              "component": "Button",
              "props": {
                "variant": "ghost"
              },
              "content": "undo-label"
            }
          ]
        }
      },
      "parameters": [
        {
          "key": "variant",
          "ask": "What kind of outcome is being confirmed?",
          "options": [
            "success",
            "warning",
            "danger",
            "neutral"
          ],
          "default": "success"
        }
      ],
      "content": {
        "message": "[what just happened]",
        "undo-label": "Undo"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toast action={<Button variant=\"ghost\">Undo</Button>} variant=\"success\">[what just happened]</Toast>\n"
    },
    {
      "id": "bulk-action-bar",
      "intent": "Bar that appears when table rows are selected: selection count, bulk actions, and a clear-selection control",
      "match": [
        "bulk actions",
        "selection bar",
        "batch actions",
        "selected rows toolbar"
      ],
      "compose": {
        "component": "Toolbar",
        "props": {
          "gap": 12
        },
        "slots": {
          "body": [
            {
              "component": "Tag",
              "props": {
                "variant": "accent",
                "subtle": true
              },
              "content": "count-label"
            },
            {
              "component": "Button",
              "props": {
                "variant": "neutral"
              },
              "content": "export-label"
            },
            {
              "component": "Button",
              "props": {
                "variant": "danger-subtle"
              },
              "content": "delete-label"
            },
            {
              "component": "Button",
              "props": {
                "variant": "ghost"
              },
              "content": "clear-label"
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "count-label": "[n] selected",
        "export-label": "Export",
        "delete-label": "Delete",
        "clear-label": "Clear selection"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toolbar\n  gap={12}\n>\n  <Tag subtle={true} variant=\"accent\">[n] selected</Tag>\n  <Button variant=\"neutral\">Export</Button>\n  <Button variant=\"danger-subtle\">Delete</Button>\n  <Button variant=\"ghost\">Clear selection</Button>\n</Toolbar>\n"
    },
    {
      "id": "data-table",
      "intent": "Sortable, selectable table of records with numeric columns and a per-row actions menu — compose the row menu from the row-actions pattern",
      "match": [
        "data table",
        "transactions table",
        "sortable table",
        "records table",
        "list of transactions"
      ],
      "compose": {
        "component": "Table",
        "props": {
          "selectable": true,
          "sortable": true
        },
        "slots": {
          "body": [
            {
              "component": "TableHead",
              "slots": {
                "body": [
                  {
                    "component": "TableRow",
                    "slots": {
                      "body": [
                        {
                          "component": "TableHeaderCell",
                          "props": {
                            "sortKey": "date"
                          },
                          "content": "date-label"
                        },
                        {
                          "component": "TableHeaderCell",
                          "props": {
                            "sortKey": "payee"
                          },
                          "content": "payee-label"
                        },
                        {
                          "component": "TableHeaderCell",
                          "props": {
                            "sortKey": "amount",
                            "numeric": true
                          },
                          "content": "amount-label"
                        },
                        {
                          "component": "TableHeaderCell",
                          "content": "actions-label"
                        }
                      ]
                    }
                  }
                ]
              }
            },
            {
              "component": "TableBody",
              "slots": {
                "body": [
                  {
                    "component": "TableRow",
                    "props": {
                      "rowId": "row-id"
                    },
                    "slots": {
                      "body": [
                        {
                          "component": "TableCell",
                          "content": "date-cell"
                        },
                        {
                          "component": "TableCell",
                          "content": "payee-cell"
                        },
                        {
                          "component": "TableCell",
                          "props": {
                            "numeric": true
                          },
                          "content": "amount-cell"
                        },
                        {
                          "component": "TableCell",
                          "content": "actions-cell"
                        }
                      ]
                    }
                  }
                ]
              }
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "date-label": "Date",
        "payee-label": "Payee",
        "amount-label": "Amount",
        "actions-label": "[a visible \"Actions\" header — the column needs an accessible name, so never an empty th]",
        "date-cell": "[one row per record]",
        "payee-cell": "[the record's payee]",
        "amount-cell": "[numeric columns align right and use tabular figures]",
        "actions-cell": "[the row-actions menu — compose it from the row-actions pattern]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Table\n  selectable={true}\n  sortable={true}\n>\n  <TableHead>\n    <TableRow>\n      <TableHeaderCell sortKey=\"date\">Date</TableHeaderCell>\n      <TableHeaderCell sortKey=\"payee\">Payee</TableHeaderCell>\n      <TableHeaderCell numeric={true} sortKey=\"amount\">Amount</TableHeaderCell>\n      <TableHeaderCell>[a visible \"Actions\" header — the column needs an accessible name, so never an empty th]</TableHeaderCell>\n    </TableRow>\n  </TableHead>\n  <TableBody>\n    <TableRow\n      rowId=\"row-id\"\n    >\n      <TableCell>[one row per record]</TableCell>\n      <TableCell>[the record's payee]</TableCell>\n      <TableCell numeric={true}>[numeric columns align right and use tabular figures]</TableCell>\n      <TableCell>[the row-actions menu — compose it from the row-actions pattern]</TableCell>\n    </TableRow>\n  </TableBody>\n</Table>\n"
    },
    {
      "id": "date-range-filter",
      "intent": "From/to date pair for narrowing a dated list — native date inputs, no calendar widget",
      "match": [
        "date range filter",
        "from to date",
        "date filter",
        "period filter",
        "filter by date"
      ],
      "compose": {
        "component": "Toolbar",
        "props": {
          "gap": 12
        },
        "slots": {
          "body": [
            {
              "component": "Field",
              "slots": {
                "label": [
                  "{content:from-label}"
                ],
                "body": [
                  {
                    "component": "Input",
                    "props": {
                      "type": "date",
                      "size": 32
                    }
                  }
                ]
              }
            },
            {
              "component": "Field",
              "slots": {
                "label": [
                  "{content:to-label}"
                ],
                "body": [
                  {
                    "component": "Input",
                    "props": {
                      "type": "date",
                      "size": 32
                    }
                  }
                ]
              }
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "from-label": "From",
        "to-label": "To"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toolbar\n  gap={12}\n>\n  <Field\n    label=\"From\"\n  >\n    <Input size={32} type=\"date\" />\n  </Field>\n  <Field\n    label=\"To\"\n  >\n    <Input size={32} type=\"date\" />\n  </Field>\n</Toolbar>\n"
    },
    {
      "id": "destructive-confirm",
      "intent": "Dialog confirming a destructive action",
      "match": [
        "delete confirmation",
        "are you sure",
        "destructive dialog",
        "confirm delete"
      ],
      "compose": {
        "component": "Dialog",
        "slots": {
          "title": [
            "{content:title}"
          ],
          "body": [
            "{content:consequence}"
          ],
          "footer": [
            {
              "component": "Button",
              "props": {
                "variant": "ghost",
                "size": "{param:size}"
              },
              "content": "cancel-label"
            },
            {
              "component": "Button",
              "props": {
                "variant": "danger",
                "size": "{param:size}"
              },
              "content": "confirm-label"
            }
          ]
        }
      },
      "parameters": [
        {
          "key": "size",
          "ask": "Button size?",
          "options": [
            32,
            40
          ],
          "default": 32
        }
      ],
      "content": {
        "title": "[Delete the object?]",
        "consequence": "[what is permanently lost]",
        "cancel-label": "Cancel",
        "confirm-label": "[verb the object]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Dialog\n  footer={<>\n    <Button size={32} variant=\"ghost\">Cancel</Button>\n    <Button size={32} variant=\"danger\">[verb the object]</Button>\n  </>}\n  title=\"[Delete the object?]\"\n>\n  [what is permanently lost]\n</Dialog>\n"
    },
    {
      "id": "detail-drawer",
      "intent": "Side sheet showing one record's detail, opened from a table row, with its primary actions in a footer",
      "match": [
        "detail drawer",
        "side sheet",
        "row detail",
        "slide-over",
        "record detail panel"
      ],
      "compose": {
        "component": "Dialog",
        "props": {
          "placement": "{param:placement}"
        },
        "slots": {
          "title": [
            "{content:title}"
          ],
          "body": [
            {
              "component": "DescriptionList",
              "props": {
                "layout": "inline"
              },
              "slots": {
                "body": [
                  {
                    "component": "DescriptionItem",
                    "props": {
                      "term": "{content:field-1-term}"
                    },
                    "content": "field-1-value"
                  },
                  {
                    "component": "DescriptionItem",
                    "props": {
                      "term": "{content:field-2-term}"
                    },
                    "content": "field-2-value"
                  }
                ]
              }
            }
          ],
          "footer": [
            {
              "component": "Button",
              "props": {
                "variant": "accent"
              },
              "content": "primary-label"
            },
            {
              "component": "Button",
              "props": {
                "variant": "neutral"
              },
              "content": "dismiss-label"
            }
          ]
        }
      },
      "parameters": [
        {
          "key": "placement",
          "ask": "Which edge should the drawer open from?",
          "options": [
            "inline-end",
            "inline-start"
          ],
          "default": "inline-end"
        }
      ],
      "content": {
        "title": "[record title]",
        "primary-label": "Save",
        "dismiss-label": "Close",
        "field-1-term": "Date",
        "field-1-value": "[the record's value for this field]",
        "field-2-term": "Amount",
        "field-2-value": "[one DescriptionItem per field you want to show]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Dialog\n  footer={<>\n    <Button variant=\"accent\">Save</Button>\n    <Button variant=\"neutral\">Close</Button>\n  </>}\n  placement=\"inline-end\"\n  title=\"[record title]\"\n>\n  <DescriptionList\n    layout=\"inline\"\n  >\n    <DescriptionItem term=\"Date\">[the record's value for this field]</DescriptionItem>\n    <DescriptionItem term=\"Amount\">[one DescriptionItem per field you want to show]</DescriptionItem>\n  </DescriptionList>\n</Dialog>\n"
    },
    {
      "id": "empty-state",
      "intent": "Placeholder shown when a list has no results, distinguishing an empty filter from an empty dataset",
      "match": [
        "empty state",
        "no results",
        "nothing here",
        "zero state",
        "no data"
      ],
      "compose": {
        "component": "Panel",
        "props": {
          "padding": 24
        },
        "slots": {
          "body": [
            "{content:headline}",
            "{content:explanation}",
            {
              "component": "Button",
              "props": {
                "variant": "neutral"
              },
              "content": "reset-label"
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "headline": "[nothing matches these filters]",
        "explanation": "[say whether the dataset is empty or the filters are too narrow]",
        "reset-label": "Clear filters"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Panel\n  padding={24}\n>\n  [nothing matches these filters]\n  [say whether the dataset is empty or the filters are too narrow]\n  <Button variant=\"neutral\">Clear filters</Button>\n</Panel>\n"
    },
    {
      "id": "filter-toolbar",
      "intent": "Toolbar of filter controls: search, category select, active-filter tags — controls are named by aria-label/placeholder, not a visible label, so no Field (contrast table-pagination)",
      "match": [
        "filter toolbar",
        "filter bar",
        "search and filter",
        "faceted filters"
      ],
      "compose": {
        "component": "Toolbar",
        "slots": {
          "body": [
            {
              "component": "Input",
              "props": {
                "type": "search",
                "aria-label": "{content:search-label}",
                "placeholder": "{content:search-placeholder}"
              }
            },
            {
              "component": "Select",
              "props": {
                "aria-label": "{content:select-label}"
              }
            },
            {
              "component": "Tag",
              "content": "example-filter"
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "search-label": "Search transactions",
        "search-placeholder": "Search transactions",
        "select-label": "Category",
        "example-filter": "[active filter]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toolbar>\n  <Input aria-label=\"Search transactions\" placeholder=\"Search transactions\" type=\"search\" />\n  <Select aria-label=\"Category\" />\n  <Tag>[active filter]</Tag>\n</Toolbar>\n"
    },
    {
      "id": "row-actions",
      "intent": "List or table row with an icon-only actions menu, including a destructive item — hand the destructive item's confirmation off to the destructive-confirm pattern",
      "match": [
        "row actions",
        "per-row actions",
        "table row menu",
        "actions menu",
        "row action list"
      ],
      "compose": {
        "component": "Menu",
        "props": {
          "placement": "{param:placement}",
          "aria-label": "{content:trigger-label}"
        },
        "slots": {
          "trigger": [
            {
              "component": "IconButton",
              "props": {
                "variant": "ghost",
                "aria-label": "{content:trigger-label}"
              },
              "content": "trigger-icon"
            }
          ],
          "body": [
            {
              "component": "MenuItem",
              "content": "edit-label"
            },
            {
              "component": "MenuItem",
              "content": "duplicate-label"
            },
            {
              "component": "MenuSeparator"
            },
            {
              "component": "MenuItem",
              "props": {
                "variant": "danger"
              },
              "content": "delete-label"
            }
          ]
        }
      },
      "parameters": [
        {
          "key": "placement",
          "ask": "Which side should the menu open on?",
          "options": [
            "bottom-start",
            "bottom-end"
          ],
          "default": "bottom-end"
        }
      ],
      "content": {
        "trigger-label": "Actions",
        "trigger-icon": "the ellipsis glyph",
        "edit-label": "Edit",
        "duplicate-label": "Duplicate",
        "delete-label": "Delete"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Menu\n  aria-label=\"Actions\"\n  placement=\"bottom-end\"\n  trigger={<IconButton aria-label=\"Actions\" variant=\"ghost\"><IconMoreHorizontal /></IconButton>}\n>\n  <MenuItem>Edit</MenuItem>\n  <MenuItem>Duplicate</MenuItem>\n  <MenuSeparator />\n  <MenuItem variant=\"danger\">Delete</MenuItem>\n</Menu>\n"
    },
    {
      "id": "settings-form-row",
      "intent": "Labeled settings row: a self-labeled control with a group label and helper text",
      "match": [
        "settings row",
        "form row",
        "labeled switch",
        "preference toggle",
        "settings form"
      ],
      "compose": {
        "component": "Field",
        "props": {
          "group": true
        },
        "slots": {
          "label": [
            "{content:row-label}"
          ],
          "body": [
            {
              "component": "Switch",
              "content": "control-label"
            }
          ],
          "description": [
            "{content:row-description}"
          ]
        }
      },
      "parameters": [],
      "content": {
        "row-label": "[setting name]",
        "control-label": "[what turning it on does]",
        "row-description": "[one-line consequence of the setting]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Field\n  description=\"[one-line consequence of the setting]\"\n  group={true}\n  label=\"[setting name]\"\n>\n  <Switch>[what turning it on does]</Switch>\n</Field>\n"
    },
    {
      "id": "summary-tiles",
      "intent": "Row of headline figures above a ledger — balances or totals, one Card per figure",
      "match": [
        "summary tiles",
        "stat cards",
        "kpi row",
        "balance cards",
        "totals row"
      ],
      "compose": {
        "component": "Toolbar",
        "props": {
          "gap": 16
        },
        "slots": {
          "body": [
            {
              "component": "Card",
              "props": {
                "variant": "stacked"
              },
              "content": "tile-note"
            },
            {
              "component": "Card",
              "props": {
                "variant": "stacked"
              },
              "content": "tile-note"
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "tile-note": "[label above, figure below]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toolbar\n  gap={16}\n>\n  <Card variant=\"stacked\">[label above, figure below]</Card>\n  <Card variant=\"stacked\">[label above, figure below]</Card>\n</Toolbar>\n"
    },
    {
      "id": "tabbed-workspace",
      "intent": "Tab set switching between sibling views of the same workspace, such as accounts or saved filters",
      "match": [
        "tabs",
        "tabbed view",
        "switch between accounts",
        "tab bar",
        "segmented views"
      ],
      "compose": {
        "component": "Tabs",
        "props": {
          "orientation": "{param:orientation}"
        },
        "slots": {
          "body": [
            {
              "component": "TabList",
              "props": {
                "aria-label": "Views"
              },
              "slots": {
                "body": [
                  {
                    "component": "Tab",
                    "props": {
                      "value": "all"
                    },
                    "content": "first-label"
                  },
                  {
                    "component": "Tab",
                    "props": {
                      "value": "flagged"
                    },
                    "content": "second-label"
                  }
                ]
              }
            },
            {
              "component": "TabPanel",
              "props": {
                "value": "all"
              },
              "content": "first-panel"
            },
            {
              "component": "TabPanel",
              "props": {
                "value": "flagged"
              },
              "content": "second-panel"
            }
          ]
        }
      },
      "parameters": [
        {
          "key": "orientation",
          "ask": "How should the tab list be laid out?",
          "options": [
            "horizontal",
            "vertical"
          ],
          "default": "horizontal"
        }
      ],
      "content": {
        "first-label": "All",
        "second-label": "Flagged",
        "first-panel": "[the default view]",
        "second-panel": "[the second view; one panel per tab, paired by value]"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Tabs\n  orientation=\"horizontal\"\n>\n  <TabList\n    aria-label=\"Views\"\n  >\n    <Tab value=\"all\">All</Tab>\n    <Tab value=\"flagged\">Flagged</Tab>\n  </TabList>\n  <TabPanel value=\"all\">[the default view]</TabPanel>\n  <TabPanel value=\"flagged\">[the second view; one panel per tab, paired by value]</TabPanel>\n</Tabs>\n"
    },
    {
      "id": "table-pagination",
      "intent": "Page-size selector and page range control beneath a data table",
      "match": [
        "pagination",
        "table pagination",
        "page controls",
        "rows per page",
        "paging"
      ],
      "compose": {
        "component": "Toolbar",
        "props": {
          "gap": 12
        },
        "slots": {
          "body": [
            {
              "component": "Field",
              "slots": {
                "label": [
                  "{content:page-size-label}"
                ],
                "body": [
                  {
                    "component": "Select",
                    "props": {
                      "size": 32
                    }
                  }
                ]
              }
            },
            {
              "component": "Pagination"
            }
          ]
        }
      },
      "parameters": [],
      "content": {
        "page-size-label": "Rows per page"
      },
      "gaps": [],
      "blocked": false,
      "preset": "<Toolbar\n  gap={12}\n>\n  <Field\n    label=\"Rows per page\"\n  >\n    <Select size={32} />\n  </Field>\n  <Pagination />\n</Toolbar>\n"
    }
  ]
}
