DEV Community

Andy Leverenz
Andy Leverenz

Posted on • Originally published at web-crunch.com on

How I Create a Tailwind CSS Plugins from Scratch

This tutorial guides you through creating a custom Tailwind CSS plugin to add a variety of button styles. I find it an excellent way to rinse and reuse button components in the multiple prototype-like apps I build yearly. We'll cover designs like solid, outline, and ghost buttons, each with customizable colors and hover states.

Why Tailwind CSS plugins?

From the Tailwind CSS docs,

Plugins let you register new styles for Tailwind to inject into the user’s stylesheet using JavaScript instead of CSS.

This is handy when leveraging reusable tailwind components or styles across different apps, websites, or environments.

Prerequisites

  • Familiarity with Tailwind CSS is super useful to have!
  • Node.js and yarn or npm installed.

Install Vite.js

I’ll be using vite.js to make use of Tailwind CSS. I reach for it when I need something more static in production. Folks who have followed me might know I usually use Ruby on Rails for my full-stack framework of choice. This guide applies to everything in that environment, too, but this guide is less about Rails.

Alright, let’s install Vite. You’ll want to create a new app using the following command. Follow the steps and choose vanilla JavaScript to keep things simple.

yarn create vite
Enter fullscreen mode Exit fullscreen mode

When naming the project, I chose:

tailwindcss-button-plugin
Enter fullscreen mode Exit fullscreen mode

Choose vanilla JavaScript for any option that prompts you and run

cd tailwindcss-button-plugin
yarn
yarn dev

Enter fullscreen mode Exit fullscreen mode

This should boot a development server and give you a localhost link to visit.

Install Tailwind CSS

Next, we need Tailwind CSS installed.

yarn add tailwindcss postcss autoprefixer -D
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

These two commands install Tailwind CSS dependencies in the project and create a tailwind.config.js file and a postcss.config.js file.

Created Tailwind CSS config file: tailwind.config.js
Created PostCSS config file: postcss.config.js
Enter fullscreen mode Exit fullscreen mode

Inside the tailwind.config.js file, we can add the following.

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {}
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Inside the style.css file, I'll remove the current contents and add the following Tailwind directives.

/* style.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Navigating back to the localhost path Vite supplied us, we should see the browser reset. Tailwind CSS is working, but it’s not apparent until we code.

I’ll remove all default content from the app so we have a clean slate.

<!-- index.html -->
  <!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Tailwind CSS Button Plugin Tutorial</title>
</head>

<body>

  <script type="module" src="/main.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode
// main.js
import "./style.css"

Enter fullscreen mode Exit fullscreen mode

You can just delete all the SVG assets, too. With this configuration complete, we are ready to write the plugin.

Step 1: Setting the Plugin File

In the app's root directory, create a new file for the plugin named tailwind-custom-buttons.js. You can call this whatever you like.

// tailwind-custom-buttons.js
module.exports = function({ addComponents }) {
    // Our button styles will be added here
};
Enter fullscreen mode Exit fullscreen mode

We’ll need to export a function with built-in helper functions that give us access to various parts of the tailwind library.

Step 2: Writing the Button Styles

We'll create several button styles: solid, outline, and ghost. Here's how you can define them:

module.exports = function({ addComponents, theme }) {
    const buttons = {
        '.btn': {
            padding: '.5rem 1rem',
            borderRadius: theme('borderRadius.md'),
            fontWeight: '600',
            display: 'inline-block',
            textAlign: 'center',
        },
        '.btn-solid': {
            backgroundColor: theme('colors.blue.500'),
            color: theme('colors.white'),
            '&:hover': {
                backgroundColor: theme('colors.blue.600'),
            },
        },
        '.btn-outline': {
            backgroundColor: 'transparent',
            color: theme('colors.blue.500'),
            border: '2px solid',
            borderColor: theme('colors.blue.500'),
            '&:hover': {
                backgroundColor: theme('colors.blue.500'),
                color: theme('colors.white'),
            },
        },
        '.btn-ghost': {
            backgroundColor: 'transparent',
            color: theme('colors.blue.500'),
            '&:hover': {
                backgroundColor: theme('colors.blue.100'),
            },
        },
        // Additional styles can be added here
    };

    addComponents(buttons);
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Testing the Plugin

Include the plugin in your tailwind.config.js:

// tailwind.config.js
module.exports = {
    // ...
    plugins: [
        require('./tailwind-custom-buttons.js'),
        // Other plugins...
    ],
};
Enter fullscreen mode Exit fullscreen mode

You can just run your build process to see the new button styles.

In the index.html file I added the following

<!-- index.html -->
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Tailwind CSS Button Plugin Tutorial</title>
</head>

<body class="bg-stone-50 text-stone-800">
  <div class="max-w-3xl mx-auto my-24">
    <h1 class="font-bold text-3xl pb-6 text-stone-800 text-center">Tailwind CSS Button Plugin Tutorial</h1>

    <div class="flex items-center justify-center gap-4">
      <button class="btn btn-solid">Solid</button>
      <button class="btn btn-outline">Outline</button>
      <button class="btn btn-ghost">Ghost</button>
      <button class="btn btn-primary">Primary</button>
      <button class="btn btn-danger">Danger</button>
      <button class="btn btn-custom">Custom</button>
    </div>
  </div>

  <script type="module" src="/main.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Step 4: Advanced Customization

Responsive and State Variants

You can easily add responsive and state variants to your buttons:

module.exports = function({ addComponents, variants }) {
    const buttons = {
        // ... your button styles
    };

    addComponents(buttons, {
        variants: ['responsive', 'hover', 'focus'],
    });
};
Enter fullscreen mode Exit fullscreen mode

This unlocks the ability to change button styles that respond to interactions and screen viewport widths.

Dynamic Theming

Allow customization of button colors by using the theme's color configuration:

'.btn-custom': {
    backgroundColor: theme('colors.custom', theme('colors.teal.500')),
    color: theme('colors.white'),
    '&:hover': {
        backgroundColor: theme('colors.customHover', theme('colors.teal.600')),
    },
},
// Similarly, add .btn-secondary, .btn-danger, etc.
Enter fullscreen mode Exit fullscreen mode

In tailwind.config.js, add custom colors if needed:

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {
      colors: {
        custom: "#f79b4b",
        customHover: "#e38a3c",
      },
    },
  },
  plugins: [require("./tailwind-custom-buttons")],
}
Enter fullscreen mode Exit fullscreen mode

Why not add these using CSS?

Well, you totally can do that. In fact, it’s pretty simple to do, but I think it boils down to reusability. If you’re on a team and build out a series of custom components like this one, you could effectively publish it as a separate repo somewhere and include it on new projects as we advance. With CSS, that’s a little harder to manage but not impossible.

I’ve primarily gone the CSS route since most of my custom CSS is relative to the application or website I’m creating and it didn’t make sense to extract into something super reusable. Your mileage may vary!

Conclusion

You've created a Tailwind CSS plugin that provides a rich set of customizable button styles. This plugin enhances your UI toolkit, enabling quick and consistent button styling across your projects.

You can experiment with different styles and configurations to tailor the plugin to your design needs. Your creativity is the limit!

Useful links

Top comments (0)