Fluxy
Components

FxButton

A pre-styled, responsive button component with multiple variants, fluent modifiers, and loading support.

FxButton

FxButton is a high-level wrapper around Flutter's Material buttons, enhanced with atomic styling and built-in reactivity.

Usage

Fx.button("Click Me")
  .primary
  .onTap(() => print("Clicked"))

Variants

Fluxy provides semantic variants that automatically adjust colors and interactions.

Button Variants
Fx.button("Primary").primary
Fx.button("Secondary").secondary
Fx.button("Danger").danger
Fx.button("Outline").outline
Fx.button("Ghost").ghost
Fx.button("Text").text
Fx.button("Custom").none // Clean-slate for unstyled interaction

The .none Variant (Interaction-Only)

The .none variant is the "Clean-Slate" primitive. It strips away all hardcoded theme colors (like the default white text contrast), allowing you to build custom interactive components using strictly DSL modifiers.

Fx.button("Black Text")
  .none
  .bg(Colors.slate50)
  .textColor(Colors.black)
  .rounded

Sizes

Control button density using preset size modifiers.

Fx.button("Tiny").sizeXs()
Fx.button("Small").sizeSm()
Fx.button("Default") // md
Fx.button("Large").sizeLg()
Fx.button("Extra Large").sizeXl()

Modifiers

Fluxy buttons support fluent modifiers for rapid customization.

ModifierDescriptionExample
.roundedMakes the button pill-shaped.rounded
.squareRemoves all border radius.square
.fullWidth()Expands to fill available width.fullWidth()
.loading(bool)Replaces content with a spinner.loading(isLoading.value)
.withIcon(Widget)Adds a leading icon.withIcon(Icon(Icons.add))
.withTrailing(Widget)Adds a trailing icon.withTrailing(Icon(Icons.arrow_right))
.shadowSm()Adds subtle elevation.shadowSm()

API Reference

Properties

NameTypeDefaultDescription
labelStringrequiredThe text content of the button.
onTapVoidCallback?nullCallback when button is pressed.
variantFxButtonVariantprimaryVisual style of the button.
sizeFxButtonSizemdSize density token.
isLoadingboolfalseWhether to show a spinner.
styleFxStyle?nullCustom atomic style override.

Variants

  • primary: Standard brand action (White text contrast).
  • secondary: Muted action.
  • danger: Destructive action (Red).
  • success: Positive action (Green).
  • warning: Cautionary action (Orange).
  • outline: Transparent background with border.
  • ghost: No background or border until hover.
  • text: Pure text action with primary tint.
  • none: Completely unstyled. Honors all manual .bg() and .textColor() modifiers without theme overrides.

Buttonizers (Extension API)

Turn any String or Widget into a button instantly using the .btn() extension.

"Login".primaryBtn(onTap: () => login())

Icon(Icons.settings).btn(onTap: () => openSettings())

The Master Button Implementation

In a professional application, you don't just use a single button. You create a cohesive set of actions with consistent spacing, variants, and responsive behavior. Here is a complex "Action Bar" example using Fluxy's atomic button system.

class ProfileActionView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final isLoading = flux(false);

    return Fx.col(
      gap: 20,
      children: [
        // 1. Primary Action Group (Responsive)
        Fx.layout(
          mobile: Fx.col(
            gap: 12,
            children: [
              Fx.button("Complete Profile").primary.fullWidth(),
              Fx.button("Skip for now").outline.fullWidth(),
            ],
          ),
          tablet: Fx.row(
            gap: 16,
            children: [
              Fx.button("Complete Profile").primary.sizeLg(),
              Fx.button("Skip for now").outline.sizeLg(),
            ],
          ),
        ),

        // 2. Interaction-Only Primitive (.none variant)
        // Building a custom interactive card with no default button styles
        Fx.button("")
          .none
          .bg(FxTokens.colors.card)
          .rounded(16)
          .border(1, FxTokens.colors.border)
          .p(20)
          .onTap(() => print("Custom Card Tapped"))
          .child(
            Fx.row(
              children: [
                Icon(Icons.verified_user).color(Fx.primary),
                Fx.text("Upgrade to Pro").font.md().ml(4),
                Spacer(),
                Icon(Icons.chevron_right),
              ],
            )
          ),

        // 3. Destructive Guard (Dynamic State)
        Fx(() => Fx.button("Delete Account")
          .danger
          .outline
          .loading(isLoading.value) // Built-in reactive loading
          .onTap(() async {
            isLoading.value = true;
            await Future.delayed(Duration(seconds: 2));
            isLoading.value = false;
            Fx.toast.info("Account Deleted (Demo)");
          })
          .fullWidth()
        ),

        // 4. Iconic Actions
        Fx.row(
          gap: 12,
          children: [
            Fx.button("Share").withIcon(Icon(Icons.share)).secondary,
            Fx.button("Export").withTrailing(Icon(Icons.download)).secondary,
          ],
        ),
      ],
    );
  }
}

Fluxy's button system is built for composition. Use .none when you want only the tap-logic, and semantic variants like .primary or .danger when you want pre-styled, branded UI.

On this page