/v1.0

LoadingButton

LoadingButton is a full-featured button that accepts an external isLoading boolean. When loading, the label and icons are replaced with a centered spinner and the button is disabled. Unlike ActionButton, it does not manage HTTP requests — you control the loading state from outside, making it ideal for form submissions handled by hooks or stores.

The component renders centered inside a div with 20px vertical padding, making it well-suited for form footers.

Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | title | string | Yes | — | Label text displayed inside the button when not loading. | | onClick | () => void | Yes | — | Callback fired when the button is pressed. | | isLoading | boolean | No | false | When true, replaces the button content with a spinner and disables interaction. | | color | string | No | "primary" | Theme color key or any CSS hex/named color. | | borderRadius | number | No | 4 | Border radius in pixels. | | type | "clear" \| "outline" \| "solid" | No | "solid" | Visual variant of the button. | | disabled | boolean | No | false | Disables interaction independently of isLoading. | | startIcon | string | No | — | Icon identifier rendered before the label (hidden while loading). | | startIconPaths | string[] | No | — | SVG path data for a custom start icon. | | startIconSize | number | No | — | Override size for the start icon in pixels. | | startIconStyle | React.CSSProperties | No | — | Inline styles applied to the start icon. | | startIconColor | string | No | — | Color override for the start icon. | | endIcon | string | No | — | Icon identifier rendered after the label (hidden while loading). | | endIconPaths | string[] | No | — | SVG path data for a custom end icon. | | endIconSize | number | No | — | Override size for the end icon in pixels. | | endIconStyle | React.CSSProperties | No | — | Inline styles applied to the end icon. | | endIconColor | string | No | — | Color override for the end icon. | | hasShadow | boolean | No | true | Whether to apply a drop shadow. | | style | React.CSSProperties | No | — | Inline styles applied to the button container. | | titleStyle | React.CSSProperties | No | — | Inline styles applied to the label text. | | size | "xs" \| "sm" \| "md" \| "lg" \| "xl" | No | "md" | Controls padding, font size, icon size, and spinner size. | | className | string | No | "loading-button" | CSS class name applied to the wrapper. | | spinnerColor | string | No | — | Color of the loading spinner. |

Usage

Basic form submission

import LoadingButton from '@/components/buttons/LoadingButton';
import { useState } from 'react';

export default function LoginForm() {
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    setLoading(true);
    await new Promise((r) => setTimeout(r, 2000)); // simulate API call
    setLoading(false);
  };

  return (
    <LoadingButton
      title="Sign In"
      isLoading={loading}
      onClick={handleSubmit}
    />
  );
}

With icons and custom spinner color

import LoadingButton from '@/components/buttons/LoadingButton';

export default function Example({ loading }: { loading: boolean }) {
  return (
    <LoadingButton
      title="Save Changes"
      isLoading={loading}
      onClick={() => {}}
      startIcon="save"
      spinnerColor="white"
      size="lg"
    />
  );
}