M
Marai.UI
v1.0.0-alpha.7

Button

A fully styled, accessible button with semantic variants, configurable sizes, loading state, and safe Tailwind overrides.

Overview

MButton is beautiful by default. Write <MButton>Save Changes</MButton> and the result is already styled, accessible, and production-ready. Use Variant to communicate intent, Size to control scale, and Loading for async feedback. The Class parameter lets you override any default safely — user-supplied classes always win conflicts.

Usage

razor
@using Marai.UI.Components.MButton

Basic Usage

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton>Save Changes</MButton>
    <MButton Variant="Variant.Primary">Submit</MButton>
    <MButton Variant="Variant.Outline">Cancel</MButton>
</div>

Variants

Use Variant to communicate intent. All variants use token-driven colors from your active theme.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton Variant="Variant.Default">Default</MButton>
    <MButton Variant="Variant.Primary">Primary</MButton>
    <MButton Variant="Variant.Secondary">Secondary</MButton>
    <MButton Variant="Variant.Destructive">Destructive</MButton>
    <MButton Variant="Variant.Outline">Outline</MButton>
    <MButton Variant="Variant.Ghost">Ghost</MButton>
    <MButton Variant="Variant.Link">Link</MButton>
    <MButton Variant="Variant.Success">Success</MButton>
    <MButton Variant="Variant.Warning">Warning</MButton>
    <MButton Variant="Variant.Info">Info</MButton>
    <MButton Variant="Variant.Muted">Muted</MButton>
</div>

Sizes

Use Size to control button scale. Defaults to Size.Default.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap items-center gap-3">
    <MButton Variant="Variant.Primary" Size="Size.Xs">Extra Small</MButton>
    <MButton Variant="Variant.Primary" Size="Size.Sm">Small</MButton>
    <MButton Variant="Variant.Primary" Size="Size.Default">Default</MButton>
    <MButton Variant="Variant.Primary" Size="Size.Lg">Large</MButton>
    <MButton Variant="Variant.Primary" Size="Size.Xl">Extra Large</MButton>
</div>

Loading State

Set Loading="true" to show an inline spinner, disable the button, and communicate the busy state to screen readers via aria-busy. Button content remains visible and the button width does not collapse.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton Variant="Variant.Primary" Loading="true">Processing</MButton>
    <MButton Variant="Variant.Outline" Loading="true">Saving</MButton>
    <MButton Variant="Variant.Destructive" Loading="true">Deleting</MButton>
</div>

<div class="mt-4 flex flex-wrap gap-3">
    <MButton Variant="Variant.Primary" Loading="@_isSubmitting" OnClick="HandleSubmit">
        @(_isSubmitting ? "Submitting" : "Approve Merchant")
    </MButton>
</div>

@code {
    private bool _isSubmitting;

    private async Task HandleSubmit()
    {
        _isSubmitting = true;
        await Task.Delay(2000);
        _isSubmitting = false;
    }
}

Disabled State

Set Disabled="true" to apply the native disabled attribute. Default styling includes disabled:pointer-events-none disabled:opacity-50.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton Variant="Variant.Primary" Disabled="true">Submit</MButton>
    <MButton Variant="Variant.Outline" Disabled="true">Cancel</MButton>
    <MButton Variant="Variant.Destructive" Disabled="true">Delete Account</MButton>
</div>

Form Submit and Reset

Use Type="submit" or Type="reset" for form buttons. The default Type is "button" to prevent accidental form submission.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex gap-3">
    <MButton Variant="Variant.Primary" Type="submit">
        Submit Application
    </MButton>
    <MButton Variant="Variant.Outline" Type="reset">
        Reset Form
    </MButton>
</div>

Click Handler

Preview
razor
@using Marai.UI.Components.MButton

<MButton Variant="Variant.Primary" OnClick="HandleApprove">
    Approve Transaction
</MButton>

@if (_approved)
{
    <p class="mt-3 text-sm text-green-700">Transaction approved successfully.</p>
}

@code {
    private bool _approved;

    private void HandleApprove()
    {
        _approved = true;
    }
}

Icon Button

Use Size="Size.Icon" for square icon buttons. Always provide aria-label for screen readers.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton Variant="Variant.Outline" Size="Size.Icon" aria-label="Add merchant">
        <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"
             stroke-linecap="round" viewBox="0 0 24 24" aria-hidden="true">
            <line x1="12" y1="8" x2="12" y2="16" />
            <line x1="8" y1="12" x2="16" y2="12" />
        </svg>
    </MButton>
    <MButton Variant="Variant.Ghost" Size="Size.Icon" aria-label="Delete record">
        <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"
             stroke-linecap="round" viewBox="0 0 24 24" aria-hidden="true">
            <path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6" />
        </svg>
    </MButton>
</div>

Theming

Button colors are driven by your theme's CSS variables — --marai-primary, --marai-primary-foreground, and equivalents for each variant. Switch the active theme and all buttons update automatically.

Safe Tailwind Overrides

The Class parameter is appended last, so it always wins conflicts. Override radius, background, padding — anything.

Preview
razor
@using Marai.UI.Components.MButton

<div class="flex flex-wrap gap-3">
    <MButton Variant="Variant.Primary" Class="rounded-full px-6">
        Pill Shape
    </MButton>
    <MButton Variant="Variant.Outline" Class="border-2 font-semibold">
        Bold Outline
    </MButton>
    <MButton Variant="Variant.Ghost" Class="text-slate-500">
        Subtle Ghost
    </MButton>
</div>

Standard HTML Attributes

Any unrecognized attribute passes through to the <button> element.

Preview
razor
@using Marai.UI.Components.MButton

<MButton Variant="Variant.Primary"
         aria-label="Save merchant profile"
         data-testid="save-merchant-btn"
         name="intent"
         value="save">
    Save Merchant
</MButton>

Accessibility

  • Focus-visible ring is built in — keyboard navigation is visible by default
  • Loading sets aria-disabled and aria-busy automatically
  • Use aria-label on icon-only buttons — visible text is not sufficient for screen readers
  • Use Type="submit" inside <EditForm> — the default "button" prevents accidental submission
  • Arbitrary ARIA attributes (aria-pressed, aria-expanded, aria-controls) pass through via AdditionalAttributes

API Reference

Parameter Type Default Description
Variant Variant Variant.Default Visual and semantic style. Maps to token-driven colors.
Size Size Size.Default Height, padding, and font-size preset.
Loading bool false Shows inline spinner, disables the button, and sets aria-busy.
Disabled bool false Applies the native disabled attribute and reduces opacity.
Type string "button" Native HTML type. Use "submit" or "reset" for form buttons.
Class string? null Additional Tailwind classes. User-supplied classes win all conflicts.
ChildContent RenderFragment? null Content rendered inside the button — text, icons, or any markup.
OnClick EventCallback<MouseEventArgs> Blazor click callback invoked when the button is clicked.
AdditionalAttributes Dictionary<string, object>? null Any unmatched HTML attributes pass through to the <button>.