0

I am developing an Electron application using React and Vite, incorporating the @heroui/react library (a UI component set) for buttons. The buttons display the click animation (ripple effect) correctly, but the color styles (e.g., color="primary" or variant="solid") and hover effects are not being applied. A CSS file (index-BQqo9mII.css) is generated by Vite and located in the out/renderer/assets directory, but it seems it is either not loading or the styles are not being properly generated/applied.

  • Environment: Electron with Electron-Vite, React, Tailwind CSS v4, and HeroUI.
  • Symptoms:
    • The click animation (ripple effect) works.
    • Color and style properties of the buttons (e.g., bg-primary) are not applied.
    • Errors related to PostCSS configuration and Tailwind v4 incompatibility have been encountered.

Solutions Attempted

  1. Initial CSS Path Configuration:
    • Configured the CSS file path in index.html (located at src/renderer/index.html) with <link rel="stylesheet" href="./out/renderer/assets/index-BQqo9mII.css" />, but it was not found in dev mode.
  2. Simplifying index.html:
    • Removed the CSS link and relied on Vite to inject the styles, but the styles were still not applied.
  3. Configuring vite.config.js:
    • Set outDir to out/renderer and assetsDir to assets.
    • Added ssr.noExternal for @heroui/react to resolve SSR errors.
    • Included React and PostCSS plugins with tailwindcss.
  4. Resolving Tailwind v4 Errors:
    • Replaced @tailwind base and @tailwind components with @import "tailwindcss/preflight" and removed components.
  5. Updating Packages:
    • Updated versions of @heroui/react, tailwindcss, postcss, and autoprefixer to the latest releases.
  6. Installing and Configuring @tailwindcss/postcss:
    • Installed the @tailwindcss/postcss package and replaced tailwindcss with it in vite.config.js.
  7. Project Cleanup:
    • Deleted node_modules and package-lock.json and rebuilt with npm install.
  8. Manual Loading of HeroUI Styles:
    • Added @import "@heroui/react/dist/index.css" to index.css.

Codes Used

File src/renderer/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>PingPlus</title>
  <!-- Vite automatically injects CSS here -->
</head>
<body>
  <div id="root"></div>
  <script type="module" src="./main.tsx"></script>
</body>
</html>

File src/renderer/index.css

@import "tailwindcss/preflight";
@tailwind utilities;

/* Import HeroUI styles */
@import "@heroui/react/dist/index.css";

body {
  background-color: lightgray;
}

File vite.config.js

const { defineConfig } = require("electron-vite");
const react = require("@vitejs/plugin-react");
const tailwindcssPostcss = require("@tailwindcss/postcss");

module.exports = defineConfig({
  main: {
    build: {
      rollupOptions: {
        input: "src/main/index.js",
      },
    },
  },
  preload: {
    build: {
      rollupOptions: {
        input: "src/preload/index.js",
      },
    },
  },
  renderer: {
    build: {
      rollupOptions: {
        input: "index.html",
      },
      outDir: "out/renderer",
      assetsDir: "assets",
      emptyOutDir: false,
      minify: false,
    },
    resolve: {
      alias: {
        "@": "src",
      },
    },
    plugins: [react()],
    css: {
      postcss: {
        plugins: [tailwindcssPostcss],
      },
    },
    server: {
      open: true,
      watch: {
        usePolling: true,
      },
    },
    ssr: {
      noExternal: ["@heroui/react"],
    },
  },
});

File src/renderer/App.tsx

import React from "react";
import { Button } from "@heroui/react";

export default function App() {
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold">Test HeroUI</h1>
      <Button color="primary" variant="solid">
        Primary Solid
      </Button>
      <Button color="danger" variant="solid" className="ml-2">
        Danger Solid
      </Button>
      <Button color="warning" variant="light" className="ml-2">
        Warning Light
      </Button>
    </div>
  );
}

File src/renderer/TitleBar.tsx

import React from "react";
import { Button } from "@heroui/react";

export default function TitleBar() {
  const handleMinimize = () => {
    window.electronAPI.minimize();
  };

  const handleClose = () => {
    window.electronAPI.close();
  };

  return (
    <div
      data-tauri-drag-region
      className="h-10 bg-gray-900 flex items-center justify-between p-0 text-white shadow-md"
    >
      <span className="font-semibold pl-2">PingPlus</span>
      <div className="flex gap-0">
        <Button
          size="sm"
          color="warning"
          variant="solid"
          onClick={handleMinimize}
          className="w-10 h-10"
        >
          -
        </Button>
        <Button
          size="sm"
          color="danger"
          variant="solid"
          onClick={handleClose}
          className="w-10 h-10"
        >
          X
        </Button>
      </div>
    </div>
  );
}

File src/renderer/main.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { HeroUIProvider } from "@heroui/react";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <HeroUIProvider>
      <App />
    </HeroUIProvider>
  </React.StrictMode>
);

File tailwind.config.js

const { heroui } = require("@heroui/react");

module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  darkMode: "class",
  plugins: [heroui()],
};

Commands Executed

  • npm install @heroui/react@latest tailwindcss@latest postcss@latest autoprefixer@latest
  • npm install @tailwindcss/postcss
  • npm cache clean --force
  • Remove-Item -Recurse -Force node_modules
  • Remove-Item -Force package-lock.json
  • npm install
  • npm run dev:electron
2
  • This question is similar to: Electron-vite + React + Tailwindcss v4. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Aug 21 at 16:59
  • I will never understand why anyone would use AI instead of clear guidelines to start a project. For this to give a perfect result, the AI would basically just need to be up to date with the latest data - otherwise the outcome is completely hallucinatory. Commented Aug 21 at 17:00

1 Answer 1

0

Follow the installation guides instead.

If you use TailwindCSS with Vite, you no longer need PostCSS.

Follow instructions for HeroUI v2.8 with TailwindCSS v4:

npm uninstall @tailwindcss/postcss postcss postcss-import autoprefixer
npm install tailwindcss @tailwindcss/vite
npm install @heroui/react@latest

./vite.config.ts

// New Vite plugin for TailwindCSS:
// https://tailwindcss.com/docs/upgrade-guide#using-vite

import { defineConfig } from 'vite'
import electron from 'vite-plugin-electron'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite' // import here

export default {
  plugins: [
    tailwindcss(), // use here
    react(),
    electron({
      main: {
        entry: 'electron/main.ts',
      },
      preload: {
        input: path.join(__dirname, 'electron/preload.ts'),
      },
      renderer: process.env.NODE_ENV === 'test'
        ? undefined
        : {},
    }),
  ],
}

The @tailwind directive has been removed.

./src/renderer/index.css

/* For TailwindCSS v4 instead of @tailwind */
/* https://tailwindcss.com/docs/upgrade-guide#removed-tailwind-directives */
@import "tailwindcss";

/* For HeroUI v2.8 */
/* Use this instead of plugins: [heroui()] */
/* https://www.heroui.com/docs/guide/tailwind-v4#without-tailwindconfigjs */
@plugin './hero.ts';

/* Note: You may need to change the path to fit your project structure */
@source '../../node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}';
@custom-variant dark (&:is(.dark *));

/* Always use @layer when declare your reset CSS */
/* See more: https://stackoverflow.com/a/79441699/15167500 */
@layer base {
  body {
    background-color: lightgray;
  }
}

./src/renderer/hero.ts

// hero.ts
import { heroui } from "@heroui/react";
// or import from theme package if you are using individual packages.
// import { heroui } from "@heroui/theme";
export default heroui();

The tailwind.config.js file has been removed.

./src/renderer/index.css

/* Previous content here */
/* ... */

/* Use @custom-variant dark instead of dark: "class" */
/* https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually */
@custom-variant dark (&:where(.dark, .dark *));

/* CSS-first configuration instead of tailwind.config.js here */
@theme {
  /* Use @theme namespaces instead of theme.extend = { ... } */
  /* https://tailwindcss.com/docs/theme */
}

And the content property in the config file has been deprecated - instead, get to know automatic source detection:

And boom, it works.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.