Create decides where an object is born. Once it exists, editing it raises questions Create
never had to answer: the surface opens with values already in it, not a blank form; some edits
are small enough to commit the instant they’re made, and others need everything held until an
explicit Save; the surface has to know whether anything has changed at all; and the object
might not be exactly as it was when the surface opened, if someone or something else touched it
in the meantime.None of that is a new surface decision. It’s what happens once the surface Create’s tree
already chose is holding an object that isn’t new anymore.
CRUD overview already states the
default: the same object type uses the same surface for Create and Update, unless a stated
reason differs.Create already names
the one legitimate case where it does — this page resolves it rather than inventing a second
answer.A quick-create Modal is optimized for speed of creating something, not for that object’s
whole life. Once the object exists, it has already earned whatever permanence its type implies
— and its ongoing edit surface is the surface that permanence calls for, even if the object was
born in a lighter one.
The exception is about the object type, not the individual object. A Tag is created in
a two-second Modal and is still edited through that same lightweight surface for as long as it
exists — a Tag never earns more permanence than that, so there’s nothing to graduate to. A
saved filter is also quick-created in a Modal, but if it later becomes something people
treat as a shared, first-class asset, its edit surface moves to the fuller one — Drawer or
full page — at that point, not before. A Campaign or an integration never faces this
question at all: both are already full-page objects from the moment they’re created, so Create
and Update land on the same surface with no exception needed.
The object already exists and its data is being changed, not authored for the first time.
The object was reached from Create’s
“duplicated from an existing one” case — the surface is Create’s tree; the values arriving
pre-filled from a template is this page’s concern.
Cancel is lighter weight and comes first, the same trailing-primary order every button pair in this system follows. Not present for a single-field edit — Inline editing has its own icon-only commit and cancel instead.
Current values load and render before the surface accepts input — no flash of an empty form filling in a moment later. See Loading & skeletons for the loading treatment while values are fetched.
A single field is edited
Commits through Inline editing’s own commit and cancel behavior. Nothing else on the surface opens for it.
Multiple fields are edited in the surface
Nothing commits until the explicit Save is pressed. Every changed field commits together.
A field changes
The surface tracks dirty state — Save is enabled once anything differs from the loaded values.
Reader navigates away with unsaved changes
Follows Destructive confirmation’s existing unsaved-edits guidance — a lightweight warning for anything non-trivially changed, nothing for an untouched surface.
The object changed on the server since the surface opened
Re-fetch at save time, the same rule Destructive confirmation already states for an object that changed while its dialog was open. If it changed, show the reader what changed and require re-confirmation before committing.
Save succeeds
Modal or Drawer closes with a Toast confirming, per Create’s own success behavior; a full-page or Detail-view edit confirms in place.
Save fails
The surface stays open with the entered values intact and the error shown inline — the same reasoning Inline editing already states for a failed single-field save, applied to the whole surface.
The surface for editing an object is the same one used to create it, unless the object has earned more permanence than that surface implies since creation — in which case the fuller surface (Drawer or full page) is used.
A quick-create Modal is optimized for speed of creation, not for the object’s whole life — the same reasoning that already sets Create and Update’s default to match.
TITAN-UPDATE-02
An object type that never earns more permanence than its quick-create Modal is edited on that same Modal for its whole life. An object type that can graduate to a first-class, shared asset moves its edit surface to the fuller one when that happens, not before.
The exception in TITAN-UPDATE-01 is about the object type, not a mood or a preference — a Tag has nothing to graduate to; a saved filter does, conditionally.
TITAN-UPDATE-03
A single field with no side effects and no cross-field validation commits through Inline editing, never by reopening the object’s full edit surface.
That page’s decision tree already answers this. Update does not re-decide it.
TITAN-UPDATE-04
A multi-field edit commits nothing until an explicit Save is pressed; every changed field commits together.
Partial application of a multi-field edit can leave the object in a combination of values the reader never intended and never saw on screen at once.
TITAN-UPDATE-05
The edit surface loads current values before it accepts input. It never renders empty fields that fill in a moment later.
See Loading & skeletons — a flash of empty-then-filled reads as the values being cleared, not as them loading.
TITAN-UPDATE-06
Navigating away from an edit surface with unsaved changes follows Destructive confirmation’s existing unsaved-edits guidance, not a rule invented here.
One definition of “leaving with unsaved work,” not two that can disagree — the same reasoning Inline editing already applies for a single field.
TITAN-UPDATE-07
If the object changed on the server since the edit surface opened, the surface re-fetches at save time and requires re-confirmation before committing.
Matches Destructive confirmation’s own rule for an object that changed while its dialog was open — same underlying risk, same answer.
Opening the edit surface moves focus to its first field once values have loaded, matching
Create’s own behavior for a Modal
or Drawer. Moving focus before values arrive would land the reader in a field about to change
under them.
A failed save’s inline error is announced per
Inline editing’s rule for a
single field, or Form validation’s rule for
a whole-surface save.
The concurrent-edit re-confirmation states the specific change in its accessible description,
not through color alone — the same requirement
Destructive confirmation
already states for its own body text.
Editing a Tag on a full page because “editing deserves more room than creating.” The Tag’s
permanence hasn’t changed just because it now exists — it never earned a fuller surface, so
its edit stays on the same one it was created on.Reopening the whole edit surface for a one-field change that Inline editing already covers.
Adds a navigation and a full form for a change that takes one field and one second.Committing a multi-field edit field-by-field as each one changes, with no single Save.
Leaves the object in a partially-applied combination of values nobody chose as a set.Silently discarding a save because the object changed on the server, with no way to see what
changed. The reader loses their edit with no explanation — the same failure mode as a dialog
that closes on failure instead of showing what went wrong.
Exemplar page — first pass. This is a proposal for review, not established policy — see
CRUD overview. This
page reuses Create’s surface tree rather than
walking it again — see Choosing a surface, revisited — and
covers only what’s genuinely different once an object already has data in it.
Last modified on September 28, 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/crud/update","slug":"/invoca-design-system/patterns/crud/update","pageMetadata":{"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","keywords":["update","edit","prefill","dirty state","partial save","concurrent edit","inline editing"],"href":"/invoca-design-system/patterns/crud/update"},"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: \"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\"\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`,em:`em`,li:`li`,p:`p`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Heading,Mermaid,Table,Tip}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!Mermaid)_missingMdxReference(`Mermaid`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(Heading,{level:`2`,id:`the-problem`,children:`The problem`}),`\n`,_jsx(_components.p,{children:`Create decides where an object is born. Once it exists, editing it raises questions Create\nnever had to answer: the surface opens with values already in it, not a blank form; some edits\nare small enough to commit the instant they’re made, and others need everything held until an\nexplicit Save; the surface has to know whether anything has changed at all; and the object\nmight not be exactly as it was when the surface opened, if someone or something else touched it\nin the meantime.`}),`\n`,_jsx(_components.p,{children:`None of that is a new surface decision. It’s what happens once the surface Create’s tree\nalready chose is holding an object that isn’t new anymore.`}),`\n`,_jsx(Heading,{level:`2`,id:`choosing-a-surface-revisited`,children:`Choosing a surface, revisited`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/overview#constraints`,children:`CRUD overview`}),` already states the\ndefault: `,_jsx(_components.strong,{children:`the same object type uses the same surface for Create and Update, unless a stated\nreason differs.`}),` `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create#variations`,children:`Create`}),` already names\nthe one legitimate case where it does — this page resolves it rather than inventing a second\nanswer.`]}),`\n`,_jsxs(_components.p,{children:[`A quick-create Modal is optimized for speed of `,_jsx(_components.em,{children:`creating`}),` something, not for that object’s\nwhole life. Once the object exists, it has already earned whatever permanence its type implies\n— and its ongoing edit surface is the surface that permanence calls for, even if the object was\nborn in a lighter one.`]}),`\n`,_jsx(Mermaid,{chart:`flowchart TD\n A[Object already exists,\u003cbr/>with data in it] --> B{Has it earned more\u003cbr/>permanence than the surface\u003cbr/>it was created on?}\n B -->|No - this object type never\u003cbr/>outgrows the quick-create Modal| C[Edit surface stays the\u003cbr/>lightweight one - Modal or inline]\n B -->|Yes - it has become a\u003cbr/>first-class, shared asset| D[Edit surface is the fuller one -\u003cbr/>Drawer or full page]`}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The exception is about the object type, not the individual object.`}),` A `,_jsx(_components.strong,{children:`Tag`}),` is created in\na two-second Modal and is still edited through that same lightweight surface for as long as it\nexists — a Tag never earns more permanence than that, so there’s nothing to graduate to. A\n`,_jsx(_components.strong,{children:`saved filter`}),` is also quick-created in a Modal, but if it later becomes something people\ntreat as a shared, first-class asset, its edit surface moves to the fuller one — Drawer or\nfull page — at that point, not before. A `,_jsx(_components.strong,{children:`Campaign`}),` or an `,_jsx(_components.strong,{children:`integration`}),` never faces this\nquestion at all: both are already full-page objects from the moment they’re created, so Create\nand Update land on the same surface with no exception needed.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`when-this-applies`,children:`When this applies`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`The object already exists and its data is being changed, not authored for the first time.`}),`\n`,_jsxs(_components.li,{children:[`The object was reached from `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create#when-it-doesnt`,children:`Create`}),`’s\n“duplicated from an existing one” case — the surface is Create’s tree; the values arriving\npre-filled from a template is this page’s concern.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`when-it-doesn’t`,children:`When it doesn’t`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Situation`}),_jsx(_components.th,{children:`Do this instead`}),_jsx(_components.th,{children:`Why`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The object doesn’t exist yet`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create`,children:`Create`})}),_jsx(_components.td,{children:`Nothing to prefill, no dirty state to track, until it exists.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`A single field, no side effects on other data, no cross-field validation`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing`,children:`Inline editing`})}),_jsx(_components.td,{children:`That page’s own decision tree already answers this. Reopening a full edit surface for one field is the failure it exists to prevent.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The operation removes the object rather than changing it`}),_jsx(_components.td,{children:_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`})}),_jsx(_components.td,{children:`A different operation, governed by that pattern directly — CRUD has no separate Delete page.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`structure`,children:`Structure`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Order`}),_jsx(_components.th,{children:`Component`}),_jsx(_components.th,{children:`Role`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`1`}),_jsxs(_components.td,{children:[`The trigger — `,_jsx(_components.a,{href:`/invoca-design-system/components/actions/button`,children:`Button`}),`, or the value itself with `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing`,children:`Inline editing`}),`’s hover affordance for a single field`]}),_jsx(_components.td,{children:`Opens the edit surface, or enters inline edit mode.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`2`}),_jsxs(_components.td,{children:[`The surface — the same one `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create`,children:`Create`}),` uses for this object type, unless permanence has moved it per `,_jsx(_components.a,{href:`#choosing-a-surface-revisited`,children:`Choosing a surface, revisited`})]}),_jsx(_components.td,{children:`Holds the form, already filled with the object’s current values.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`3`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/forms/form`,children:`Form`}),`, `,_jsx(_components.a,{href:`/invoca-design-system/components/forms/input`,children:`Input`}),`, `,_jsx(_components.a,{href:`/invoca-design-system/components/forms/select`,children:`Select`}),`, etc.`]}),_jsxs(_components.td,{children:[`Same fields as Create, prefilled — see `,_jsx(_components.a,{href:`#behavior`,children:`Behavior`}),` for load timing.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{\"data-numeric\":`true`,children:`4`}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`/invoca-design-system/components/actions/button`,children:`Button`}),` `,_jsx(_components.code,{children:`contained`}),` — commit, `,_jsx(_components.code,{children:`text`}),` — cancel`]}),_jsxs(_components.td,{children:[`Cancel is lighter weight and comes first, the same trailing-primary order every button pair in this system follows. Not present for a single-field edit — `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#structure`,children:`Inline editing`}),` has its own icon-only commit and cancel instead.`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`behavior`,children:`Behavior`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`State`}),_jsx(_components.th,{children:`Behavior`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Surface opens`}),_jsxs(_components.td,{children:[`Current values load and render before the surface accepts input — no flash of an empty form filling in a moment later. See `,_jsx(_components.a,{href:`/invoca-design-system/patterns/loading-and-skeletons`,children:`Loading \u0026 skeletons`}),` for the loading treatment while values are fetched.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`A single field is edited`}),_jsxs(_components.td,{children:[`Commits through `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#behavior`,children:`Inline editing`}),`’s own commit and cancel behavior. Nothing else on the surface opens for it.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Multiple fields are edited in the surface`}),_jsx(_components.td,{children:`Nothing commits until the explicit Save is pressed. Every changed field commits together.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`A field changes`}),_jsx(_components.td,{children:`The surface tracks dirty state — Save is enabled once anything differs from the loaded values.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Reader navigates away with unsaved changes`}),_jsxs(_components.td,{children:[`Follows `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#when-it-doesnt`,children:`Destructive confirmation`}),`’s existing unsaved-edits guidance — a lightweight warning for anything non-trivially changed, nothing for an untouched surface.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`The object changed on the server since the surface opened`}),_jsxs(_components.td,{children:[`Re-fetch at save time, the same rule `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#behavior`,children:`Destructive confirmation`}),` already states for an object that changed while its dialog was open. If it changed, show the reader what changed and require re-confirmation before committing.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Save succeeds`}),_jsxs(_components.td,{children:[`Modal or Drawer closes with a `,_jsx(_components.a,{href:`/invoca-design-system/components/feedback/toast`,children:`Toast`}),` confirming, per `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create#behavior`,children:`Create`}),`’s own success behavior; a full-page or Detail-view edit confirms in place.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Save fails`}),_jsxs(_components.td,{children:[`The surface stays open with the entered values intact and the error shown inline — the same reasoning `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#constraints`,children:`Inline editing`}),` already states for a failed single-field save, applied to the whole surface.`]})]})]})]}),`\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-UPDATE-01`})}),_jsx(_components.td,{children:`The surface for editing an object is the same one used to create it, unless the object has earned more permanence than that surface implies since creation — in which case the fuller surface (Drawer or full page) is used.`}),_jsx(_components.td,{children:`A quick-create Modal is optimized for speed of creation, not for the object’s whole life — the same reasoning that already sets Create and Update’s default to match.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-02`})}),_jsx(_components.td,{children:`An object type that never earns more permanence than its quick-create Modal is edited on that same Modal for its whole life. An object type that can graduate to a first-class, shared asset moves its edit surface to the fuller one when that happens, not before.`}),_jsxs(_components.td,{children:[`The exception in TITAN-UPDATE-01 is about the object `,_jsx(_components.em,{children:`type`}),`, not a mood or a preference — a Tag has nothing to graduate to; a saved filter does, conditionally.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-03`})}),_jsxs(_components.td,{children:[`A single field with no side effects and no cross-field validation commits through `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing`,children:`Inline editing`}),`, never by reopening the object’s full edit surface.`]}),_jsx(_components.td,{children:`That page’s decision tree already answers this. Update does not re-decide it.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-04`})}),_jsx(_components.td,{children:`A multi-field edit commits nothing until an explicit Save is pressed; every changed field commits together.`}),_jsx(_components.td,{children:`Partial application of a multi-field edit can leave the object in a combination of values the reader never intended and never saw on screen at once.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-05`})}),_jsx(_components.td,{children:`The edit surface loads current values before it accepts input. It never renders empty fields that fill in a moment later.`}),_jsxs(_components.td,{children:[`See `,_jsx(_components.a,{href:`/invoca-design-system/patterns/loading-and-skeletons#constraints`,children:`Loading \u0026 skeletons`}),` — a flash of empty-then-filled reads as the values being cleared, not as them loading.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-06`})}),_jsxs(_components.td,{children:[`Navigating away from an edit surface with unsaved changes follows `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#when-it-doesnt`,children:`Destructive confirmation`}),`’s existing unsaved-edits guidance, not a rule invented here.`]}),_jsxs(_components.td,{children:[`One definition of “leaving with unsaved work,” not two that can disagree — the same reasoning `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#constraints`,children:`Inline editing`}),` already applies for a single field.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`TITAN-UPDATE-07`})}),_jsx(_components.td,{children:`If the object changed on the server since the edit surface opened, the surface re-fetches at save time and requires re-confirmation before committing.`}),_jsxs(_components.td,{children:[`Matches `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#behavior`,children:`Destructive confirmation`}),`’s own rule for an object that changed while its dialog was open — same underlying risk, same answer.`]})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`content`,children:`Content`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Element`}),_jsx(_components.th,{children:`✅`}),_jsx(_components.th,{children:`❌`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Commit button`}),_jsx(_components.td,{children:`Save Campaign`}),_jsx(_components.td,{children:`Submit or Save`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Single-field commit`}),_jsxs(_components.td,{children:[`Handled by `,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#content`,children:`Inline editing`}),`’s own quiet return to resting state`]}),_jsx(_components.td,{children:`A full Toast for a one-field save that Inline editing already handles without one`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Unsaved-changes warning`}),_jsxs(_components.td,{children:[`Per `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#content`,children:`Destructive confirmation`}),`’s existing copy`]}),_jsx(_components.td,{children:`A separate warning invented for this page`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`accessibility`,children:`Accessibility`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`Opening the edit surface moves focus to its first field once values have loaded, matching\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create#accessibility`,children:`Create`}),`’s own behavior for a Modal\nor Drawer. Moving focus before values arrive would land the reader in a field about to change\nunder them.`]}),`\n`,_jsxs(_components.li,{children:[`A failed save’s inline error is announced per\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing#accessibility`,children:`Inline editing`}),`’s rule for a\nsingle field, or `,_jsx(_components.a,{href:`/invoca-design-system/patterns/form-validation`,children:`Form validation`}),`’s rule for\na whole-surface save.`]}),`\n`,_jsxs(_components.li,{children:[`The concurrent-edit re-confirmation states the specific change in its accessible description,\nnot through color alone — the same requirement\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation#accessibility`,children:`Destructive confirmation`}),`\nalready states for its own body text.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`variations`,children:`Variations`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variation`}),_jsx(_components.th,{children:`When`}),_jsx(_components.th,{children:`Change`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Duplicate-then-edit`}),_jsxs(_components.td,{children:[`The object was created via `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create#when-it-doesnt`,children:`Create`}),`’s “duplicated from an existing one” path`]}),_jsx(_components.td,{children:`Same surface as a normal edit; the values arrived pre-filled from a template rather than from the object’s own prior save.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Saved filter graduates to a shared asset`}),_jsx(_components.td,{children:`The object’s permanence changes after creation`}),_jsx(_components.td,{children:`Its edit surface moves from the lightweight one to the fuller one at that point, not before.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Quick edit reached from a Read surface`}),_jsx(_components.td,{children:`The reader is previewing the object in a Drawer or Detail view and wants to change one thing`}),_jsx(_components.td,{children:`Opens Update’s own surface — Inline editing for a single field, the fuller surface otherwise. The Read surface itself never edits.`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`anti-patterns`,children:`Anti-patterns`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Editing a Tag on a full page because “editing deserves more room than creating.”`}),` The Tag’s\npermanence hasn’t changed just because it now exists — it never earned a fuller surface, so\nits edit stays on the same one it was created on.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Reopening the whole edit surface for a one-field change that Inline editing already covers.`}),`\nAdds a navigation and a full form for a change that takes one field and one second.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Committing a multi-field edit field-by-field as each one changes, with no single Save.`}),`\nLeaves the object in a partially-applied combination of values nobody chose as a set.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Silently discarding a save because the object changed on the server, with no way to see what\nchanged.`}),` The reader loses their edit with no explanation — the same failure mode as a dialog\nthat closes on failure instead of showing what went wrong.`]}),`\n`,_jsx(Heading,{level:`2`,id:`related`,children:`Related`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/overview`,children:`CRUD overview`}),`, for the shared axes and\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/overview#constraints`,children:`TITAN-CRUD-02`}),`, which this page\nresolves. `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create`,children:`Create`}),`, whose surface this page reuses\nand whose Variations table first raised the pointer this page answers.\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/read`,children:`Read`}),`, the sibling CRUD operation.\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/inline-editing`,children:`Inline editing`}),`, for a single field’s whole\nbehavior. `,_jsx(_components.a,{href:`/invoca-design-system/patterns/loading-and-skeletons`,children:`Loading \u0026 skeletons`}),`, for the\nprefill-loading treatment. `,_jsx(_components.a,{href:`/invoca-design-system/patterns/destructive-confirmation`,children:`Destructive confirmation`}),`\nand `,_jsx(_components.a,{href:`/invoca-design-system/patterns/form-validation`,children:`Form validation`}),`, cited above rather than\nrestated.`]}),`\n`,_jsx(Heading,{level:`2`,id:`status`,children:`Status`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Exemplar page — first pass.`}),` This is a proposal for review, not established policy — see\n`,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/overview#coverage-stated-honestly`,children:`CRUD overview`}),`. This\npage reuses `,_jsx(_components.a,{href:`/invoca-design-system/patterns/crud/create`,children:`Create`}),`’s surface tree rather than\nwalking it again — see `,_jsx(_components.a,{href:`#choosing-a-surface-revisited`,children:`Choosing a surface, revisited`}),` — and\ncovers only what’s genuinely different once an object already has data in it.`]})]})}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":"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","keywords":["update","edit","prefill","dirty state","partial save","concurrent edit","inline editing"],"href":"/invoca-design-system/patterns/crud/update"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"The problem","slug":"the-problem","depth":2,"children":[]},{"title":"Choosing a surface, revisited","slug":"choosing-a-surface-revisited","depth":2,"children":[]},{"title":"When this applies","slug":"when-this-applies","depth":2,"children":[]},{"title":"When it doesn’t","slug":"when-it-doesn’t","depth":2,"children":[]},{"title":"Structure","slug":"structure","depth":2,"children":[]},{"title":"Behavior","slug":"behavior","depth":2,"children":[]},{"title":"Constraints","slug":"constraints","depth":2,"children":[]},{"title":"Content","slug":"content","depth":2,"children":[]},{"title":"Accessibility","slug":"accessibility","depth":2,"children":[]},{"title":"Variations","slug":"variations","depth":2,"children":[]},{"title":"Anti-patterns","slug":"anti-patterns","depth":2,"children":[]},{"title":"Related","slug":"related","depth":2,"children":[]},{"title":"Status","slug":"status","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"invoca-5bd45748","siteName":"Invoca","title":"Update - Invoca","relatedPagesConfig":{"enabled":true,"limit":5,"mode":"automatic"},"contextualStarterQuestions":[{"_id":"6aba7dfa7b4d112548b3909c","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"What is dirty-state tracking?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/crud/update","createdAt":"2026-09-28T14:47:22.238Z","updatedAt":"2026-09-28T14:47:22.238Z","__v":0},{"_id":"6aba7dfa7b4d112548b3909a","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"When should I change edit surfaces?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/crud/update","createdAt":"2026-09-28T14:47:22.238Z","updatedAt":"2026-09-28T14:47:22.238Z","__v":0},{"_id":"6aba7dfa7b4d112548b3909b","deploymentId":"6a10d9fbb2a094386ec2a44e","questionText":"How do I handle prefilled forms?","status":"active","generatedBy":"contextual","path":"invoca-design-system/patterns/crud/update","createdAt":"2026-09-28T14:47:22.238Z","updatedAt":"2026-09-28T14:47:22.238Z","__v":0}],"navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-28T14:47:13.368Z","gitLastModified":"2026-09-28T14:45:01.000Z","originalFileLocation":"invoca-design-system/patterns/crud/update.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=\"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\">\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=\"Update - Invoca\">\u003cmeta data-mint-head property=\"og:description\" content=\"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\">\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/crud/update\">\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=CRUD\u0026amp;title=Update\u0026amp;description=What+changes+once+an+object+already+has+data+%E2%80%94+prefill%2C+partial+versus+whole-form+save%2C+dirty-state+tracking%2C+and+concurrent+edits.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=5d41231d965dc2b0f3047124e47795610f3fc957bade09c92ff8a12e7c05f6fb\">\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=\"Update - Invoca\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://invoca-5bd45748.mintlify.app/_mintlify/api/og/v2?division=CRUD\u0026amp;title=Update\u0026amp;description=What+changes+once+an+object+already+has+data+%E2%80%94+prefill%2C+partial+versus+whole-form+save%2C+dirty-state+tracking%2C+and+concurrent+edits.\u0026amp;theme=1c2016f9c5ca3323f39e5905\u0026amp;signature=5d41231d965dc2b0f3047124e47795610f3fc957bade09c92ff8a12e7c05f6fb\">\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/crud/update\">\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/crud/update.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/crud/update#webpage\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update\",\"name\":\"Update\",\"description\":\"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\",\"dateModified\":\"2026-09-28T14:45:01.000Z\",\"isPartOf\":{\"@id\":\"https://docs.invoca.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Patterns\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CRUD\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/overview\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Update\",\"item\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update#article\",\"headline\":\"Update\",\"name\":\"Update\",\"description\":\"What changes once an object already has data — prefill, partial versus whole-form save, dirty-state tracking, and concurrent edits.\",\"url\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update\",\"mainEntityOfPage\":{\"@id\":\"https://docs.invoca.com/invoca-design-system/patterns/crud/update#webpage\"},\"dateModified\":\"2026-09-28T14:45:01.000Z\",\"keywords\":\"update, edit, prefill, dirty state, partial save, concurrent edit, inline editing\",\"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","icon":"trash-2","href":"/invoca-design-system/patterns/destructive-confirmation"},{"title":"Form validation","icon":"clipboard-check","href":"/invoca-design-system/patterns/form-validation"},{"title":"Empty \u0026 zero states","icon":"inbox","href":"/invoca-design-system/patterns/empty-and-zero-states"},{"title":"Loading \u0026 skeletons","icon":"loader","href":"/invoca-design-system/patterns/loading-and-skeletons"},{"title":"Error handling","icon":"octagon-alert","href":"/invoca-design-system/patterns/error-handling"},{"title":"Filtering and search","icon":"filter","href":"/invoca-design-system/patterns/filtering-and-search"},{"title":"Bulk selection","icon":"list-checks","href":"/invoca-design-system/patterns/bulk-selection"},{"title":"Inline editing","icon":"pencil","href":"/invoca-design-system/patterns/inline-editing"},{"title":"Progressive disclosure","icon":"chevrons-down-up","href":"/invoca-design-system/patterns/progressive-disclosure"},{"title":"Notifications","icon":"bell","href":"/invoca-design-system/patterns/notifications"},{"title":"Footers","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","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","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":"Update - Invoca","buildId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","deploymentId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","dynamics":[],"chunks":[]}