Button
The Button component is a versatile UI element used to trigger actions, navigate users, or submit forms. It supports various styles, sizes, loading, and states to fit different use cases. Designed for flexibility, it can be easily customized to match your application's theme.
Buttons preview
Please install everything that's required
1. Quick setup
Create a SpinLoadingIcon.tsx file in folder /components/icons/SpinLoadingIcon.tsx
jsximport React from "react"; import { cn } from "@/utils/cn"; const sizeMap: { [key: number]: string } = { 4: "w-4 h-4", 5: "w-5 h-5", 6: "w-6 h-6", 7: "w-7 h-7", 8: "w-8 h-8", 10: "w-10 h-10", 12: "w-12 h-12", }; const SpinLoadingIcon = ({ size = 5, className, ...rest }: { size?: number; className?: string; }) => { return ( <svg className={cn( `-ml-1 mr-3 animate-spin`, sizeMap[size], // Fallback to w-5 h-5 if size is not mapped className, )} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" {...rest} > <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /> </svg> ); }; export default SpinLoadingIcon;
Create a Button.tsx file in folder /components/common/Button.tsx
jsximport React from "react"; import Link from "next/link"; import { cn } from "@/utils/cn"; import SpinLoadingIcon from "./icons/SpinLoadingIcon"; const variantStyles = { primary: `bg-primary font-semibold text-white hover:opacity-80 active:bg-zinc-800 active:text-zinc-100/70`, secondary: `bg-zinc-50 font-medium text-zinc-900 border border-gray-300 hover:opacity-80 active:bg-zinc-100 active:text-zinc-900/60`, }; type ButtonProps = { variant?: keyof typeof variantStyles; isATag?: boolean; isLoading?: boolean; rounded?: boolean; shadow?: boolean; children: any; } & ( | (React.ComponentPropsWithoutRef<"button"> & { href?: undefined }) | React.ComponentPropsWithoutRef<typeof Link> ); const Button = ({ variant = "primary", className, isATag = false, children, isLoading, rounded = true, shadow = false, ...props }: ButtonProps) => { className = cn( `${rounded ? "rounded-full" : "rounded-md"} inline-flex items-center gap-1 justify-center py-2 px-3 text-sm outline-offset-2 transition active:transition-none`, variantStyles[variant], isLoading ? "cursor-not-allowed bg-gray-400 opacity-60" : "cursor-pointer", shadow && "shadow-md hover:shadow-lg", className, ); if (isATag) return ( // @ts-expect-error: Unreachable code error <a className={className} {...props}> {children} </a> ); return typeof props.href === "undefined" ? ( <button className={className} {...props} disabled={isLoading}> {isLoading && ( <SpinLoadingIcon className={`${variant === "secondary" ? "text-primary" : "text-white"} `} /> )} {children} </button> ) : ( <Link className={className} {...props}> {children} </Link> ); }; export default Button;
2. Usages
2.1 Shapes
jsx<Button>Click here!</Button> <Button rounded={false}>Click here!</Button>
2.2 Primary and secondary buttons
jsx<Button>Click here!</Button> <Button variant="secondary">Click here!</Button>
2.3 Shadow button
jsx<Button shadow>Shadow Button</Button>
2.4 Loading button
Sometimes, when you call the API so you want the user see the loading and user can not click on your button, so you need the loading button:
jsx<Button isLoading>is loading ...</Button>
2.5 Button with icon
If you want to add icon on your button like: download button, back button, forward button, ... just add inside Button component like the children:
Notes: If you want use the icon like me, just refer this link
jsximport { ArrowDownTrayIcon } from "@heroicons/react/24/solid"; <Button isLoading> Download <ArrowDownTrayIcon aria-hidden="true" className="size-5 font-semibold" /> </Button>
2.6 Button as a link (using Link component from NextJs)
Sometimes, if you want to use the link to navigate but you want the link with UI like button. Just simple add the href in Button. The Button component will use the Link component from NextJs.
jsx<Button href="/internal-path">Click here!</Button>
2.7 Button as <a> tag
Sometimes, if you want to use the a tag as the button, you can add the href and set isTag=true for Button component. The Button component will use a tag (it works a lit bit with Link com).
jsx<Button href="/test" isATag={true}>Click here!</Button>