rc-button
Progressive-enhancement button wrapper for a direct native <button>.
rc-button keeps the real button in light DOM for forms, labels, keyboard
behavior, and no-JavaScript fallback. The custom element adds reflected state
attributes, icon/label presence hooks, and overlay parts for state-layer or
progress effects.
- Package
@rcarls/rc-button- Element
<rc-button>- Native dependency
- Direct-child <button> element
- State model
- Controlled or uncontrolled toggle state
- Main events
rc-button-toggle- Related
- Theme previews
Installation
- npm
- Yarn
npm install @rcarls/rc-button
yarn add @rcarls/rc-button
import '@rcarls/rc-button/define';
Markup
<rc-button toggle default-selected>
<button type="button">
<span data-rc-button-icon aria-hidden="true">♡</span>
<span data-rc-button-selected-icon aria-hidden="true">♥</span>
<span data-rc-button-label>Save</span>
</button>
</rc-button>
Place icons, selected icons, progress-adjacent content, and visible labels
inside the native button. rc-button never moves author nodes.
Mark custom progress-adjacent content with data-rc-button-progress so it is
excluded from label detection, the same way data-rc-button-icon and
data-rc-button-selected-icon are.
States
Use reflected attributes such as pending, progress, selected,
icon-only, and full-width as declarative hooks. pending and progress
disable the native button and expose aria-busy when the author has not set
it. Use pending or boolean progress for an indeterminate affordance. Pair
progress with progress-value for a determinate percentage from 0 through
100; out-of-range values are clamped visually.
Use [data-rc-button-icon] and [data-rc-button-selected-icon] inside the
button for theme-driven selected icon switching.
Add toggle to opt into the APG toggle-button pattern. In uncontrolled usage,
default-selected supplies the initial state and user activation updates
selected, aria-pressed, and the displayed icon. In controlled usage, set
selected and update it from rc-button-toggle; the event's selected detail
contains the requested next state. Host property writes are silent. Removing
toggle removes component-owned toggle semantics.
const favoriteButton = document.querySelector('rc-button[toggle]');
favoriteButton.addEventListener('rc-button-toggle', (event) => {
favoriteButton.selected = event.detail.selected;
});
Accessibility
Keep the native button's accessible label unchanged between states. The icons
may change because they are presentational and marked aria-hidden, while the
visible “Save recipe” label remains stable as required by the
APG button pattern.
rc-button writes aria-pressed="true" or "false" only after toggle opts
the native child into toggle-button semantics. Enter and Space continue to use
the native button's activation behavior, and focus remains on the button.
Without a theme, the direct child keeps its native button appearance. The wrapper adds only layout and behavior until component tokens or a packaged theme opt into decorative styling.
Substrate supplies hover, focus, and pressed state layers, and presents determinate progress as a numeric percentage. Material supplies the same interaction states, adds a reduced-motion-aware ripple originating at the pointer or touch position, and uses a compact circular progress affordance.
Live demo
The Save recipe button is controlled: both native button activation and the
Selected checkbox update the same selected state.
API
Properties
| Property | Markup | Type | Default | Description |
|---|---|---|---|---|
disabled | disabled | boolean | false | Mirror disabled state to the native child. |
pending | pending | boolean | false | Show an indeterminate progress affordance and disable the native button. |
progress | progress | boolean | false | Show a progress affordance and disable the native button. |
progressValue | progress-value | number | undefined | Not specified | Optional determinate progress percentage, clamped from 0 through 100. |
toggle | toggle | boolean | false | Opt the native child into APG toggle-button behavior. |
selected | selected | boolean | Not specified | Controlled selected state. Host writes are silent. |
defaultSelected | default-selected | boolean | Not specified | Initial selected state for uncontrolled toggle usage. |
iconOnly | icon-only | boolean | false | Icon-only layout hint. May also be reflected by child classification. |
fullWidth | full-width | boolean | false | Stretch the native child button to the host inline size. |
Methods
No public methods are documented in the custom elements manifest.
Events
| Event | Detail type | Description |
|---|---|---|
rc-button-toggle | CustomEvent | Fired when a user activates a button with `toggle`. |
Slots
| Name | Description |
|---|---|
(default) | A direct native `<button>` child. |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--rc-button-gap | Not specified | Gap between icon and label content. |
--rc-button-block-size | Not specified | Minimum button block size. |
--rc-button-min-inline-size | Not specified | Minimum button inline size. |
--rc-button-inline-size | Not specified | Button inline size. |
--rc-button-padding-block | Not specified | Button block-axis padding (defers to native button padding when unset). |
--rc-button-padding-inline | Not specified | Button inline-axis padding (defers to native button padding when unset). |
--rc-button-border | Not specified | Button border (defers to native button border when unset). |
--rc-button-radius | Not specified | Button and overlay border radius (defers to native button radius when unset). |
--rc-button-bg | Not specified | Button background (defers to native button background when unset). |
--rc-button-color | Not specified | Button text color (defers to native button color when unset). |
--rc-button-shadow | Not specified | Button box shadow (defers to native button shadow when unset). |
--rc-button-font | Not specified | Button font shorthand (defers to native button font when unset). |
--rc-button-transition | Not specified | Button transition shorthand (defers to native button transition when unset). |
--rc-button-icon-size | Not specified | Button inline and min-inline size when `icon-only`. Falls back to `--rc-button-block-size`, then `--rc-control-block-size`, then `2.5rem`. |
--rc-button-disabled-opacity | Not specified | Disabled button opacity (defers to native disabled styling when unset). |
--rc-button-busy-content-color | transparent | Button text color while `pending` or `progress`. |
--rc-button-state-layer-bg | currentColor | State-layer overlay color. |
--rc-button-state-layer-duration | 150ms | State-layer opacity transition duration. |
--rc-button-state-layer-easing | ease | State-layer opacity transition easing. |
--rc-button-hover-state-layer-opacity | 0 | State-layer opacity on hover. |
--rc-button-focus-state-layer-opacity | 0 | State-layer opacity on focus-within. |
--rc-button-pressed-state-layer-opacity | 0 | State-layer opacity on active press. |
--rc-button-progress-color | currentColor | Progress affordance color. |
--rc-button-progress-font | 600 0.75rem / 1 sans-serif | Determinate progress percentage font. |
--rc-button-progress-size | 1.25rem | Indeterminate progress spinner diameter. |
--rc-button-progress-track-width | 2px | Indeterminate progress spinner stroke width. |
--rc-button-progress-track-color | color-mix(in srgb, currentColor 24%, transparent) | Indeterminate progress spinner track color. |
--rc-button-progress-active-color | currentColor | Indeterminate progress spinner active arc color. |
CSS Parts
| Part | Description |
|---|---|
state-layer | Overlay layer for hover, focus, pressed, ripple, or design-system effects. |
progress | Non-interactive progress affordance overlay shown for `pending` or `progress`. |