Skip to content

Button

hc-button is a thin semantic class applied to the standard <button> element. Variants and sizes are switched with data-* attributes so the markup stays close to plain HTML.

data-variant accepts default (implicit), primary, secondary, error, and ghost. Variants compose with sizes and states.

VariantPurpose
omittedNeutral default action — outlined.
primaryThe primary action on a page or in a dialog. Follows the active color theme.
secondaryA second filled action that ranks under primary. Neutral grey — intentionally not theme-tinted so primary stays distinct.
errorDestructive action — pair with a confirm UI.
ghostLow-emphasis action; transparent background.

Visual hierarchy from highest to lowest emphasis:

primary (themed fill) → secondary (neutral fill) → default (outlined) → ghost (no surface).

data-size accepts sm, md (default), and lg.

State belongs in HTML attributes — not modifier classes. The component styles :disabled, [aria-disabled="true"], :focus-visible, and [data-loading="true"] directly.

Use disabled when the action genuinely cannot be invoked. Use aria-disabled="true" when the control must remain focusable (for example, so a screen-reader user can read why it is unavailable).

hc-button is a normal <button>, so any htmx attribute works on it. The primary documentation uses data-hx-* so examples stay valid HTML and play well with template engines.

<button
class="hc-button"
data-variant="primary"
data-hx-post="/items"
data-hx-target="#items"
data-hx-swap="outerHTML">
Save
</button>

A confirmation flow combines the button with the confirm-action recipe:

<button
class="hc-button"
data-variant="error"
data-hc-confirm="Delete this item?"
data-hx-delete="/items/123"
data-hx-trigger="hc:confirmed"
data-hx-target="closest tr">
Delete
</button>
  • Always use the native <button> element. Do not apply hc-button to a <div> or <span>.
  • Provide a visible, descriptive label. Icon-only buttons need aria-label or visually-hidden text.
  • Focus is visualized through :focus-visible and the --hc-color-focus-ring token. Do not remove the outline without providing an equally clear alternative.
  • The disabled attribute removes the button from the tab order. Use aria-disabled="true" instead when the control should remain focusable.
  • For destructive actions, pair the button with a confirmation dialog so the action is not invoked accidentally.

hc-button reads from these component tokens (defined in component.tokens.json):

Token pathPurpose
button.heightDefault block size.
button.padding-xInline padding.
button.radiusBorder radius.
button.font-sizeDefault font size.
button.{default,primary,secondary,error,ghost}.{bg,fg,border}Per-variant colors.
button.{default,primary,secondary,error,ghost}-hover.{bg,border}Per-variant hover colors.
button.{sm,lg}.{height,padding-x,font-size}Size-specific overrides.

Override at any level — primitive, semantic, or component — by setting the corresponding --hc-* custom property on a scope.

:root {
--hc-button-radius: 999px; /* fully rounded */
--hc-button-primary-bg: #6d28d9; /* purple primary */
}
Show the generated CSS variables

The generated --hc-* custom properties consumed directly by this component:

--hc-button-height
--hc-button-padding-x
--hc-button-radius
--hc-button-font-size
--hc-button-font-weight
--hc-button-default-bg | -fg | -border | -hover-bg
--hc-button-primary-bg | -fg | -border | -hover-bg | -hover-border
--hc-button-secondary-bg | -fg | -border | -hover-bg | -hover-border
--hc-button-error-bg | -fg | -border | -hover-bg | -hover-border
--hc-button-ghost-bg | -fg | -border | -hover-bg
--hc-button-sm-height | -padding-x | -font-size
--hc-button-lg-height | -padding-x | -font-size
--hc-color-focus-ring
--hc-opacity-disabled
  • request-action — wraps a button with a spinner and disabled state.
  • confirm-action — destructive action with a confirm dialog.