S

Buttons

Configure submit, next, and back buttons for your forms.

Buttons

@saastro/forms provides three button types for form navigation and submission:

ButtonPurposeWhen Shown
submitSubmit the formOn the last step
nextGo to next stepOn non-final steps
backReturn to previous stepWhen there’s step history

Basic Configuration

const config = FormBuilder.create('wizard')
  .addField('name', (f) => f.type('text').label('Name'))
  .addField('email', (f) => f.type('email').label('Email'))
  .addStep('step1', ['name'])
  .addStep('step2', ['email'])
  .buttons({
    submit: {
      type: 'submit',
      label: 'Send',
      variant: 'default',
    },
    next: {
      type: 'next',
      label: 'Continue',
      variant: 'default',
    },
    back: {
      type: 'back',
      label: 'Back',
      variant: 'outline',
    },
  })
  .build();

Button Properties

Common Properties

PropertyTypeDefaultDescription
type'submit' | 'next' | 'back'-Button type (required)
labelstringAutoButton text
variantstring'default'Visual style
sizestring'md'Button size
iconReactNode-Icon element
iconPosition'left' | 'right''right'Icon placement
disabledbooleanfalseDisable button

Variants

variant: 'default'; // Primary solid background
variant: 'secondary'; // Secondary muted background
variant: 'outline'; // Border only
variant: 'ghost'; // No background, subtle hover
variant: 'destructive'; // Red/danger style
variant: 'link'; // Looks like a link

Sizes

size: 'xs'; // Extra small
size: 'sm'; // Small
size: 'md'; // Medium (default)
size: 'lg'; // Large
size: 'xl'; // Extra large

Effects

Special hover/interaction effects:

effect: 'default'; // Standard button
effect: 'expandIcon'; // Icon expands on hover
effect: 'ringHover'; // Ring appears on hover
effect: 'shine'; // Continuous shine animation
effect: 'shineHover'; // Shine on hover only
effect: 'gooeyRight'; // Gooey effect to right
effect: 'gooeyLeft'; // Gooey effect to left
effect: 'underline'; // Underline always visible
effect: 'hoverUnderline'; // Underline on hover

Button Icons

Add icons to buttons using React components:

import { ArrowRight, ArrowLeft, Send } from 'lucide-react';

.buttons({
  submit: {
    type: 'submit',
    label: 'Send Message',
    icon: <Send className="h-4 w-4" />,
    iconPosition: 'right',
  },
  next: {
    type: 'next',
    label: 'Continue',
    icon: <ArrowRight className="h-4 w-4" />,
    iconPosition: 'right',
  },
  back: {
    type: 'back',
    label: 'Go Back',
    icon: <ArrowLeft className="h-4 w-4" />,
    iconPosition: 'left',
  },
})

Button Alignment

Control horizontal alignment of the button container:

.buttons({
  align: 'start',       // Left aligned
  align: 'center',      // Center aligned
  align: 'end',         // Right aligned (default)
  align: 'between',     // Space between (back left, next/submit right)
  align: 'responsive',  // Stacked on mobile, right-aligned on desktop
  // ...
})

Visual Examples

align: 'start'
[Back] [Submit]

align: 'center'
              [Back] [Submit]

align: 'end'
                              [Back] [Submit]

align: 'between'
[Back]                              [Submit]

align: 'responsive' (mobile)
[Submit]
[Back]

align: 'responsive' (desktop)
                              [Back] [Submit]

Inline Buttons

Place buttons on the same row as fields (useful for search forms):

const config = FormBuilder.create('search')
  .layout('manual')
  .columns(12)
  .addField('query', (f) =>
    f.type('text').label('Search').hideLabel().placeholder('Search...').columns({ default: 10 }),
  )
  .addStep('main', ['query'])
  .buttons({
    inline: true, // Same row as fields
    submit: {
      type: 'submit',
      label: 'Search',
    },
  })
  .build();

Multi-Step Form Example

Complete example with navigation buttons:

import { FormBuilder } from '@saastro/forms';
import { ArrowRight, ArrowLeft, Check } from 'lucide-react';

const config = FormBuilder.create('onboarding')
  .layout('manual')
  .columns(12)

  // Step 1: Personal Info
  .addField('name', (f) =>
    f.type('text').label('Full Name').required().columns({ default: 12, md: 6 }),
  )
  .addField('email', (f) =>
    f.type('email').label('Email').required().columns({ default: 12, md: 6 }),
  )

  // Step 2: Preferences
  .addField('theme', (f) =>
    f
      .type('select')
      .label('Theme')
      .options([
        { value: 'light', label: 'Light' },
        { value: 'dark', label: 'Dark' },
        { value: 'system', label: 'System' },
      ]),
  )

  // Step 3: Confirmation
  .addField('terms', (f) =>
    f.type('checkbox').label('I accept the terms and conditions').required(),
  )

  // Define steps
  .addStep('personal', ['name', 'email'])
  .addStep('preferences', ['theme'])
  .addStep('confirmation', ['terms'])
  .initialStep('personal')

  // Configure buttons
  .buttons({
    align: 'between',
    submit: {
      type: 'submit',
      label: 'Complete',
      icon: <Check className="h-4 w-4" />,
      variant: 'default',
    },
    next: {
      type: 'next',
      label: 'Continue',
      icon: <ArrowRight className="h-4 w-4" />,
      variant: 'default',
    },
    back: {
      type: 'back',
      label: 'Previous',
      icon: <ArrowLeft className="h-4 w-4" />,
      iconPosition: 'left',
      variant: 'outline',
    },
  })

  .build();

Custom Button Actions

Override default button behavior:

.buttons({
  back: {
    type: 'back',
    label: 'Cancel',
    action: () => {
      // Custom action instead of going back
      if (confirm('Are you sure you want to cancel?')) {
        window.location.href = '/';
      }
    },
  },
})

API Reference

FormButtons Interface

interface FormButtons {
  submit?: ButtonConfig;
  next?: ButtonConfig;
  back?: ButtonConfig;
  align?: 'start' | 'center' | 'end' | 'between' | 'responsive';
  inline?: boolean;
}

ButtonConfig Interface

interface ButtonConfig {
  type: 'button' | 'submit' | 'next' | 'back';
  label?: string;
  action?: () => void;
  loading?: boolean;
  icon?: ReactNode;
  iconPosition?: 'left' | 'right';
  variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
  effect?:
    | 'default'
    | 'expandIcon'
    | 'ringHover'
    | 'shine'
    | 'shineHover'
    | 'gooeyRight'
    | 'gooeyLeft'
    | 'underline'
    | 'hoverUnderline';
  rounded?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';
  disabled?: boolean;
}