Skip to content

Instantly share code, notes, and snippets.

@KonradSzwarc
Created August 12, 2022 10:17
Show Gist options
  • Select an option

  • Save KonradSzwarc/c5c661812239f31769e4d9e37ed8ced3 to your computer and use it in GitHub Desktop.

Select an option

Save KonradSzwarc/c5c661812239f31769e4d9e37ed8ced3 to your computer and use it in GitHub Desktop.
Tailwind CSS variants
import type { ButtonProps } from './button';
type Props = Required<ButtonProps>;
export const baseClasses =
'inline-flex items-center border font-medium rounded-md enabled:shadow-sm active:enabled:translate-y-px focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500';
export const sizeClasses: Record<Props['size'], string> = {
xs: 'px-3 h-6 text-xs',
sm: 'px-4 h-8 text-sm',
md: 'px-5 h-10 text-base',
lg: 'px-6 h-12 text-lg',
xl: 'px-7 h-14 text-xl',
};
export const variantColorClasses: Record<Props['variant'], Record<Props['color'], string>> = {
filled: {
primary: 'border-transparent text-white bg-indigo-600 hover:enabled:bg-indigo-700',
danger: 'border-transparent text-white bg-red-600 hover:enabled:bg-red-700',
success: 'border-transparent text-white bg-emerald-600 hover:enabled:bg-emerald-700',
},
light: {
primary: 'border-transparent text-indigo-700 bg-indigo-100 hover:enabled:bg-indigo-200',
danger: 'border-transparent text-red-700 bg-red-100 hover:enabled:bg-red-200',
success: 'border-transparent text-emerald-700 bg-emerald-100 hover:enabled:bg-emerald-200',
},
default: {
primary: 'border-gray-300 text-gray-700 bg-white hover:enabled:bg-gray-50',
danger: 'border-gray-300 text-gray-700 bg-white hover:enabled:bg-gray-50',
success: 'border-gray-300 text-gray-700 bg-white hover:enabled:bg-gray-50',
},
};
export const disabledClasses = 'disabled:cursor-not-allowed disabled:opacity-50';
export const iconSizeClasses: Record<Props['size'], string> = {
xs: '-ml-0.5 mr-1 h-3.5 w-3.5',
sm: '-ml-0.5 mr-1.5 h-4 w-4',
md: '-ml-1 mr-2 h-4.5 w-4.5',
lg: '-ml-1 mr-2.5 h-5 w-5',
xl: '-ml-1.5 mr-3 h-6 w-6',
};
import { ComponentPropsWithoutRef, ComponentType, forwardRef, HTMLAttributes } from 'react';
import clsx from 'clsx';
import { baseClasses, disabledClasses, iconSizeClasses, sizeClasses, variantColorClasses } from './button.styles';
type ButtonVariant = 'filled' | 'light' | 'default';
type ButtonColor = 'primary' | 'danger' | 'success';
type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
export interface ButtonProps extends ComponentPropsWithoutRef<'button'> {
size?: ButtonSize;
variant?: ButtonVariant;
color?: ButtonColor;
icon?: ComponentType<HTMLAttributes<SVGSVGElement>>;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ size = 'md', variant = 'filled', color = 'primary', className, icon: Icon, children, ...props }, ref) => {
const finalClassName = clsx(
baseClasses,
sizeClasses[size],
variantColorClasses[variant][color],
disabledClasses,
className
);
const iconElement = Icon ? <Icon className={iconSizeClasses[size]} aria-hidden="true" /> : null;
return (
<button type="button" className={finalClassName} ref={ref} {...props}>
{iconElement}
{children}
</button>
);
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment