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.
1. Install required dependencies
If you use yarn:
shellyarn add clsx
or use npm:
shellnpm install clsx
2. Quick using
Create a SpinLoadingIcon.tsx file in folder /components/icons/SpinLoadingIcon.tsx
jsximport clsx from "clsx"; import React from "react"; const SpinLoadingIcon = (props: React.ComponentPropsWithoutRef<"svg">) => { const { className, ...rest } = props; return ( <svg className={clsx("-ml-1 mr-3 h-5 w-5 animate-spin", className)} // Merge custom classes xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" > <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" ></circle> <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" ></path> </svg> ); }; export default SpinLoadingIcon;
Create a Button.tsx file in folder /components/common/Button.tsx
jsximport clsx from "clsx"; import Link from "next/link"; import React from "react"; 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 dark:bg-zinc-700 dark:hover:bg-zinc-600 dark:active:bg-zinc-700 dark: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 dark:bg-zinc-800/50 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-zinc-50 dark:active:bg-zinc-800/50 dark:active:text-zinc-50/70`, }; type ButtonProps = { variant?: keyof typeof variantStyles; isATag?: boolean; isLoading?: boolean; rounded?: boolean; children: any; } & ( | (React.ComponentPropsWithoutRef<"button"> & { href?: undefined }) | React.ComponentPropsWithoutRef<typeof Link> ); const Button = ({ variant = "primary", className, isATag = false, children, isLoading, rounded = true, ...props }: ButtonProps) => { className = clsx( `${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", className, ); if (isATag) return ( // @ts-ignore: 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.1 Shapes
jsx<Button>Click here!</Button> <Button rounded={false}>Click here!</Button>
2.3 Primary and secondary buttons
jsx<Button>Click here!</Button> <Button variant="secondary">Click here!</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>