Submit Button
Specifically designed for form submission with built-in loading states, making it perfect for forms that need to show submission progress and prevent double submissions.
npx shadcn@latest add @shuip/submit-button
pnpm dlx shadcn@latest add @shuip/submit-button
bun x shadcn@latest add @shuip/submit-button
import { Loader2Icon } from 'lucide-react';
import type * as React from 'react';
import { Button } from '@/components/ui/button';
export interface SubmitButtonProps extends React.ComponentProps<typeof Button> {
loading?: boolean;
icon?: React.JSX.Element;
}
export function SubmitButton({
children,
disabled,
loading,
icon = <Loader2Icon className='size-4 animate-spin' aria-label='Loading' />,
...props
}: SubmitButtonProps) {
return (
<Button type='submit' aria-label='Submit' disabled={disabled || loading} {...props}>
{loading && icon}
{children || 'Submit'}
</Button>
);
}
The command is the same for Base UI and Radix: the CLI reads the style in your components.json and installs the matching variant.
Built-in features
- Automatic loading state: Shows spinner icon when
loadingprop is true - Full-width by default: Optimized for form layouts
- Customizable icon: Can override the default loading spinner
- Form integration: Native
type="submit"behavior
Common use cases
Basic form submission
<SubmitButton children="Save Changes" loading={isSaving} />
<SubmitButton loading={isSaving}>
<span className="flex items-center">
<Send className="mr-2 h-4 w-4" />
Send Message
</span>
</SubmitButton>With custom icon
<SubmitButton
children="Processing Payment"
loading={isProcessing}
icon={<CreditCard className="mr-2 h-4 w-4 animate-pulse" />}
/>With JSX label
<SubmitButton
children={
<span className="flex items-center">
<Send className="mr-2 h-4 w-4" />
Send Message
</span>
}
loading={isSending}
/>Custom styling
<SubmitButton
children="Delete Account"
loading={isDeleting}
className="bg-destructive hover:bg-destructive/90"
disabled={!confirmed}
/>Examples
Default
Loading
Props
Prop
Type