Button
Starts an action, or navigates when it is a link.
mq-button is the console's Button as a design-system primitive. It ships
from @mediquo/ui as a custom element and as a React component.
Install
// Custom element — the import registers <mq-button>
import "@mediquo/ui/components/button";// React
import { Button } from "@mediquo/ui/react/button";Variants and sizes
variant is one of primary, secondary, light, negative,
outline-negative, ghost, ghost-negative, link and outline.
size is one of xs, sm, md (the default) and lg, or one of the square
icon sizes icon-xs, icon-sm, icon, icon-lg and icon-xl. full-width
stretches the button to its container.
Links
The console reaches links through Radix's asChild. A custom element cannot
adopt its child's tag, so href replaces it: the button renders a real <a>
and keeps link semantics — middle-click, "open in new tab", and announced as a
link rather than a button that happens to navigate.
<Button variant="outline" href="/citas">
Ver mis citas
</Button>target="_blank" gets rel="noopener noreferrer" unless you pass your own
rel.
Forms
type defaults to "button", not the HTML default "submit", so a button
dropped into a form does not submit it by accident. The control lives in a
shadow root, where it cannot reach an outer <form> on its own; the element is
form-associated and forwards type="submit" and type="reset" to its form.
Accessibility
- Icon-only buttons need
label. Theicon*sizes render no text, solabelbecomes thearia-label— the component warns in the console when it is missing. Mark the icon itselfaria-hidden. loadingkeeps focus where it is. Unlikedisabled, a loading button stays in the tab order, so focus is not thrown back to the page mid-action. It ignores clicks and reportsaria-busyandaria-disabled; the spinner isaria-hidden.- Toggle and disclosure state are opt-in:
pressedsetsaria-pressed,expandedsetsaria-expandedandhaspopupsetsaria-haspopup. Left unset, the attributes are absent —aria-pressed="false"would announce an ordinary button as an unpressed toggle. - A disabled link drops its
href, so it leaves the tab order and cannot navigate, and keepsrole="link"witharia-disabledso it is still announced as a link. - The focus ring is a 2px outline with an offset, which holds the 3:1 contrast a
focus indicator needs on every fill. Forced-colours mode draws a border so
the shape survives, and the transitions are dropped under
prefers-reduced-motion: reduce.
Styling
The component uses --mq-* tokens with literal fallbacks. --mq-button-radius
overrides the corner radius; part="control" reaches the inner <button> or
<a>, and part="spinner" the loading indicator.
Differences from the console
ghost-destructiveis gone: it drew the same red text on the same red hover asghost-negative. Useghost-negative.ghostandoutlineuse the primary text colour instead of the secondary grey, which fell under 4.5:1 contrast on a white background.