Button
An action the user takes: submit a form, open a dialog, run a command. Renders a real <button>; variant="default" is the primary style and variant="destructive" marks an irreversible action. To go to another page, put an <a href> inside it instead: the link becomes the control, styled as the button.
Intents
action
primary-action
secondary-action
destructive-action
navigation
Variants
Every value of the attributes that change how it looks. The values come from the schema.
variant
Visual style variant
variant="default"variant="secondary"variant="outline"variant="ghost"variant="link"variant="destructive"size
Button size
size="sm"size="md"size="lg"size="icon"Examples
Each one rendered live, over the markup that produces it.
Primary action
The default variant, for the main thing to do in a view.
<aihio-button>Click me</aihio-button>
Small and outlined
A lower-emphasis action beside a primary one.
<aihio-button variant="outline" size="sm">Cancel</aihio-button>
Destructive
For an action that deletes something or cannot be undone.
<aihio-button variant="destructive">Delete</aihio-button>
Icon only
With no visible text, aria-label is its name.
<aihio-button size="icon" aria-label="Close">✕</aihio-button>
A link drawn as a button
A call to action that goes to another page wraps an <a href>.
<aihio-button variant="outline"><a href="/pricing">See pricing</a></aihio-button>
Submits its form
type="submit" makes it the form's submitter, so Enter in a field submits too.
<form>
<label>
Email
<aihio-input type="email" name="email" required></aihio-input>
</label>
<aihio-button type="submit">Sign in</aihio-button>
</form>
Opens a dialog from markup
commandfor names the dialog and command="--open" opens it, with no script.
<aihio-button commandfor="confirm-delete" command="--open" variant="destructive">Delete project</aihio-button>
<aihio-dialog id="confirm-delete">
<aihio-dialog-header>
<aihio-dialog-title>Delete project?</aihio-dialog-title>
</aihio-dialog-header>
<form method="post">
<aihio-dialog-footer>
<aihio-button commandfor="confirm-delete" command="--close" variant="outline">Cancel</aihio-button>
<aihio-button type="submit" variant="destructive">Delete project</aihio-button>
</aihio-dialog-footer>
</form>
</aihio-dialog>
Mistakes
Each one beside its fix, with what aihio lint says about it. The prompt fragment gives agents the
same pairs, and the build fails if the linter stops catching one or a fix stops passing.
variant="primary" is not valid.
The primary style is variant="default".
Don't
<aihio-button variant="primary">Save</aihio-button>
aihio lint reports
-
invalid-enum-attributeerror Suggestsvariant="default"
Do
<aihio-button variant="default">Save</aihio-button>
Buttons must not be nested.
Use sibling buttons or aihio-dropdown for grouped actions.
Don't
<aihio-button><aihio-button>Save</aihio-button></aihio-button>
aihio lint reports
-
forbidden-descendanterror
Do
<aihio-cluster>
<aihio-button variant="outline">Cancel</aihio-button>
<aihio-button>Save</aihio-button>
</aihio-cluster>
Icon-only button is missing an accessible name.
Add aria-label="Close" (or similar).
Don't
<aihio-button size="icon">✕</aihio-button>
aihio lint reports
-
button-accessible-nameerror
Do
<aihio-button size="icon" aria-label="Close">✕</aihio-button>
A submit button outside the <form> never submits it.
Move the button inside the form element.
Don't
<form>
<aihio-input name="email" aria-label="Email"></aihio-input>
</form>
<aihio-button type="submit">Sign in</aihio-button>
aihio lint reports
-
button-form-ownerwarn
Do
<form>
<aihio-input name="email" aria-label="Email"></aihio-input>
<aihio-button type="submit">Sign in</aihio-button>
</form>
A button that navigates is announced as a button, shows no URL, cannot be opened in a new tab, and does nothing without script.
Put a link inside it: <aihio-button><a href="/pricing">See pricing</a></aihio-button>.
Don't
<aihio-button onclick="location.href='/pricing'">See pricing</aihio-button>
aihio lint reports
-
button-link-navigationerror
Do
<aihio-button><a href="/pricing">See pricing</a></aihio-button>
aihio-button has no href; nothing reads it.
Put the link inside: <aihio-button><a href="/pricing">See pricing</a></aihio-button>.
Don't
<aihio-button href="/pricing">See pricing</aihio-button>
aihio lint reports
-
unknown-attributeerror Suggests<aihio-button><a href="/pricing">See pricing</a></aihio-button>
Do
<aihio-button><a href="/pricing">See pricing</a></aihio-button>
API
Every attribute, property, method, and event the schema declares for aihio-button.
Attributes
variant-
one of
defaultsecondaryoutlineghostlinkdestructivedefaultdefault - Visual style variant
size-
one of
smmdlgicondefaultmd - Button size
disabled-
boolean
default
false - Disables the button
loading-
boolean
default
false - Shows loading state and disables interaction
type-
one of
buttonsubmitresetdefaultbutton - Form behaviour, forwarded to the native
<button>this component renders. submit submits the owning form (running native constraint validation first); reset resets it. Defaults to button, which does neither. name- string
- Submitter name included with form data.
value- string
- Submitter value included with form data.
form- string
- Id of an external form that owns the button.
formaction- string
- Submit URL override for submit buttons.
formmethod-
one of
getpostdialog - HTTP method override for submit buttons.
formenctype-
one of
application/x-www-form-urlencodedmultipart/form-datatext/plain - Encoding override for submit buttons.
formnovalidate- boolean
- Skips form validation when this submit button is used.
formtarget- string
- Browsing context target for the form response.
command- string
- Invoker command sent to the element named by commandfor when the button is activated, e.g.
command="--open"to open anaihio-dialog. Aihio components take--prefixedcustom commands; see each component's commands. commandfor- string
- Id of the element that receives command. Use with command to open or close an overlay without script.
Properties
control-
HTMLButtonElement | HTMLAnchorElement | nullread-only - The native button the component delegates to, or the authored
<a>when it wraps a link form-
HTMLFormElement | nullread-only - The owning form, or null outside one or when the control is a link
type-
"button" | "submit" | "reset" - Current native button type
Methods
click(): void- Activates the native button.
focus(options?: FocusOptions): void- Moves focus to the native button.
blur(): void- Removes focus from the native button.
Events
click- Fired when the button is clicked
Slots
default- Button label content
Composition
- Forbidden descendants
-
aihio-buttonaihio-inputaihio-dialogaihio-dropdown
Accessibility
What you have to provide, and what the component already does. The obligations with a rule are checked by
aihio lint and by the dev build's console warnings.
Your obligations
-
error Whensize="icon"or the button has no visible textProvide aria-label describing the action (e.g.
aria-label="Close").Checked as
button-accessible-name -
warn When the button submits a formSet
type="submit"and either place the button inside its<form>or reference that form with the form attribute.Checked as
button-form-owner -
error When the button goes to another page from a click handler (onclick sets location, or calls window.open or router.push)Put an
<a href>insideaihio-buttoninstead:<aihio-button><a href="/pricing">See pricing</a></aihio-button>. A button that navigates is announced as a button, shows no URL, cannot be opened in a new tab, and does nothing without script.Checked as
button-link-navigation -
error When the button wraps an<a>Give the
<a>an href. Without one it is not a link: it has no role, takes no focus, and goes nowhere.Checked as
button-link-href -
warn When the button wraps an<a>Leave type, name, value, form*, command, and commandfor off the host. They configure a
<button>, so on a link they do nothing.Checked as
button-link-attributes
Handled for you
- The component renders a real
<button>and forwards its attributes to it, so the role, Enter and Space activation, focus behaviour, disabled semantics, and the forced-colours mapping are the platform's rather than an emulation of it - An authored
<a>child becomes the control instead of a<button>, so a call to action that goes to another page is a real link: it is announced as one, shows its URL, opens in a new tab, and works before the module loads - aria-* set on the host is mirrored onto that control
- A disabled or loading link gets
aria-disabled="true", leaves the tab order, and its clicks are cancelled, since a link has no native disabled state - aria-busy reflects loading state, which also disables the control
- Form participation is native: the button is a submitter of its owning form, so Enter in a field submits, SubmitEvent.submitter identifies it, and
<fieldset disabled>disables it in both directions type="submit"runs native constraint validation before the form submits
In patterns
Canonical compositions that use aihio-button.