A pattern is a named composition of two or more components, with rules, but no export. It
sits between Components and Views in Titan’s four-tier ladder: a pattern tells you which
components to combine, in what order, and how they behave together, but it ships nothing of
its own — no import, no props API, no tokens. If you can import it, it’s a Component. If it
defines a page’s regions, it’s a View. If it’s a recurring, rule-bound arrangement of existing
components that answers to neither of those tests, it’s a Pattern.Patterns exist because component pages answer “what does a Button do” and views answer “what
regions does this page have,” and neither answers “how do these five components work together
to let someone delete a campaign safely” or “what happens across a whole form when three
fields are invalid at once.” That composition-level question is this section’s job.
The reader’s intent, not the component name, is the useful index. Use this table before the
card grid below — it is written in the words of the problem, not the solution.
Components, the units these compositions are
built from. Views, which decide the page regions a
pattern is placed into. AI Experience, the
sibling section for anything in this composition tier where the output isn’t deterministic —
several patterns here have an AI-driven counterpart there (Empty & zero states pairs with
Welcome / empty state;
Filtering & search pairs with Search).
A pattern is defined by what it lacks, not by what it contains. Any of these could be
redescribed as “a Card, a Button, and some state” — that description is true of nearly every
screen in the product and explains nothing. What makes something worth a page here is a
recurring decision — when to skip the pattern entirely, what order the pieces go in, what
happens on failure — not the inventory of components involved.Proposal-first is the honest way to grow this section without Titan. Waiting for every
pattern to be confirmed against a shipped screen before writing it down means the vocabulary
for “how does Invoca do bulk selection” doesn’t exist until someone happens to build bulk
selection first and document it after. Writing the proposal first gives the next person
building one a starting point to correct, instead of a blank page.
Sign-off state per pattern. A pattern marked Proposal is still what to build to; it means
the rule has not yet been checked against a shipped screen, not that it is optional.
Pattern
Decided for Invoca?
Destructive confirmation
Proposal — reviewed once
Bulk selection
Proposal
Empty & zero states
Proposal
Error handling
Proposal
Filtering & search
Proposal
Form validation
Proposal
Footers
Proposal
Inline editing
Proposal
Loading & skeletons
Proposal
Notifications
Proposal
Progressive disclosure
Proposal
CRUD (Create, Read, Update, Delete)
Proposal — varies by operation; see its own status block
Destructive confirmation
How to ask before an action that destroys work — and when not to ask at all.
Form validation
When an error appears, where it renders, and how many places say it at once.
Empty & zero states
Nothing here yet, versus nothing matched — and why a failed load is neither.
Loading & skeletons
Matching a loading placeholder to the shape of what's coming — and when to reach for a spinner or a progress bar instead.
Error handling
Where a deterministic action or load failure is shown, and what it must tell the reader next.
Filtering and search
Narrowing a list down to what someone wants, with deterministic filters and a search box — not natural-language interpretation.
Bulk selection
Selecting many rows at once and acting on them as a single batch.
Inline editing
Editing a value in place, and when that stops being the right idea.
Progressive disclosure
Keeping a screen simple without hiding what people actually need.
Notifications
Toast, banner, or alert — and what decides which one tells the reader something happened.
Footers
Which surface owns the commit: how to decide where a footer belongs, on views, containers, dialogs, and drawers.
The decision tree for where a new object gets created — full page, modal, drawer, or inline — based on permanence, density, and continuity, not habit.
Read
Viewing one object in detail — full Detail view, Drawer preview, or inline expansion — based on how much the reader needs right now.
Update
What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.
Last modified on September 17, 2026
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Invoca","colors":{"primary":"#00A87F","light":"#00A87F","dark":"#0EEEB7"},"logo":{"light":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/light.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=3ed629c5be28d08bd1a6580e72b6dbfa","dark":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/dark.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=b64ce8e5cfa4f8c7893b2738e8131f45","href":"https://www.invoca.com/"},"favicon":"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/favicon.png?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=c846713bb1afdf274154a01d7e9abb8d","appearance":{"default":"light"},"background":{"decoration":"gradient"},"navbar":{"primary":{"type":"button","label":"Invoca Academy","href":"https://academy.invoca.com/"}},"footer":{"socials":{"linkedin":"https://www.linkedin.com/company/invoca-com","youtube":"https://www.youtube.com/channel/UCLQwNQFnN1OV1ACnlXICPKw"}},"fonts":{"body":{"family":"Gt America","source":"https://cdn.prod.website-files.com/5d82e225060d003d65ddae98/677d87009656fca63c0c7d8f_GT-America-Standard-Regular.woff2","format":"woff2"}},"contextual":{"options":["copy","download-pdf","view","assistant","chatgpt","claude","perplexity"],"display":"header"},"metadata":{"timestamp":true},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"invoca-5bd45748","hasAudioNarration":false,"actualSubdomain":"invoca-5bd45748","customDomains":["docs.invoca.com"],"gitSource":{"type":"github","owner":"invoca","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae8bdbaca78e468455a6b97","collectionId":"54b26950-9181-41ce-985a-32d474ce8dd0","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae8bdbaca78e468455a6b97"},"feedback":{"thumbs":true,"agentFeedback":true,"contextualFeedback":{"allowEmail":false}},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED","enabled":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae8bdbaca78e468455a6b97","clientVersion":"0.0.4045","searchFilterCounts":[{"language":"default","tag":"Invoca Docs","count":666},{"language":"default","tag":"Guide","count":665},{"language":"default","tag":"Developer","count":191},{"language":"default","tag":"Integrations","count":184},{"language":"default","tag":"Invoca Design System","count":163},{"language":"default","tag":"API Documentation","count":151},{"language":"default","tag":"Campaign \u0026 Call Handling","count":127},{"language":"default","tag":"Insights \u0026 Analytics","count":101},{"language":"default","tag":"Network Integration","count":99},{"language":"default","tag":"Components","count":75}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":true,"enableContextualStarterQuestions":true,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"type":"link","url":"https://support.invoca.com/s/contactsupport"}},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":".custom-card .card img{width:60%;padding:1rem;margin:0 auto}a[href=\"https://academy.invoca.com/\"] span.absolute{background-color:#004030}#assistant-entry,#assistant-entry-mobile{background-color:#00a87f;border-color:#00a87f}#assistant-entry-mobile:hover,#assistant-entry:hover{background-color:#009973}#assistant-entry span,#assistant-entry svg,#assistant-entry-mobile span,#assistant-entry-mobile svg{color:#fff}.ivk-home{--ivk-forest:#0A231E;--ivk-footer-bg:#004030;--ivk-accent:#00A87F;--ivk-ink:#1F2121;--ivk-muted:#626464;--ivk-line:#E7E9E4;--ivk-bg:#FFFFFF;--ivk-sand:#F8FAF1;--ivk-banner:#D1FFD1;--ivk-card:#FFFFFF;--ivk-radius-btn:6px;--ivk-radius-card:16px;color:var(--ivk-ink);width:100%;max-width:1600px;margin:0 auto;padding:2rem clamp(1.25rem,4vw,4rem) 4rem}.dark .ivk-home,:root[data-theme=dark] .ivk-home{--ivk-bg:#10201B;--ivk-card:#16261F;--ivk-ink:#EAF1EC;--ivk-muted:#9BAAA1;--ivk-line:#223229;--ivk-sand:#16261F;--ivk-banner:#1C3A2C}.ivk-home a{color:inherit;text-decoration:none}.ivk-home footer a[href*=mintlify]{color:#9ea3a2}.dark .ivk-home footer a[href*=mintlify]{color:#6f7573}.ivk-home footer a[href*=mintlify]:hover{color:#4f5553}.dark .ivk-home footer a[href*=mintlify]:hover{color:#ced3d1}.ivk-home img,.ivk-home svg{display:block}.ivk-home-announce,.ivk-home-hero{border-radius:var(--ivk-radius-card)}.ivk-home-announce{background:var(--ivk-banner);color:var(--ivk-ink);font-size:13.5px;font-weight:500;text-align:center;padding:9px 16px;margin-bottom:20px}.ivk-home-announce a{color:var(--ivk-footer-bg);font-weight:600;text-decoration:underline;margin-left:6px}.ivk-home-hero{position:relative;overflow:hidden;background:var(--ivk-forest);color:#fff;padding:56px 32px}.ivk-home-hero-eyebrow{display:inline-flex;align-items:center;gap:8px;color:#fff;font-size:13px;font-weight:500;border:1px solid rgba(255,255,255,.28);border-radius:999px;padding:6px 14px;margin:0 0 22px}.ivk-home-hero h1{font-size:clamp(28px,4.2vw,44px);font-weight:700;line-height:1.1;letter-spacing:-.01em;max-width:17ch;margin:0 0 16px;color:#fff}.ivk-home-hero h1 .ivk-home-hl{color:#00b388}.ivk-home-hero-lede{font-size:16.5px;color:rgba(255,255,255,.78);max-width:48ch;margin:0 0 30px;line-height:1.55}.ivk-home-search-field{display:flex;align-items:center;gap:10px;background:#fff;border-radius:var(--ivk-radius-btn);padding:13px 16px;max-width:560px;box-shadow:0 14px 34px rgba(0,0,0,.28);cursor:pointer;border:0;width:100%;text-align:left;font-family:inherit}.ivk-home-search-field input{border:0;outline:0;flex:1;font-size:15px;font-family:inherit;color:#1f2121;background:0 0;pointer-events:none}.ivk-home-search-field input::placeholder{color:#626464}.ivk-home-search-field .ivk-home-icon{color:#626464;flex:none}.ivk-home-search-field kbd{font-size:11.5px;color:#626464;border:1px solid #e7e9e4;border-radius:5px;padding:2px 6px}.ivk-home-popular{margin-top:26px;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.ivk-home-popular .ivk-home-label{color:rgba(255,255,255,.62);font-size:13px;margin-right:4px}.ivk-home-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.2);color:#fff;font-size:13px;padding:7px 12px;border-radius:999px}.ivk-home-chip:hover{background:rgba(255,255,255,.16)}.ivk-home-note-banner{background:var(--ivk-sand);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);padding:16px 20px;font-size:13.5px;color:var(--ivk-muted);line-height:1.55;margin-top:24px}.ivk-home-note-banner strong{color:var(--ivk-ink)}.ivk-home-band{padding:60px 0}.ivk-home-band-alt{background:var(--ivk-sand);border-radius:var(--ivk-radius-card)}.ivk-home-section-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:26px;flex-wrap:wrap}.ivk-home-section-head h2,.ivk-home-topic-tile h3{font-size:23px;font-weight:700;letter-spacing:-.01em;margin:0;color:var(--ivk-ink)}.ivk-home-section-head .ivk-home-meta,.ivk-home-section-sub{color:var(--ivk-muted);font-size:13.5px}.ivk-home-section-sub{font-size:14.5px;max-width:62ch;margin:-14px 0 26px;line-height:1.55}.ivk-home-topic-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;align-items:start}@media (min-width:1400px){.ivk-home-topic-grid{grid-template-columns:repeat(4,1fr)}}@media (max-width:860px){.ivk-home-topic-grid{grid-template-columns:repeat(2,1fr)}}@media (max-width:600px){.ivk-home-topic-grid{grid-template-columns:1fr}}.ivk-home-topic-tile{background:var(--ivk-card);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);transition:border-color .15s ease}.ivk-home-topic-tile:hover{border-color:color-mix(in srgb,var(--ivk-accent) 40%,var(--ivk-line))}.ivk-home-t-head{display:block;width:100%;padding:22px 22px 18px;cursor:pointer;background:0 0;border:0;text-align:left;font-family:inherit;color:inherit}.ivk-home-row-top{display:flex;align-items:center;justify-content:space-between;gap:10px}.ivk-home-icon-wrap{width:36px;height:36px;border-radius:10px;background:rgba(0,168,127,.12);color:var(--ivk-accent);display:flex;align-items:center;justify-content:center}.ivk-home-count{font-size:12px;color:var(--ivk-muted);white-space:nowrap}.ivk-home-title-row{display:flex;align-items:flex-start;gap:6px;margin:12px 0 4px}.ivk-home-topic-tile h3{font-size:16.5px;font-weight:600;letter-spacing:-.005em;line-height:1.3;min-height:2.6em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.ivk-home-tag-pill{flex:none;margin-top:2px;padding:2px 4px;border-radius:6px;font-size:.65rem;font-weight:700;line-height:13px;color:var(--ivk-accent);background:rgba(0,168,127,.1)}.dark .ivk-home-tag-pill,:root[data-theme=dark] .ivk-home-tag-pill{color:#1dc79a;background:rgba(29,199,154,.15)}.ivk-home-desc{font-size:13.5px;color:var(--ivk-muted);margin:0;line-height:1.5;min-height:3em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.ivk-home-expand-cue{display:flex;align-items:center;gap:6px;margin-top:14px;font-size:12.5px;color:var(--ivk-accent);font-weight:600}.ivk-home-expand-cue svg{transition:transform .18s ease}.ivk-home-topic-tile.ivk-home-open .ivk-home-expand-cue svg{transform:rotate(180deg)}.ivk-home-t-panel{border-top:1px solid var(--ivk-line);margin-top:2px;padding:16px 22px 22px}.ivk-home-t-panel ul{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:9px}.ivk-home-t-panel li a{font-size:13px;color:var(--ivk-ink);display:flex;align-items:center;gap:7px}.ivk-home-dev-card h3 a:hover,.ivk-home-t-panel li a:hover,.ivk-home-viewall{color:var(--ivk-accent)}.ivk-home-t-panel li a svg{flex:none;opacity:.5}.ivk-home-viewall{font-size:12.5px;font-weight:600}.ivk-home-dev-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}@media (max-width:700px){.ivk-home-dev-grid{grid-template-columns:1fr}}.ivk-home-dev-card{background:var(--ivk-card);border:1px solid var(--ivk-line);border-radius:var(--ivk-radius-card);padding:18px;display:flex;gap:12px;align-items:flex-start}.ivk-home-dev-card .ivk-home-icon-wrap{background:var(--ivk-forest);color:#fff;width:32px;height:32px;border-radius:9px}.ivk-home-dev-card h3{font-size:14.5px;font-weight:600;margin:0 0 3px;color:var(--ivk-ink)}.ivk-home-dev-card p{font-size:13px;color:var(--ivk-muted);margin:0;line-height:1.45}"}],"page":{"pagePath":"invoca-design-system/patterns/overview","slug":"/invoca-design-system/patterns/overview","pageMetadata":{"title":"Patterns overview","description":"Named compositions of two or more components, with rules but no export — and how to choose between them.","icon":"layout-template","keywords":["patterns","composition","recurring","ui patterns","decision","when to use"],"href":"/invoca-design-system/patterns/overview"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Named compositions of two or more components, with rules but no export — and how to choose between them.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,p:`p`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,..._provideComponents(),...props.components},{Card,Columns,Heading,Table}=_components;if(!Card)_missingMdxReference(`Card`,true);if(!Columns)_missingMdxReference(`Columns`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);return _jsxs(_Fragment,{children:[_jsx(Heading,{level:`2`,id:`what-patterns-governs`,children:`What Patterns governs`}),`\n`,_jsxs(_components.p,{children:[`A `,_jsx(_components.strong,{children:`pattern`}),` is a named composition of two or more components, with rules, but no export. It\nsits between Components and Views in Titan’s four-tier ladder: a pattern tells you which\ncomponents to combine, in what order, and how they behave together, but it ships nothing of\nits own — no import, no props API, no tokens. If you can `,_jsx(_components.code,{children:`import`}),` it, it’s a Component. If it\ndefines a page’s regions, it’s a View. If it’s a recurring, rule-bound arrangement of existing\ncomponents that answers to neither of those tests, it’s a Pattern.`]}),`\n`,_jsx(_components.p,{children:`Patterns exist because component pages answer “what does a Button do” and views answer “what\nregions does this page have,” and neither answers “how do these five components work together\nto let someone delete a campaign safely” or “what happens across a whole form when three\nfields are invalid at once.” That composition-level question is this section’s job.`}),`\n`,_jsx(Heading,{level:`2`,id:`choosing-a-pattern`,children:`Choosing a pattern`}),`\n`,_jsx(_components.p,{children:`The reader’s intent, not the component name, is the useful index. Use this table before the\ncard grid below — it is written in the words of the problem, not the solution.`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`If you need to…`}),_jsx(_components.th,{children:`Use`}),_jsx(_components.th,{children:`Not`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Let someone act on many rows at once`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/bulk-selection`,children:`Bulk selection`})}),_jsx(_components.td,{children:`Per-row buttons repeated on every row — cheap to build, expensive for anyone who has to click it fifty times`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Ask before an action that destroys work`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`})}),_jsx(_components.td,{children:`A confirmation dialog on an action the user could just as easily undo — training people to click through a dialog that never protected anything`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Tell someone a view has nothing in it yet`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/empty-and-zero-states`,children:`Empty \u0026 zero states`})}),_jsx(_components.td,{children:`A blank region with no explanation — indistinguishable from a bug`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Tell someone an action or a load failed`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/error-handling`,children:`Error handling`})}),_jsx(_components.td,{children:`A generic toast with no path to retry or recover`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Let someone narrow a large list down to what they want`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/filtering-and-search`,children:`Filtering \u0026 search`})}),_jsx(_components.td,{children:`Asking the user to scroll and scan a list that’s grown past a page`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Decide which surface owns a Save and Cancel — the view, a container, a dialog, or a drawer`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/footers`,children:`Footers`})}),_jsx(_components.td,{children:`A Save and Cancel on every group of fields — as many commits as the page has groups, and no answer to “am I done?”`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Catch a mistake in a field before it’s submitted`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/form-validation`,children:`Form validation`})}),_jsx(_components.td,{children:`Waiting for a full-page error banner to explain what a red asterisk didn’t`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Let someone change one small value without leaving the page`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing`,children:`Inline editing`})}),_jsx(_components.td,{children:`A full edit page for a change that’s one field`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Show that content is on its way, matching its eventual shape`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/loading-and-skeletons`,children:`Loading \u0026 skeletons`})}),_jsx(_components.td,{children:`A centered spinner over a page whose layout is about to jump once content lands`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Tell someone about something that happened outside the flow they’re in`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/notifications`,children:`Notifications`})}),_jsx(_components.td,{children:`Blocking the whole page with a dialog for something that isn’t a decision`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Keep an advanced or rarely-needed option out of the way without deleting it`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/progressive-disclosure`,children:`Progressive disclosure`})}),_jsx(_components.td,{children:`Hiding a setting most people need behind an extra click, to keep a screen looking simple`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Decide where creating, viewing, editing, or deleting an object should happen — full page, drawer, modal, or inline`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/overview`,children:`CRUD`})}),_jsx(_components.td,{children:`Defaulting every object to the same surface regardless of how permanent or complex it is`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`choosing-where-to-look`,children:`Choosing where to look`}),`\n`,_jsxs(Columns,{cols:2,children:[_jsx(Card,{title:`Destructive confirmation`,icon:`trash-2`,href:`/invoca-design-system/patterns/destructive-confirmation`,children:_jsx(_components.p,{children:`Undo versus confirm, and three tiers of friction matched to consequence.`})}),_jsx(Card,{title:`Bulk selection`,icon:`list-checks`,href:`/invoca-design-system/patterns/bulk-selection`,children:_jsx(_components.p,{children:`Selecting many rows and acting on them as one batch.`})}),_jsx(Card,{title:`Empty \u0026 zero states`,icon:`inbox`,href:`/invoca-design-system/patterns/empty-and-zero-states`,children:_jsx(_components.p,{children:`Nothing here yet, versus nothing matched, versus something went wrong.`})}),_jsx(Card,{title:`Error handling`,icon:`octagon-alert`,href:`/invoca-design-system/patterns/error-handling`,children:_jsx(_components.p,{children:`Where a failure is shown, and what it must tell the user next.`})}),_jsx(Card,{title:`Filtering \u0026 search`,icon:`filter`,href:`/invoca-design-system/patterns/filtering-and-search`,children:_jsx(_components.p,{children:`Narrowing a list, and keeping the narrowing visible and reversible.`})}),_jsx(Card,{title:`Footers`,icon:`panel-bottom`,href:`/invoca-design-system/patterns/footers`,children:_jsx(_components.p,{children:`Which surface owns Save and Cancel — the view, a container, a dialog, or a drawer — never more than one at a time.`})}),_jsx(Card,{title:`Form validation`,icon:`clipboard-check`,href:`/invoca-design-system/patterns/form-validation`,children:_jsx(_components.p,{children:`When an error appears, where it appears, and how many places say it at once.`})}),_jsx(Card,{title:`Inline editing`,icon:`pencil`,href:`/invoca-design-system/patterns/inline-editing`,children:_jsx(_components.p,{children:`Editing a value in place, and when that stops being the right idea.`})}),_jsx(Card,{title:`Loading \u0026 skeletons`,icon:`loader`,href:`/invoca-design-system/patterns/loading-and-skeletons`,children:_jsx(_components.p,{children:`Matching a loading placeholder to the shape of what’s coming.`})}),_jsx(Card,{title:`Notifications`,icon:`bell`,href:`/invoca-design-system/patterns/notifications`,children:_jsx(_components.p,{children:`Toast, banner, or alert — and what decides which.`})}),_jsx(Card,{title:`Progressive disclosure`,icon:`chevrons-down-up`,href:`/invoca-design-system/patterns/progressive-disclosure`,children:_jsx(_components.p,{children:`Keeping a screen simple without hiding what people actually need.`})}),_jsx(Card,{title:`CRUD`,icon:`database`,href:`/invoca-design-system/patterns/crud/overview`,children:_jsx(_components.p,{children:`Full page, drawer, modal, or inline — the decision tree for Create, Read, Update, and Delete.`})})]}),`\n`,_jsx(Heading,{level:`2`,id:`constraints`,children:`Constraints`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`ID`}),_jsx(_components.th,{children:`Constraint`}),_jsx(_components.th,{children:`Rationale`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-PATTERN-01`})}),_jsx(_components.td,{children:`A pattern page composes existing components. It never introduces a new visual value, and never asks for a component that doesn’t exist.`}),_jsx(_components.td,{children:`A pattern that requires an unshipped primitive isn’t a pattern yet — it’s a component proposal wearing a pattern’s name.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-PATTERN-02`})}),_jsx(_components.td,{children:`Every “when it doesn’t apply” entry names a specific, linked alternative.`}),_jsx(_components.td,{children:`”Don’t use this for the wrong thing” tells a reader nothing about what the right thing is.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-PATTERN-03`})}),_jsx(_components.td,{children:`A pattern’s constraints cite the component-level constraint they follow from, where one exists, rather than restating it.`}),_jsx(_components.td,{children:`Restating a rule in two places means it can disagree with itself the first time one copy is updated and the other isn’t.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`related`,children:`Related`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/overview`,children:`Components`}),`, the units these compositions are\nbuilt from. `,_jsx(_components.a,{href:`/invoca-design-system/views/overview`,children:`Views`}),`, which decide the page regions a\npattern is placed into. `,_jsx(_components.a,{href:`/invoca-design-system/ai-experience/overview`,children:`AI Experience`}),`, the\nsibling section for anything in this composition tier where the output isn’t deterministic —\nseveral patterns here have an AI-driven counterpart there (Empty \u0026 zero states pairs with\n`,_jsx(_components.a,{href:`/invoca-design-system/ai-experience/actions/welcome-empty-state`,children:`Welcome / empty state`}),`;\nFiltering \u0026 search pairs with `,_jsx(_components.a,{href:`/invoca-design-system/ai-experience/actions/search`,children:`Search`}),`).`]}),`\n`,_jsx(Heading,{level:`2`,id:`why-it-works-this-way`,children:`Why it works this way`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`A pattern is defined by what it lacks, not by what it contains.`}),` Any of these could be\nredescribed as “a Card, a Button, and some state” — that description is true of nearly every\nscreen in the product and explains nothing. What makes something worth a page here is a\nrecurring `,_jsx(_components.strong,{children:`decision`}),` — when to skip the pattern entirely, what order the pieces go in, what\nhappens on failure — not the inventory of components involved.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Proposal-first is the honest way to grow this section without Titan.`}),` Waiting for every\npattern to be confirmed against a shipped screen before writing it down means the vocabulary\nfor “how does Invoca do bulk selection” doesn’t exist until someone happens to build bulk\nselection first and document it after. Writing the proposal first gives the next person\nbuilding one a starting point to correct, instead of a blank page.`]}),`\n`,_jsx(Heading,{level:`2`,id:`status`,children:`Status`}),`\n`,_jsxs(_components.p,{children:[`Sign-off state per pattern. A pattern marked `,_jsx(_components.strong,{children:`Proposal`}),` is still what to build to; it means\nthe rule has not yet been checked against a shipped screen, not that it is optional.`]}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Pattern`}),_jsx(_components.th,{children:`Decided for Invoca?`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Destructive confirmation`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Proposal`}),` — reviewed once`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Bulk selection`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Empty \u0026 zero states`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Error handling`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Filtering \u0026 search`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Form validation`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Footers`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Inline editing`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Loading \u0026 skeletons`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Notifications`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Progressive disclosure`}),_jsx(_components.td,{children:_jsx(_components.strong,{children:`Proposal`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`CRUD (Create, Read, Update, Delete)`}),_jsxs(_components.td,{children:[_jsx(_components.strong,{children:`Proposal`}),` — varies by operation; see its own status block`]})]})]})]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Patterns overview","description":"Named compositions of two or more components, with rules but no export — and how to choose between them.","icon":"layout-template","keywords":["patterns","composition","recurring","ui patterns","decision","when to use"],"href":"/invoca-design-system/patterns/overview"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"What Patterns governs","slug":"what-patterns-governs","depth":2,"children":[]},{"title":"Choosing a pattern","slug":"choosing-a-pattern","depth":2,"children":[]},{"title":"Choosing where to look","slug":"choosing-where-to-look","depth":2,"children":[]},{"title":"Constraints","slug":"constraints","depth":2,"children":[]},{"title":"Related","slug":"related","depth":2,"children":[]},{"title":"Why it works this way","slug":"why-it-works-this-way","depth":2,"children":[]},{"title":"Status","slug":"status","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"invoca-5bd45748","siteName":"Invoca","title":"Patterns overview - Invoca","relatedPagesConfig":{"enabled":true,"limit":5,"mode":"automatic"},"contextualStarterQuestions":[{"_id":"6ab71c04fc74c9b83ba92d1d","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"How do I choose the right pattern?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/overview","createdAt":"2026-09-26T01:12:36.026Z","updatedAt":"2026-09-26T01:12:36.026Z","__v":0},{"_id":"6ab71c04fc74c9b83ba92d1c","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"When should I use a pattern?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/overview","createdAt":"2026-09-26T01:12:36.026Z","updatedAt":"2026-09-26T01:12:36.026Z","__v":0}],"navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-17T19:58:06.958Z","gitLastModified":"2026-09-17T19:57:46.000Z","originalFileLocation":"invoca-design-system/patterns/overview.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Named compositions of two or more components, with rules but no export — and how to choose between them.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Invoca\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Patterns overview - Invoca\">\u003cmeta data-mint-head property=\"og:description\" content=\"Named compositions of two or more components, with rules but no export — and how to choose between them.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Invoca\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.invoca.com/invoca-design-system/patterns/overview\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://invoca-5bd45748.mintlify.app/_mintlify/api/og/v2?division=Documentation\u0026amp;title=Patterns+overview\u0026amp;description=Named+compositions+of+two+or+more+components%2C+with+rules+but+no+export+%E2%80%94+and+how+to+choose+between+them.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=58927d46dbb46d34871990c35f4bba68c0441b49f77f4630e6591946937ec824\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Patterns overview - Invoca\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Named compositions of two or more components, with rules but no export — and how to choose between them.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://invoca-5bd45748.mintlify.app/_mintlify/api/og/v2?division=Documentation\u0026amp;title=Patterns+overview\u0026amp;description=Named+compositions+of+two+or+more+components%2C+with+rules+but+no+export+%E2%80%94+and+how+to+choose+between+them.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=58927d46dbb46d34871990c35f4bba68c0441b49f77f4630e6591946937ec824\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/invoca-5bd45748/Q9AjSeskElHvFPzD/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Invoca\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#00A87F\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.invoca.com/invoca-design-system/patterns/overview\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/invoca-design-system/patterns/overview.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.invoca.com/#organization\",\"name\":\"Invoca\",\"url\":\"https://docs.invoca.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/invoca-5bd45748/9Md68DqArcq3WD3L/logo/light.svg?fit=max\u0026auto=format\u0026n=9Md68DqArcq3WD3L\u0026q=85\u0026s=3ed629c5be28d08bd1a6580e72b6dbfa\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.invoca.com#website\",\"name\":\"Invoca\",\"url\":\"https://docs.invoca.com\",\"publisher\":{\"@id\":\"https://docs.invoca.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/overview#webpage\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/overview\",\"name\":\"Patterns overview\",\"description\":\"Named compositions of two or more components, with rules but no export — and how to choose between them.\",\"dateModified\":\"2026-09-17T19:57:46.000Z\",\"isPartOf\":{\"@id\":\"https://docs.invoca.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/overview#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/overview#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Invoca\",\"item\":\"https://docs.invoca.com\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Patterns overview\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/overview\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/overview#article\",\"headline\":\"Patterns overview\",\"name\":\"Patterns overview\",\"description\":\"Named compositions of two or more components, with rules but no export — and how to choose between them.\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/overview\",\"mainEntityOfPage\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/overview#webpage\"},\"dateModified\":\"2026-09-17T19:57:46.000Z\",\"keywords\":\"patterns, composition, recurring, ui patterns, decision, when to use\",\"publisher\":{\"@id\":\"https://docs.invoca.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.invoca.com#website\"}}]}\u003c/script>","siteName":"Invoca","nav":{"global":null,"products":[{"product":"Invoca Docs","pages":[{"title":"Invoca Docs","href":""}]},{"product":"Developer","pages":[{"title":"Developer","href":"/en/latest"}]},{"product":"Invoca Design System","icon":"palette","color":{"light":"#00b388","dark":"#00b388"},"description":"","tabs":[{"tab":"Get started","icon":"rocket","pages":[{"title":"Get started","href":"/invoca-design-system"}]},{"tab":"Foundations","icon":"palette","pages":[{"title":"Foundations","href":"/invoca-design-system/foundations/overview"}]},{"tab":"Content","icon":"font","pages":[{"title":"Content","href":"/invoca-design-system/content/voice-and-tone"}]},{"tab":"Components","icon":"shapes","pages":[{"title":"Components","href":"/invoca-design-system/components/overview"}]},{"tab":"Patterns","icon":"clipboard-list","groups":[{"group":"Patterns","root":{"title":"Patterns overview","icon":"layout-template","href":"/invoca-design-system/patterns/overview"},"directory":"card","pages":[{"title":"Destructive confirmation","description":"How to ask before an action that destroys work — and when not to ask at all.","icon":"trash-2","href":"/invoca-design-system/patterns/destructive-confirmation"},{"title":"Form validation","description":"When an error appears, where it renders, and how many places say it at once.","icon":"clipboard-check","href":"/invoca-design-system/patterns/form-validation"},{"title":"Empty \u0026 zero states","description":"Nothing here yet, versus nothing matched — and why a failed load is neither.","icon":"inbox","href":"/invoca-design-system/patterns/empty-and-zero-states"},{"title":"Loading \u0026 skeletons","description":"Matching a loading placeholder to the shape of what's coming — and when to reach for a spinner or a progress bar instead.","icon":"loader","href":"/invoca-design-system/patterns/loading-and-skeletons"},{"title":"Error handling","description":"Where a deterministic action or load failure is shown, and what it must tell the reader next.","icon":"octagon-alert","href":"/invoca-design-system/patterns/error-handling"},{"title":"Filtering and search","description":"Narrowing a list down to what someone wants, with deterministic filters and a search box — not natural-language interpretation.","icon":"filter","href":"/invoca-design-system/patterns/filtering-and-search"},{"title":"Bulk selection","description":"Selecting many rows at once and acting on them as a single batch.","icon":"list-checks","href":"/invoca-design-system/patterns/bulk-selection"},{"title":"Inline editing","description":"Editing a value in place, and when that stops being the right idea.","icon":"pencil","href":"/invoca-design-system/patterns/inline-editing"},{"title":"Progressive disclosure","description":"Keeping a screen simple without hiding what people actually need.","icon":"chevrons-down-up","href":"/invoca-design-system/patterns/progressive-disclosure"},{"title":"Notifications","description":"Toast, banner, or alert — and what decides which one tells the reader something happened.","icon":"bell","href":"/invoca-design-system/patterns/notifications"},{"title":"Footers","description":"Which surface owns the commit: how to decide where a footer belongs, on views, containers, dialogs, and drawers.","icon":"panel-bottom","href":"/invoca-design-system/patterns/footers"},{"group":"CRUD","root":{"title":"CRUD overview","icon":"database","href":"/invoca-design-system/patterns/crud/overview"},"pages":[{"title":"Create","description":"The decision tree for where a new object gets created — full page, modal, drawer, or inline — based on permanence, density, and continuity, not habit.","icon":"circle-plus","href":"/invoca-design-system/patterns/crud/create"},{"title":"Read","description":"Viewing one object in detail — full Detail view, Drawer preview, or inline expansion — based on how much the reader needs right now.","icon":"eye","href":"/invoca-design-system/patterns/crud/read"},{"title":"Update","description":"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.","icon":"pencil-line","href":"/invoca-design-system/patterns/crud/update"}]}]}]},{"tab":"Views","icon":"table-columns","pages":[{"title":"Views","href":"/invoca-design-system/views/overview"}]},{"tab":"AI Experience","icon":"robot","pages":[{"title":"AI Experience","href":"/invoca-design-system/ai-experience/overview"}]},{"tab":"Contribute","icon":"code-pull-request","pages":[{"title":"Contribute","href":"/invoca-design-system/contribute/governance"}]},{"tab":"Open Issues","icon":"triangle-exclamation","pages":[{"title":"Open Issues","href":"/invoca-design-system/foundations/divergences"}]}]}]},"basePath":"","title":"Patterns overview - Invoca","buildId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","deploymentId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","dynamics":[],"chunks":[]}