Modal Component
Default — small (400px)
Icon + title + body + footer
razor
<Button Variant="primary" Text="Open modal"
OnClick="() => showDefault = true" />
<Modal @bind-IsOpen="showDefault"
Title="Add labels to project"
Description="Labels help organize projects."
Size="sm">
<Icon>
<svg>...tag icon...</svg>
</Icon>
<ChildContent>
<InputField Placeholder="Search for label" />
</ChildContent>
<Footer>
<Button Variant="secondary" Text="Cancel" OnClick="() => showDefault = false" />
<Button Variant="primary" Text="Add labels" OnClick="() => showDefault = false" />
</Footer>
</Modal>
@code { private bool showDefault; }Sizes
Four preset widths
razor
@* Sizes: sm (400), md (480), lg (560), xl (640) *@
<Modal @bind-IsOpen="showMd" Size="md" Title="Medium modal">
<ChildContent>...</ChildContent>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Confirm" />
</Footer>
</Modal>Destructive confirmation
Use primary-destructive for both trigger and confirm
razor
<Button Variant="primary-destructive"
Text="Delete project"
OnClick="() => showDestructive = true" />
<Modal @bind-IsOpen="showDestructive"
Title="Delete project"
Description="This action cannot be undone."
Size="sm">
<Icon>
<svg>...trash icon...</svg>
</Icon>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary-destructive" Text="Delete" />
</Footer>
</Modal>Without icon
Omit the Icon slot for a text-only header
razor
<Modal @bind-IsOpen="showNoIcon"
Title="Edit workspace name"
Description="Rename your workspace to something meaningful."
Size="sm">
<ChildContent>
<InputField Label="Workspace name" Value="Design System" />
</ChildContent>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Save changes" />
</Footer>
</Modal>Footer with status message
Validation error on the left, actions on the right
razor
<Modal @bind-IsOpen="showValidation"
Title="Edit workspace"
Size="md"
StatusType="error"
StatusMessage="Please fix 2 fields before saving">
<ChildContent>
<InputField Label="Workspace name" Value="" />
<InputField Label="Contact email" Value="not-an-email" />
</ChildContent>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Save changes" />
</Footer>
</Modal>Success status — auto-saved indicator
razor
<Modal @bind-IsOpen="showSaved"
Title="Edit workspace"
Size="md"
StatusType="success"
StatusMessage="Last saved a moment ago">
<ChildContent>...</ChildContent>
<Footer>
<Button Variant="secondary" Text="Close" />
<Button Variant="primary" Text="Done" />
</Footer>
</Modal>
@* StatusType options: neutral | info | success | warning | error *@Custom FooterStatus slot — loading spinner
razor
<Modal @bind-IsOpen="showSaving" Title="Edit workspace" Size="md">
<FooterStatus>
@* Custom slot — render anything (spinner, count badge, link) *@
<span class="modal-footer__status-icon">
<svg style="animation: spin 0.8s linear infinite;">...</svg>
</span>
<span class="modal-footer__status-text">Saving changes…</span>
</FooterStatus>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Save" Disabled />
</Footer>
</Modal>Footer actions layout
ActionsLayout="split" — full-width buttons (default when no status)
razor
<Modal @bind-IsOpen="showSplit"
Title="Confirm action"
Size="md"
ActionsLayout="split">
<ChildContent>...</ChildContent>
<Footer>
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Confirm" />
</Footer>
</Modal>
@* ActionsLayout values: auto (default) | split | end *@ActionsLayout="end" — content-sized, right-aligned
razor
<Modal @bind-IsOpen="showEnd"
Title="Review changes"
Size="md"
ActionsLayout="end">
<ChildContent>...</ChildContent>
<Footer>
<Button Variant="tertiary" Text="Save draft" />
<Button Variant="secondary" Text="Cancel" />
<Button Variant="primary" Text="Publish" />
</Footer>
</Modal>
@* Use "end" when you have 3+ buttons, or when stretched
labels look awkward. Buttons keep their natural width. *@