Skip to main content

Overview

HuxButton is a versatile button component that provides multiple visual variants, sizes, loading states, and automatic WCAG AA contrast compliance. It adapts seamlessly to light and dark themes.

Basic Usage

HuxButton(
  onPressed: () => print('Button pressed!'),
  child: Text('Primary Button'),
)

Variants

HuxButton supports four visual variants through the HuxButtonVariant enum:

Primary

The default variant with a filled background using the primary color. Primary Button
HuxButton(
  onPressed: () {},
  child: Text('Primary'),
  variant: HuxButtonVariant.primary, // Default
)

Secondary

A subtle variant with a light background and border. Secondary Button
HuxButton(
  onPressed: () {},
  child: Text('Secondary'),
  variant: HuxButtonVariant.secondary,
)

Outline

A transparent button with only a border outline. Outline Button
HuxButton(
  onPressed: () {},
  child: Text('Outline'),
  variant: HuxButtonVariant.outline,
)

Ghost

A minimal transparent button without borders. Ghost Button
HuxButton(
  onPressed: () {},
  child: Text('Ghost'),
  variant: HuxButtonVariant.ghost,
)

Sizes

Control button dimensions with three size options:

Small

Compact size for tight spaces (32px height). Small Button
HuxButton(
  onPressed: () {},
  child: Text('Small'),
  size: HuxButtonSize.small,
)

Medium

Default size for most use cases (40px height). Medium Button
HuxButton(
  onPressed: () {},
  child: Text('Medium'),
  size: HuxButtonSize.medium, // Default
)

Large

Prominent size for important actions (48px height). Large Button
HuxButton(
  onPressed: () {},
  child: Text('Large'),
  size: HuxButtonSize.large,
)

States

Loading State

Display a loading indicator while processing.
class LoadingButtonExample extends StatefulWidget {
  @override
  _LoadingButtonExampleState createState() => _LoadingButtonExampleState();
}

class _LoadingButtonExampleState extends State<LoadingButtonExample> {
  bool _isLoading = false;

  void _handlePress() async {
    setState(() {
      _isLoading = true;
    });

    // Simulate async operation
    await Future.delayed(Duration(seconds: 2));

    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return HuxButton(
      onPressed: _isLoading ? null : _handlePress,
      isLoading: _isLoading,
      child: Text('Submit'),
    );
  }
}

Disabled State

Disable button interaction.
HuxButton(
  onPressed: null, // or use isDisabled: true
  child: Text('Disabled Button'),
  isDisabled: true,
)

Icons

Add icons to enhance button meaning:

Icon with Text

Icon with text Button
HuxButton(
  onPressed: () {},
  child: Text('Save'),
  icon: FeatherIcons.save,
)

Icon-only Button

Icon-only Button
HuxButton(
  onPressed: () {},
  child: Icon(FeatherIcons.heart),
  size: HuxButtonSize.small,
)

Square Icon-only Button

HuxButton(
  onPressed: () {},
  child: SizedBox(width: 0), // Icon-only with no text
  icon: FeatherIcons.heart,
  size: HuxButtonSize.medium,
  width: HuxButtonWidth.fixed,
  widthValue: 40, // Square button: 40x40
)

Width Control

Control button width behavior with the HuxButtonWidth enum:

Hug Content (Default)

Button width matches its content. Hug Content Button
HuxButton(
  onPressed: () {},
  child: Text('Short Text'),
  // width: HuxButtonWidth.hug (default)
)

Expand to Fill

Button takes full available width. Full Width Button
HuxButton(
  onPressed: () {},
  child: Text('Full Width'),
  width: HuxButtonWidth.expand,
)

Fixed Width

Button has a specific width. Fixed Width Button
HuxButton(
  onPressed: () {},
  child: Text('Fixed Width'),
  width: HuxButtonWidth.fixed,
  widthValue: 200, // 200px width
)

Custom Colors

Using Preset Colors

// Indigo theme
HuxButton(
  onPressed: () {},
  child: Text('Indigo Button'),
  primaryColor: HuxColors.getPresetColor('indigo'),
)

// Green theme
HuxButton(
  onPressed: () {},
  child: Text('Green Button'),
  primaryColor: HuxColors.getPresetColor('green'),
)

// Pink theme
HuxButton(
  onPressed: () {},
  child: Text('Pink Button'),
  primaryColor: HuxColors.getPresetColor('pink'),
)

Custom Colors

HuxButton(
  onPressed: () {},
  child: Text('Custom Purple'),
  primaryColor: Color(0xFF6366F1),
)

HuxButton(
  onPressed: () {},
  child: Text('Custom Orange'),
  primaryColor: Colors.deepOrange,
)

API Reference

HuxButton Properties

PropertyTypeDefaultDescription
onPressedVoidCallback?requiredCallback triggered when button is pressed
childWidgetrequiredThe child widget to display inside the button
variantHuxButtonVariantprimaryVisual variant of the button
sizeHuxButtonSizemediumSize variant of the button
isLoadingboolfalseWhether to show loading indicator
isDisabledboolfalseWhether the button is disabled
iconIconData?nullOptional icon to display before text
primaryColorColor?nullCustom primary color (overrides theme)

HuxButtonVariant Enum

  • HuxButtonVariant.primary - Filled background with primary color
  • HuxButtonVariant.secondary - Light background with border
  • HuxButtonVariant.outline - Transparent with border only
  • HuxButtonVariant.ghost - Transparent without border

HuxButtonSize Enum

  • HuxButtonSize.small - 32px height, compact padding
  • HuxButtonSize.medium - 40px height, standard padding
  • HuxButtonSize.large - 48px height, generous padding

Common Patterns

Form Buttons

Row(
  children: [
    Expanded(
      child: HuxButton(
        onPressed: () {},
        child: Text('Cancel'),
        variant: HuxButtonVariant.outline,
      ),
    ),
    SizedBox(width: 12),
    Expanded(
      child: HuxButton(
        onPressed: () {},
        child: Text('Submit'),
        variant: HuxButtonVariant.primary,
      ),
    ),
  ],
)

Action Buttons

Column(
  children: [
    HuxButton(
      onPressed: () {},
      child: Text('Primary Action'),
      variant: HuxButtonVariant.primary,
      size: HuxButtonSize.large,
    ),
    SizedBox(height: 12),
    HuxButton(
      onPressed: () {},
      child: Text('Secondary Action'),
      variant: HuxButtonVariant.secondary,
    ),
    SizedBox(height: 8),
    HuxButton(
      onPressed: () {},
      child: Text('Cancel'),
      variant: HuxButtonVariant.ghost,
    ),
  ],
)

Button Grid

GridView.count(
  crossAxisCount: 2,
  shrinkWrap: true,
  children: [
    HuxButton(
      onPressed: () {},
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(FeatherIcons.camera),
          SizedBox(height: 8),
          Text('Camera'),
        ],
      ),
      variant: HuxButtonVariant.outline,
    ),
    HuxButton(
      onPressed: () {},
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(FeatherIcons.image),
          SizedBox(height: 8),
          Text('Gallery'),
        ],
      ),
      variant: HuxButtonVariant.outline,
    ),
  ],
)

Accessibility

HuxButton includes several accessibility features:

Automatic Contrast

Text color is automatically calculated to ensure WCAG AA compliance (4.5:1 contrast ratio) against any background color.

Semantic Roles

Buttons include proper semantic roles for screen readers.

Focus States

Keyboard navigation support with visible focus indicators.

Disabled States

Proper disabled state handling for assistive technologies.

Best Practices

  • Use Primary for the main action on a screen
  • Use Secondary for important but not primary actions
  • Use Outline for secondary actions that need visual weight
  • Use Ghost for subtle actions like “Cancel” or “Skip”
  • Use Large for important call-to-action buttons
  • Use Medium for most standard interactions
  • Use Small for compact interfaces or secondary actions
// Always disable the button during loading
HuxButton(
  onPressed: _isLoading ? null : _handlePress,
  isLoading: _isLoading,
  child: Text('Submit'),
)
  • Use action-oriented labels: “Save”, “Delete”, “Continue”
  • Avoid generic labels: “OK”, “Submit”, “Button”
  • Keep labels concise but descriptive

Examples

I