Card
A surface that groups related content - composed from header, content and footer sections, or driven by plain parameters when that is all you need.
Header, content, footer
The composed form. VetoCardHeader holds a VetoCardTitle and a VetoCardDescription for structured metadata, VetoCardContent holds the body, VetoCardFooter holds the actions. Each section pads itself, so the card needs no padding of its own and the sections never double up.
Deploy to production
Three commits are waiting. The last deploy was four days ago.
Deploying runs the full test suite first. If anything fails the release is held and nothing reaches production.
<VetoCard Padding="VetoSpacing.None">
<VetoCardHeader>
<VetoCardTitle>Deploy to production</VetoCardTitle>
<VetoCardDescription>Three commits are waiting.</VetoCardDescription>
</VetoCardHeader>
<VetoCardContent>
<p>Deploying runs the full test suite first.</p>
</VetoCardContent>
<VetoCardFooter Justify="VetoJustify.End">
<VetoButton Variant="VetoVariant.Text">Cancel</VetoButton>
<VetoButton Color="VetoColor.Primary">Deploy</VetoButton>
</VetoCardFooter>
</VetoCard>Media card
Put an image at the top of the card, before the header. The card clips to its own rounded corners without being asked, so the image's top edge is rounded and its sides run flush - which is what blog posts, product listings and portfolio items all want.
Building a component library
12 September 2026 ยท 8 minute read
What a component contract is for, and why the second component is the one that tells you whether the first one was designed properly.
@* The image goes before the header. The card clips to its own corners already,
so nothing has to ask for the rounded top. *@
<VetoCard Padding="VetoSpacing.None" Elevation="VetoElevation.Raised">
<img src="/media/post.jpg" alt="" />
<VetoCardHeader>
<VetoCardTitle>Building a component library</VetoCardTitle>
<VetoCardDescription>12 September 2026 · 8 minute read</VetoCardDescription>
</VetoCardHeader>
<VetoCardContent>
<p>What a component contract is for.</p>
</VetoCardContent>
</VetoCard>Statistic tiles
A grid of cards, each reversing the usual order inside the header: description first, then title. That puts the label above the figure, which is the order a KPI reads in. There is no parameter for it - writing the two children the other way round is the whole feature. Level="0" keeps the figures out of the page's heading outline, where twenty of them would do real damage.
Revenue
+12.4% on last month
Active users
+3.1% on last month
Churn
-0.4% on last month
P95 latency
+22 ms on last month
<VetoGrid Columns="1" ColumnsMedium="2" ColumnsLarge="4" Gap="VetoSpacing.Medium">
<VetoGridItem>
<VetoCard Padding="VetoSpacing.None">
<VetoCardHeader>
@* Description first: the label sits above the figure. *@
<VetoCardDescription>Revenue</VetoCardDescription>
<VetoCardTitle Level="0" Display="true">$48,290</VetoCardTitle>
<VetoCardDescription>+12.4% on last month</VetoCardDescription>
</VetoCardHeader>
</VetoCard>
</VetoGridItem>
</VetoGrid>The plain form
When a card is just a padded box with a heading, the parameters are less ceremony than the sections. Title, Header and Footer still work exactly as they did - the composed form is an addition, not a replacement.
Storage
41.2 GB of 100 GB used.
<VetoCard Title="Storage">
<p>41.2 GB of 100 GB used.</p>
</VetoCard>Elevation and interactivity
Flat, outlined or raised. Giving a card OnClick makes the whole surface activate - and renders it as a button, so it is focusable, keyboard operable and announced as a control rather than being a div that happens to respond to clicks.
Flat
Outlined
Raised
<VetoCard Elevation="VetoElevation.Flat" Title="Flat">Sits on the background.</VetoCard>
<VetoCard Elevation="VetoElevation.Raised" Title="Raised">A soft shadow.</VetoCard>
<VetoCard Title="Clickable" OnClick="Activate">Renders as a button.</VetoCard>Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
VetoCardHeader |
component |
— |
The title/description block. Bordered draws a hairline under it. |
VetoCardTitle |
component |
— |
The heading. Level sets h1-h6, or 0 for a plain div. Display renders it at figure size. |
VetoCardDescription |
component |
— |
The muted supporting line. Before the title for a KPI label, after it for a subtitle. |
VetoCardContent |
component |
— |
The body of a composed card. |
VetoCardFooter |
component |
— |
The actions. Justify distributes them; Bordered draws a hairline above. |
Title / Header / Footer |
string? / RenderFragment? |
null |
The plain form, unchanged. |
ChildContent |
RenderFragment? |
null |
The card's content. |
Elevation |
VetoElevation |
Outlined |
Flat, Outlined or Raised. |
Padding |
VetoSpacing |
Large |
Padding inside each region. Use None with the composed sections, which pad themselves. |
OnClick |
EventCallback<MouseEventArgs> |
— |
Makes the whole card activate, and renders it as a button. |
Disabled |
bool |
false |
Disables an interactive card. |