DEV Community

Gabriel Linassi
Gabriel Linassi

Posted on


How to create a polymorphic Button with variants in NextJS + TailwindCSS + TS + RadixUI

This is a quick post just to share a nice way how to do it with full TypeScript support. It uses RadixUI Slot component for the polymorphism.

import React, { forwardRef } from 'react';
import { cnMerge } from 'common/cn-merge';
import { Slot } from '@radix-ui/react-slot';

const baseClasses = /*tw:*/ `inline-flex items-center justify-center gap-2 font-bold text-center rounded-md`;

const variantsLookup = {
  solid: /*tw:*/ `text-white bg-primary hover:shadow-button duration-100`,
  outline: /*tw:*/ `text-primary border border-blue-300 hover:bg-blue-600 hover:border-primary`,
  subtle: /*tw:*/ `text-primary hover:bg-blue-600`,

const sizesLookup = {
  base: /*tw:*/ `px-5 py-2.5`,

type ButtonProps = {
  children: React.ReactNode;
  variant?: 'outline' | 'solid' | 'subtle';
  size?: 'base';
  href?: string;
  className?: string;
  asChild?: boolean;

const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
  const { children, variant, size, asChild, className, } = props;

  const classes = cnMerge([
    variantsLookup[variant || 'solid'],
    sizesLookup[size || 'base'],

  const Comp = asChild ? Slot : 'button';

  return (
    <Comp {} className={classes} ref={ref}>

export default Button;
Enter fullscreen mode Exit fullscreen mode


<NextLink href="/extension" passHref>
  <Button asChild>
      <ExtensionIcon />
      Install Chrome Extension

/* ---- */

<Button asChild>
  <a href="" target="_blank" rel="noopener noreferrer">
    <ExtensionIcon />
    Install Chrome Extension

Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Top Posts from the React Ecosystem

1. Changes In The Official React Documentation

The former React Docs Beta has been officially released as the updated React documentation at after years of hard work and refinement. Check out the brand new React Docs: What’s New in the Updated React Docs

2. CRA's Time is Over

React developer team has removed create-react-app (CRA) from official documentation rendering it no longer the default setup method for new projects. The bulky setup, slow, and outdated nature of CRA led to its removal: create-react-app is officially dead

3. How to Fetch Articles for Your Portfolio

Integrate the articles of your profile into your personal portfolio with either React, Vue, or Next.js by following these simple steps. It outlines how to include frontend to pull the information and correctly utilizes the API: How to Fetch Your Articles for Your Portfolio with React