Actions

AppButton

Triggers an action — submit, save, open, confirm. The one way to render an action in the portal.

<app-button variant="primary">Save changes</app-button>

A button lets a user carry out an action — submitting a form, opening a dialog, confirming a choice. <app-button> is the single way to render an action; never hand-roll a raw .btn.

Its look comes entirely from the shared @webority/theme, so the Razor <app-button> and the React <AppButton> render identically — a button is a button on every Webority surface.

Playground

Every attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the button above it.

<app-button>Save changes</app-button>
href turns the button into a linkSet href and the same button renders as an <a role="button">. Disable it and the anchor drops its href and leaves the tab order, so a disabled link can't be followed by mouse or keyboard.

Variants

Eight emphasis levels. Emphasis signals importance — the strongest variant should be the single most important action in view.

The five core variants
primary → the main action · secondary → supporting · outline → lower emphasis · ghost → transparent, brand-tinted on hover · danger → destructive.
Show code
<app-button variant="primary">Save changes</app-button>
<app-button variant="secondary">Cancel</app-button>
<app-button variant="outline">Preview</app-button>
<app-button variant="ghost">Learn more</app-button>
<app-button variant="danger">Delete</app-button>
One primary per viewA screen has exactly one primary button — the main thing you want the user to do. Everything else is secondary, outline, or ghost. Two primaries compete and neither wins.
Three more
secondary-danger → a soft-tinted destructive action (the danger counterpart of secondary) · outline-danger → a lower-emphasis destructive action · light → sits well on a dark or tinted surface · warning → a caution action, short of destructive.
Show code
<app-button variant="secondary-danger">Remove</app-button>
<app-button variant="outline-danger">Remove</app-button>
<app-button variant="light">Dismiss</app-button>
<app-button variant="warning">Proceed anyway</app-button>
The emphasis ladder — pick by weight, not by colour you likeEight variants, two ladders. Neutral actions, strongest to quietest: primary → secondary → outline → ghost (light is the same low weight for a dark or tinted surface). Destructive actions: danger for the real, high-stakes delete → outline-danger when the same destructive action should sit quietly in a row. warning is the odd one out — a caution ("Proceed anyway"), a step short of destructive, not a general "important" button. Reach down the ladder as importance drops; don't swap variants just for variety.

Sizes

Three sizes. Default (md) suits almost everything; use sm inside dense toolbars and lg for a marketing call-to-action.

sm · md · lg
Show code
<app-button size="sm">Small</app-button>
<app-button size="md">Medium</app-button>
<app-button size="lg">Large</app-button>

With icons

An icon can reinforce the label — never replace it. For an icon-only control use AppActionIcon instead. The icon sizes itself to the button, so a large button never wears a tiny glyph.

Leading and trailing icons
Show code
<app-button left-icon="download">Download</app-button>
<app-button variant="outline" right-icon="arrow-right">Continue</app-button>
Icon size follows the button size
14px on sm, 16px on md, 20px on lg.
Show code
<app-button size="sm" left-icon="download">Small</app-button>
<app-button size="md" left-icon="download">Medium</app-button>
<app-button size="lg" left-icon="download">Large</app-button>

Hover animation

Every button animates on hover. The default is a royal angled sheen sweep; switch the feel with a .btn-anim-* modifier, or turn motion off with .btn-anim-none. Every option reads on every variant and honours prefers-reduced-motion. Hover each button to compare.

The options
default (sheen) · fill · expand · glow · none. Apply the modifier via the class attribute.
Show code
<app-button variant="primary">Default sheen</app-button>
<app-button variant="primary" class="btn-anim-fill">Fill</app-button>
<app-button variant="primary" class="btn-anim-expand">Expand</app-button>
<app-button variant="primary" class="btn-anim-glow">Glow</app-button>
<app-button variant="primary" class="btn-anim-none">None</app-button>
Each option on every variant
The moving layer tints from the button's own colour, so all options read on solid, outline, ghost and light alike.
Show code
<app-button variant="outline" class="btn-anim-fill">Outline · fill</app-button>
<app-button variant="ghost" class="btn-anim-expand">Ghost · expand</app-button>
<app-button variant="danger" class="btn-anim-glow">Danger · glow</app-button>
<app-button variant="light" class="btn-anim-sheen">Light · sheen</app-button>

States

Show progress and prevent double-submits with loading; use disabled only when an action is genuinely unavailable.

Loading and disabled
loading shows a spinner and disables the button so it can't be clicked twice.
Show code
<app-button loading="true">Saving…</app-button>
<app-button disabled="disabled">Unavailable</app-button>
Prefer loading over a bare disabled during async workWhen a click kicks off a request, set loading="true" — it disables the button and shows a spinner, so the user gets feedback and can't fire the action twice.

When to use

Use it when

  • The user performs an action — submit, save, open a dialog, confirm.
  • You need to mark the single most important action on a screen (one primary).
  • A destructive action needs to stand out (danger) — pair it with a confirm dialog.

Reach for something else when

  • It navigates to another page or URL. → a link
  • It toggles a single on/off setting. → AppSwitch
  • It is an icon-only action in a row or toolbar. → AppActionIcon
  • It is a selectable filter or tag. → AppChoiceChip

Best practices

Do
One clear primary action, supported by a secondary. The eye knows where to go.
Don't
Two primaries compete for attention — neither reads as the main action.
Do
Destructive actions use danger and name the object — "Delete project", not "OK".
Don't
A vague "Submit" in the default variant hides that this deletes data.
Do
Action-first verb + optional reinforcing icon. The label says exactly what happens.
Don't
A noun-only label leaves the user guessing what the button does.

Every option

The whole surface of the component, one cell per value — including the two variants the sections above don't cover (subtle, outline-light) and the shapes a normal example never shows: link, block, submit.

variant — all ten

variant="primary"
variant="secondary"
variant="outline"
variant="ghost"
variant="danger"
variant="success"
variant="secondary-danger"
variant="outline-danger"
variant="light"
variant="warning"
variant="subtle"
variant="outline-light"

size — every variant at every size

size="sm"
size="md"
size="lg"

state

(default)
loading
disabled
loading + left-icon (icon suppressed)
disabled variant="danger"
disabled href (drops href, leaves tab order)

icon slots

left-icon="download"
right-icon="arrow-right"
both slots

shape — block, link, native type

block — stretches to the container width
href="/Components/AppCard" — renders <a role="button">
type="submit" — submits the surrounding form
(submits this page)

hover animation — class modifiers

class="btn-anim-sheen"
class="btn-anim-fill"
class="btn-anim-expand"
class="btn-anim-glow"
class="btn-anim-none"

Attributes

AttributeTypeDefaultDescription
(content) *string—The button label (inner content). Always a verb-led phrase.
variantprimary | secondary | outline | ghost | danger | success | outline-danger | light | warning | subtle | outline-lightprimaryEmphasis level. One primary per view.
sizesm | lgmdControl size.
loadingboolfalseShows a spinner and disables the button during async work.
left-iconstring—A Bootstrap Icons glyph name for a leading icon, sized to the button (14/16/20px). Suppressed while loading.
right-iconstring—A Bootstrap Icons glyph name for a trailing icon.
typebutton | submit | resetbuttonNative button type. Use submit inside a form.
disabledbool—Disable the control.
blockbool—Stretch to the full width of the container.
hrefstring—Render as a button-styled link (<a href> with role="button") instead of a <button>.
staticbool—Render as a non-interactive <span> with full button chrome — a resolved confirmation (e.g. Verified) that keeps the footprint but does not click, focus, or hover.
tooltipstring—A collision-aware hover/focus tooltip (Bootstrap/Popper, same engine as <app-tooltip>) that flips to stay on-screen. Sparingly on a labelled button; most useful on a terse/icon-led action.
tooltip-placementstringautoPreferred tooltip side — auto/top/bottom/start/end. auto picks the side with the most room.