Skip to content

Button ​

Basic button component, an enhanced native <button>.

Types ​

Button types

DefaultPrimarySuccessWarningDangerText

Sizes ​

Five sizes

XSSmallMediumLargeXL

size supports five tiers: xs / small / medium (default) / large / xl; invalid values fall back to medium with a warning.

Five sizes · primary

XSSmallMediumLargeXL

Five sizes · icon-only

Disabled & Loading ​

disabled disables the button; loading enters the loading state — the original label keeps its space (width stays unchanged) and a spinner is centered; pair with loading-text to show a loading message.

Disabled and loading states

DisabledLoadSubmit

Async auto loading ​

With loading="auto", the button automatically enters the loading state while the host oas-click handler returns a Promise, and exits after the Promise resolves or rejects.

Auto loading for async submit

Click to submitSave async

Disabled but focusable ​

disabled-focusable renders a disabled look (desaturated + aria-disabled) without a native disabled attribute — still focusable and hoverable, ideal for wrapping in a tooltip that explains why it is disabled; clicks are intercepted by the component and oas-click is not dispatched.

Disabled but focusable (with tooltip)

Sign in to continueDownload report

Events ​

Click event

Click me

Clicking dispatches the oas-click CustomEvent (bubbles + composed); detail.originalEvent is the native MouseEvent.

Icon buttons ​

icon renders an icon before the text (reusing the oas-icon icon set, IconName); the spacing between the icon and text follows --oas-space-2.

Icon + text

SearchDownloadDeleteNew

Without text, the button becomes an equal-width square and needs an aria-label for an accessible name; when not set explicitly, the icon name is used as a fallback (e.g. icon="close" → aria-label="close"). It is recommended to provide an explicit label.

Icon-only buttons

Block ​

block makes the button fill the full width of its parent container.

Block buttons

Block buttonDownload

Rounded ​

round applies a pill radius (--oas-radius-full, falling back to 999px when the token is unavailable).

Rounded buttons

DoneUnsubscribe

Ghost ​

ghost renders a transparent background with an outline; the outline and text are colored by type and darken on hover.

Ghost buttons

Default ghostPrimary ghostSuccess ghostWarning ghostDanger ghost

Circle ​

circle turns the button into a circle; icon-only buttons combine equal-width and full rounding into a circle.

Circle buttons

Icon position ​

icon-position controls the icon/text order: start (default, icon on the left) or end (icon on the right).

Icon on the right

DownloadNext

Dual icons ​

icon renders an icon before the text and icon-end renders a second icon after the text (both reuse the oas-icon set); they can coexist with icon-position.

Dual icons

Download & continueNextConfirm & submit

Secondary text (compound two-row variant) ​

When the slot="description" secondary line is present, the button switches to a vertical two-row layout: the main row (icon + text) on top, the secondary line below (smaller, muted). Good for card entries, settings entries, upload entries — "main action + one line of explanation". Fully compatible with loading / icon / disabled / href.

Two-row button

Upload fileDrag & drop supported, ≤ 500KB per filePreferencesShortcut ⌘ + ,Submit order~3 seconds to complete

Setting href renders a native link (<a>); target controls how it opens (_blank / _self etc.); download (file download) and rel (link relationship) are passed through.

Link buttons

Default linkOpen in new tab

Download and rel

Download quarterly reportExternal link (rel=noopener)

Plain ​

plain uses a low-contrast, subtle style (a 12% tint of the semantic color as background with a transparent border and semantic-colored text), gentler on light backgrounds.

Plain buttons

Plain buttonPrimary plainDanger plain

Variant ​

variant controls the button shape, orthogonal to the type semantic color: solid (default filled) / outlined / dashed / filled (soft) / text / link. Legacy ghost equals outlined, plain equals filled.

Outlined / Dashed / Filled

OutlinedDashedFilledDefault outlinedDefault dashed

Text / Link

Text buttonPrimary textLink button

Custom color ​

color overrides the type semantic color with any color value.

Color priority: --oas-button-bg (host-injected CSS variable, gradients allowed) > color attribute > type semantic color > default gray. In outlined / filled / dashed / text variants, color tints the border/text/light background; for solid buttons the text color is picked black or white by background luminance (stays readable in dark mode).

Custom color values are rendered as-is (never rewritten) — make sure the text/background contrast meets WCAG AA (4.5:1).

Custom color

Purple solidGreen outlinedPink filled

Selected state (active / active-tint) ​

The active boolean attribute marks the selected state (controlled: the component does not toggle itself; the host writes back on oas-click). Selected visuals share the button-group selection anchor (aria-pressed). active-tint customizes the selected color — the 11 preset names resolve to theme tokens (light/dark adapted automatically), any CSS color is injected as-is, and the solid selected text color adapts to background luminance (contrast is the host's responsibility, WCAG AA 4.5:1).

Selected state

Default (soft selected tint)Primary (solid selected)Text (selected tint)Outlined (selected tint)

active-tint custom selected color

Custom solid selectedPreset selectedFilled variant selected

Toggle selection on click (controlled write-back)

Click to toggle selection

Press feedback ​

wave enables a subtle press feedback (slight sink + darken, on by default); wave="false" disables it.

Press feedback

Press me (on by default)Feedback off

CJK auto spacing ​

auto-insert-space inserts a space between two consecutive CJK characters (typography optimization, off by default).

CJK auto spacing

保存设置确认提交订单

Autofocus ​

autofocus gives the button focus after page load (native autofocus does not pierce Shadow DOM; the component forwards focus to the inner button on mount).

autofocus

Focused on loadNormal button

Long content wrapping ​

Buttons are single-line by default (white-space: nowrap). With the explicit wrap attribute, long text wraps within a constrained width (parent container or width / max-width) and the box grows with the content (same height as default when it fits on one line).

wrap for long content

A long button label that wraps automaticallyLong primary button text wraps in a narrow container

Touch targets on mobile ​

On touch devices (pointer: coarse) the button minimum height grows to 44px (--oas-touch-target-min): small sizes such as the 32px default or the 20px xs become 44px tall on touch, while sizes already ≥44px (e.g. xl) are unchanged; icon-only / circle buttons become 44×44 hit areas via aspect-ratio. Only the height grows — padding, font size, and border radius stay untouched; desktop (fine pointer) is unaffected.

Native form submission ​

html-type sets the native form behavior: button (default, no form behavior) / submit / reset. Buttons inside Shadow DOM do not participate in native form submission — the component bridges automatically: clicking triggers native submit/reset on the target form (the enclosing <form>, or the form id referenced by form); formaction / formmethod / formnovalidate / formtarget take effect through the native submitter mechanism (overriding the form's own action / method / novalidate / target). Submission is not triggered in disabled / loading state; in href link mode this attribute group is silently ignored.

Bridging notes (two boundaries): ① the bridge works via a transient native proxy submitter injected at click time — the form's submit event sees this proxy as submitter, not the oas-button (the proxy carries data-oas-form-proxy for identification); hosts with click delegation on the form area will see both the host's synthetic click and the proxy's native click bubble. ② html-type="submit" does not work inside oas-form: its real <form> lives in shadow DOM, so a light-DOM proxy finds no ancestor form — use oas-form's submit() method / oas-submit event instead.

Native form submission (html-type / form attributes)

SubmitSubmit in new tab (formtarget)ResetNo-validate submit (formaction/formmethod)

Clicking "Submit" fires the native submit event (the demo calls preventDefault and shows the fields about to be submitted); "Reset" restores the initial input values and fires reset; "No-validate submit" demonstrates formnovalidate skipping required validation plus formaction/formmethod overriding the submission target.

Custom Loading Icon ​

slot="loading-icon" replaces the built-in spinner ring with custom content while loading (the spinner positioning is reused, so stable loading width etc. are unchanged); when absent, the built-in spinner shows. Commonly paired with oas-icon spin for a themed loading icon.

loading-icon slot

Icon loading ⟳ Glyph loading Built-in spinner (default)

API ​

oas-button ​

Attributes ​

AttributeDescriptionTypeDefault
activeSelected state (controlled): present = selected; the host writes back on oas-click (the component does not toggle itself); selected visuals share the button-group selection anchor (aria-pressed), pair with active-tint for a custom tintboolean—
active-tintSelected-state tint: the 11 preset names resolve to --oas-preset-*-text tokens (one set per theme); any CSS color is injected as-is; solid selected text color (primary etc.) adapts to background luminance, contrast is the host’s responsibilitystring—
auto-insert-spaceCJK auto spacing: inserts a space between two consecutive CJK characters (off by default)string—
autofocusAutofocus: focuses the inner button on mount (native autofocus does not pierce Shadow DOM; the component forwards it)boolean—
blockFill the full width of the parent container (block level)boolean—
circleCircle button (icon-only, square + full rounding)boolean—
colorCustom color: overrides the type semantic color (any color value)string—
disabledDisabledboolean—
disabled-focusableVisually disabled but stays focusable/hoverable (aria-disabled + click intercepted), for tooltips explaining whyboolean—
downloadPassthrough download attribute in link mode (href) for file-download buttonsstring—
formAssociated form id for buttons outside the target form (native form-attribute association)string—
formactionTarget URL for this submission (overrides the form action)string—
formmethodHTTP method for this submission (get/post/dialog, overrides the form method)string—
formnovalidateSkip native validation for this submission onlyboolean—
formtargetBrowsing target for the response (_blank/_self etc., overrides the form target)string—
ghostGhost/outline style: transparent background + outline colored by type, darkens on hoverboolean—
hrefLink address: renders a native <a> when setstring—
html-typeNative form behavior: button (default, none) / submit submits the containing or form-targeted form / reset resets it (bridged via a proxy submitter)stringbutton
iconIcon name (reusing the oas-icon icon set); without text it becomes an equal-width square and uses the icon name as the fallback labelstring—
icon-endA second icon after the text (built-in icon name), works with icon/icon-position — e.g. left icon + right dropdown arrowstring—
icon-positionIcon position: start (default, left) / end (right)stringstart
loadingLoading state——
loading-textText shown while loading (e.g. "Submitting…"); replaces the label content when setstring—
plainPlain style: a 12% tinted background in the semantic color with text in its -text tone and a transparent border (no visible outline); equals variant="filled"boolean—
relPassthrough rel attribute in link mode (pair noopener with target="_blank")string—
roundPill radius (--oas-radius-full / 999px)boolean—
sizeSize: xs / small / medium (default) / large / xl; invalid values fall back to medium with a warningButtonSizemedium
targetHow the link opens (_blank / _self etc.), with hrefstring—
typeTypeButtonTypedefault
variantShape (orthogonal to type): solid (default filled) / outlined / dashed / filled (soft) / text / linkButtonVariant | ''—
wavePress feedback: slight sink + darken (on by default); wave="false" disablesstringtrue
wrapLong-text wrapping: single-line nowrap by default; when enabled, content wraps within constrained widths and the box grows with itboolean—

Events ​

EventDescription
oas-clickClick, detail: { originalEvent }

Slots ​

NameDescription
defaultButton content (text / icon)
descriptionSecondary text line (compound two-row variant): when present, the button switches to a vertical two-row layout (main row on top, secondary below, smaller muted text)
loading-iconCustom loading icon replacing the built-in spinner ring when slot content is present

CSS Variables ​

CSS VariableDescriptionDefault
--oas-button-active-tintSelected-state tint channel (injected by the active-tint attribute; preset names resolve to --oas-preset-*-text, raw colors as-is); consumed by selected text/border/soft and solid fillsvar(--oas-color-primary)
--oas-button-active-tint-onLabel color on solid selected fills (primary etc.): custom tints pick black/white by background luminance; falls back to --oas-color-text-on-primary when not injectedvar(--oas-color-text-on-primary)
--oas-button-active-tint-textText-safe variant of the selected tint: theme-aware deepen/lighten mix (toward near-black in light, near-white in dark; presets use the -text token directly) — labels on soft selected fills and text-variant selectionvar(--oas-color-primary-text)
--oas-button-bg—var(--oas-color-primary)
--oas-button-color—var(--oas-color-text-primary)
--oas-button-color-deepText-safe deepened variant of the custom color: the color-mix used for hover/active and outlined/dashed/filled text (injected by the component via --oas-deep-mix / --oas-deep-sink; inert without a custom color)var(--btn-color, var(--oas-color-text-primary))
--oas-button-group-radius—var(--oas-radius-md)
--oas-button-group-width—auto
--oas-button-heightButton height override (falls back to the size-tier value by default); containers needing full-row-height buttons (e.g. swipe-cell actions) inject 100% via ::slotted (built into swipe-cell)var(--oas-control-height-md)
--oas-button-on-color—var(--oas-color-text-on-primary)
--oas-glass-refractionLiquid-glass edge refraction filter (active under data-glass, default none); for local opt-out override with an empty value (--oas-glass-refraction: ;)—not none (mixing none with button-state brightness() invalidates the whole filter declaration)none

Released under the MIT OR Apache-2.0 License.