Basic
Use the primary button for the main action in a section or flow.
Icons by @ng-icons/tabler-icons
The component library does not provide icons.
Action primitives with variants, loading, icon support, and sizing options.
Preview
TS
import { FrButtonModule } from '@frame-ui-ng/components/button';
import { FrSpinnerModule } from '@frame-ui-ng/components/spinner';HTML
<button frButton type="button">
<span frButtonIcon>
<ng-icon name="tablerPlus" size="16" />
</span>
<span frButtonLabel>Save changes</span>
</button>Use the primary button for the main action in a section or flow.
Switch appearances to control emphasis, from the filled primary action to lighter outline and ghost affordances.
Use `sm`, `md`, and `lg` to match dense toolbars, default forms, or more prominent page-level actions.
Use radius presets when a button should feel more squared, softly rounded, or fully pill-shaped.
Buttons can replace their content with a shared Spinner primitive or keep the label visible and show loading inline, depending on how much continuity the action needs.
Use `FrIconButton` for compact icon-only actions and always provide an accessible label because there is no visible text label.
Buttons can be rendered on anchors when the interaction is true navigation but still needs button styling.
Override button tokens on a local wrapper when a product area needs a different height, radius, or visual density while keeping the same button API and behavior.
Hover the button shell, icon, label, or loading indicator to inspect the tokens that control spacing, height, radius, icon sizing, and loading treatment. Click a region to pin the inspector while you review the current values.
Use these CSS custom properties to tune button height, spacing, icon sizing, loading indicators, and interaction states without changing the markup structure.
SCSS
--frame-button-root-gap: 0.5rem;
--frame-button-root-height: 2.25rem;
--frame-button-root-padding-x: 1rem;
--frame-button-root-radius: var(--frame-radius-md);
--frame-button-root-shadow: var(--frame-shadow-sm);
--frame-button-root-font-size: 0.875rem;
--frame-button-root-font-weight: 600;
--frame-button-root-ring-color: var(--frame-ring);
--frame-button-root-focus-shadow: var(--frame-button-root-shadow), 0 0 0 3px color-mix(in srgb, var(--frame-button-root-ring-color) 35%, transparent);
--frame-button-root-hover-filter: brightness(0.98);
--frame-button-root-active-filter: brightness(0.96);
--frame-button-root-disabled-opacity: 0.55;
--frame-button-root-disabled-shadow: none;
--frame-button-loading-size: 1rem;
--frame-button-loading-stroke: 2px;
--frame-button-loading-track: color-mix(in srgb, currentColor 24%, transparent);
--frame-spinner-size: 1rem;
--frame-spinner-stroke: 2px;
--frame-spinner-track-color: color-mix(in srgb, currentColor 24%, transparent);
--frame-spinner-indicator-color: currentColor;
--frame-button-icon-size: 1rem;
--frame-button-label-weight: inherit;