Button

Free

9 variants × 6 styles × 5 sizes × 3 shapes — solid, outline, soft, ghost, link and gradient with loading states and icon support.

</>sv-button actionctaform
import { SvButtonComponent } from '@styloviz/button';

Demo & usage

Basic usage

Live, interactive instance.

More examples

Styles & variants

Mix btnStyle with a semantic variant to cover every action weight.

example.htmlAngular
<sv-button label="Solid" variant="primary" />
<sv-button label="Outline" btnStyle="outline" variant="primary" />
<sv-button label="Ghost" btnStyle="ghost" variant="secondary" />
<sv-button label="Gradient" btnStyle="gradient" variant="primary" />
<sv-button label="Danger" variant="danger" />

Icons, counter & sizes

Lead/trail icons, a counter badge, and the size scale.

example.htmlAngular
<sv-button label="New" icon="plus" />
<sv-button label="Inbox" trailingIcon="chevron-down" [counter]="12" />
<sv-button label="Small"  size="sm" />
<sv-button label="Large"  size="lg" shape="pill" />

Custom / third-party icons

`iconTemplate` / `trailingIconTemplate` accept a TemplateRef, so you can render any third-party icon component, an <img>, an icon font, or a multi-color SVG — not just single-path currentColor icons.

example.htmlAngular
<ng-template #rocket>
  <img src="/assets/icons/rocket.svg" alt="" />
  <!-- or a real icon component: <lucide-icon name="rocket" /> -->
</ng-template>
<sv-button label="Launch" [iconTemplate]="rocket" />

Link button

Set href to render a semantic anchor that still looks like a button.

example.htmlAngular
<sv-button label="View docs" href="/docs" target="_blank" btnStyle="soft" />

Accessibility & safe links

target="_blank" auto-adds rel="noopener noreferrer". Use ariaLabel for icon-only buttons, counterLabel so badges are announced, and name/value in multi-button forms.

example.htmlAngular
<sv-button href="https://angular.dev" target="_blank" label="Docs" />
<sv-button iconPosition="only" icon="plus" ariaLabel="Add item" />
<sv-button iconPosition="only" label="Inbox" [counter]="5" counterLabel="unread" icon="plus" />
<sv-button type="submit" name="action" value="publish" label="Publish" />

When to use

  • Triggering an in-page action: submit, save, open a dialog, confirm a step.
  • You need a single, visually dominant call-to-action — use one primary button per view.
  • For navigation to another URL, set `href` so it renders a real anchor.

Async states

  • loading

Inputs

NameTypeDefaultDescription
variantButtonVariant'primary'Semantic color/intent: primary, secondary, success, danger, etc.
btnStyleButtonStyle'solid'Visual treatment: solid, soft, outline, ghost, link or gradient.
sizeButtonSize'md'Button size from xs to xl.
shapeButtonShape'rounded'Corner style: rounded, pill or square.
blockbooleanfalseStretch to 100% width.
elevatedbooleanfalseAdd drop shadow.
labelstring''Button text. Omit when projecting custom content.
iconstring''Icon-library NAME for the built-in leading/trailing icon — e.g. `'plus'`. Ignored when `iconTemplate` is set. BREAKING (icon sweep): was `iconPath`, a raw SVG `d` string. A name resolves through `@styloviz/icons`, so `check:icons` catches a typo that a `d` string rendered as a blank button. ⚠️ The old attribute was usually written STATICALLY (`iconPath="M12 4.5v15…"`), and Angular silently ignores an unknown static attribute — so a missed call site renders no icon rather than failing the build. All 157 in-repo sites were rewritten tag-scoped.
trailingIconstring''Icon-library NAME for the secondary/dual trailing icon. Ignored when `trailingIconTemplate` is set. Was `trailingIconPath`.
iconTemplateButtonIconTemplatenullCustom template for the primary icon — use this to render a third-party icon component (e.g. lucide-angular, ngx-heroicons), an `<img>`, an icon font `<i>`, or arbitrary custom SVG instead of the built-in `icon`. Positioned per `iconPosition()`. Takes precedence over `icon` when set.
trailingIconTemplateButtonIconTemplatenullCustom template for the secondary/dual trailing icon. Takes precedence over `trailingIcon` when set. See `iconTemplate` for usage.
iconPositionButtonIconPos'leading'Where the main icon sits relative to the label.
counternumber | nullnullNumeric counter badge. null = hidden.
counterMaxnumber99Value above which the counter shows "{max}+".
counterLabelstring''Noun describing the counter for screen readers, e.g. "unread".
typeButtonType'button'Native button type when not in link mode.
disabledbooleanfalseDisable interaction and dim the button.
loadingbooleanfalseShow a loading indicator and block activation.
loadingStyleButtonLoader'spinner'Loading indicator style: spinner or dots.
loadingLabelstring''Optional text shown beside the loading indicator.
preventDoubleSubmitbooleanfalseIgnore a second activation that lands within `doubleSubmitWindowMs` of the one before it.
doubleSubmitWindowMsnumber400How long a repeat activation is ignored for, in milliseconds.
announceLoadingbooleantrueAnnounce the loading state in a live region.
hrefstring''When set, renders an <a> anchor instead of a <button>.
targetstring'_self'Anchor target (e.g. _blank) when href is set.
relstring''Anchor rel. `noopener noreferrer` is auto-added for target="_blank".
downloadstring | nullnullAnchor download attribute (filename or empty string to use the URL).
namestring''Native `name` for the button when submitted as part of a form.
valuestring''Native `value` submitted with `name` for multi-button forms.
ariaLabelstring''Explicit accessible name. Required for icon-only buttons; overrides label.
pressedboolean | nullnullToggle state, published as `aria-pressed`. A BUTTON THAT STAYS ON IS A TOGGLE, AND A TOGGLE HAS TO SAY SO. Filter chips, "pin", "mute", "bold" — every one of them is a button whose variant changes to show it is active, and to a screen reader that change is invisible: the name is identical in both states, so the control reads as an ordinary button that does nothing. `aria-pressed` is the whole difference between "Filter" and "Filter, pressed". `null` — the default — omits the attribute entirely, because a button that is not a toggle must NOT claim to be one. `aria-pressed="false"` on an ordinary button tells the reader there is a state to toggle.
titlestring''Native tooltip / title attribute.
autofocusbooleanfalseAutofocus the control on render.

Outputs

EventPayload typeDescription
clickedMouseEventEmitted on click (suppressed while disabled or loading).
focusedFocusEventEmitted when the control receives focus.
blurredFocusEventEmitted when the control loses focus.

Customization & theming

  • Switch the look with `variant` (primary, secondary, success…) and `btnStyle` (solid, soft, outline, ghost, link, gradient).
  • Size with `size` (xs–xl) and shape with `shape` (rounded, pill, square); stretch with `block` and lift with `elevated`.
  • Add icons via `icon` / `trailingIcon` — icon-library names such as `plus` or `chevron-down`, resolved through `@styloviz/icons` — and a badge with `counter`; tune overflow with `counterMax` and announce it with `counterLabel`.
  • Bring your own icon with `iconTemplate` / `trailingIconTemplate` — pass a `TemplateRef` to render any third-party icon component, `<img>`, icon font, or multi-color SVG; it takes precedence over `icon` / `trailingIcon` when set.
  • Loading state via `[loading]="true"` with `loadingStyle` (spinner · dots · pulse) and an optional `loadingLabel`.
  • Link mode with `href` / `target` / `rel` / `download`; form integration with `name` / `value`; tooltip with `title`.

Best practices

  • Do: Reserve `variant="primary"` for the single most important action on the screen.
  • Do: Set `[loading]="true"` during async work so the button blocks duplicate submits.
  • Don't: Avoid stacking multiple solid primary buttons side by side — downgrade secondary actions to soft/ghost.
  • Tip: Use `icon` with a concise `label` rather than icon-only buttons unless you also set `ariaLabel`.

Accessibility

  • Renders a native <button> (or <a> when `href` is set) so keyboard and screen-reader semantics work out of the box.
  • Set `ariaLabel` for an explicit accessible name — required for icon-only buttons; the `counter` is folded into it (e.g. "Inbox, 5 unread") via `counterLabel`.
  • Disabled and loading states set `aria-disabled` / `aria-busy` and block activation; disabled links are removed from the tab order.
  • External links opening a new tab automatically receive `rel="noopener noreferrer"` to prevent reverse tabnabbing.
  • A visually-hidden status label announces the loading state when no text is visible. Visible focus ring with a theme-aware offset in light and dark mode.

Feedback on Button

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.