-1

I'm trying to create a simple button component in a Next App using Tailwind CSS where I'm passing some values as background, color, etc in the button props and I want to get this values in my component and then render my button with that props. I've more than one type of button in my app.

That's my colors options:

export type ColorOptions =
  | "light"
  | "primary"
  | "secondary"
  | "terciary"
  | "details";

Here is my button component:

import { ButtonHTMLAttributes } from "react";
import { ColorOptions, FontOptions } from "@/app/@types/theme";

type ButtonNativeProps = ButtonHTMLAttributes<HTMLButtonElement>;

type ButtonProps = ButtonNativeProps & {
  children: React.ReactNode;
  onClick: () => void;
  color?: ColorOptions;
  background?: ColorOptions;
  font?: FontOptions;
  fontSize?: string;
  icon?: React.ReactNode;
  styleProps?: string;
};

export default function Button({
  children,
  onClick,
  color = "light",
  background = "terciary",
  font = "main",
  fontSize = "xl",
  icon,
  styleProps,
  ...props
}: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={`font-${font} bg-${background}-100 text-${color}-100 text-${fontSize} flex flex-row px-6 py-3 rounded-small font-bold tracking-wide transition hover:bg-${background}-75 animation ${styleProps}`}
      {...props}
    >
      {children}
      {icon}
    </button>
  );
}

And my tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      colors: {
        light: {
          100: "#FFFFFF",
        },
        primary: {
          100: "#383436",
          75: "rgba(56, 52, 54, 0.75)",
          50: "rgba(56, 52, 54, 0.5)",
        },
        secondary: {
          100: "#3891A6",
          75: "rgba(56, 145, 166, 0.75)",
          50: "rgba(56, 145, 166, 0.5)",
        },
        terciary: {
          100: "#DB5461",
          75: "rgba(219, 84, 97, 0.75)",
          50: "rgba(219, 84, 97, 0.5)",
        },
        details: {
          100: "#61ED46",
          75: "rgba(97, 237, 70, 0.75)",
          50: "rgba(97, 237, 70, 0.5)",
        },
      },
      fontFamily: {
        title: ["Jost", "serif"],
        main: ["Nunito Sans", "serif"],
        code: ["Fira Code", "sans-serif"],
      },
      borderRadius: {
        small: "0.625rem",
        large: "1.25rem",
      },
    },
  },
  plugins: [],
  darkMode: "class",
};

I'm having the following first result Initial return

But if I put a value in the button component as here my result just disappears

<Button background="details" onClick={() => {}} />

My component don't have the background color

The worst is that the class is present in my html element, as we can check on browser's elements tree.Classes in my component with correctly values

1 Answers1

0

As per the documentation:

The most important implication of how Tailwind extracts class names is that it will only find classes that exist as complete unbroken strings in your source files.

If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS:

Don’t construct class names dynamically

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes. Instead, make sure any class names you’re using exist in full:

Always use complete class names

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

You could consider:

  • Using full class names in the props, like:
    export default function Button({
      children,
      onClick,
      color = "text-light-100",
      background = "bg-terciary-100 hover:bg-terciary-75",
      font = "font-main",
      fontSize = "text-xl",
      icon,
      styleProps,
      ...props
    }: ButtonProps) {
      return (
        <button
          onClick={onClick}
          className={`${font} ${background} ${color} ${fontSize} flex flex-row px-6 py-3 rounded-small font-bold tracking-wide transition animation ${styleProps}`}
    
  • Using class maps:
    const COLOR = {
      light: 'text-light-100',
      …
    };
    
    const BACKGROUND = {
      terciary: 'bg-terciary-100 hover:bg-terciary-75',
      …
    };
    
    const FONT = {
      main: 'font-main',
      …
    };
    
    const FONT_SIZE = {
      xl: 'text-xl',
      …
    };
    
    export default function Button({
      children,
      onClick,
      color = "light",
      background = "terciary",
      font = "main",
      fontSize = "xl",
      icon,
      styleProps,
      ...props
    }: ButtonProps) {
      return (
        <button
          onClick={onClick}
          className={`${FONT[font]} ${BACKGROUND[background]} ${COLOR[color]} ${FONT_SIZE[fontSize]} flex flex-row px-6 py-3 rounded-small font-bold tracking-wide transition animation ${styleProps}`}
    
  • Using safelist in your Tailwind configuration:
    /** @type {import('tailwindcss').Config} */
    module.exports = {
      …
      safelist: [
        { pattern: /^(bg|text)-.+-100$/ },
        { pattern: /^bg-.+-75$/, variants: ['hover'] },
        { pattern: /^font-(title|main|code|sans|sans-serif|mono)$/ },
        { pattern: /^text-(xs|sm|base|lg|[0-9]?xl)$/ },
      ],
    }
    
Wongjn
  • 8,544
  • 2
  • 8
  • 24