Material Tailwind with Remix

Learn how to set up Material Tailwind with Remix. This guide will walk you through installation, configuration, and basic usage.


Setting up Remix with Tailwind CSS

Start by creating a new Remix project and installing the required dependencies:

1npx create-remix@latest
2npm install -D tailwindcss postcss autoprefixer
3npx tailwindcss init -p

Configure your template paths

Update the content paths in your tailwind.config.js or tailwind.config.ts:

1// For JavaScript (tailwind.config.js)
2/** @type {import('tailwindcss').Config} */
3module.exports = {
4content: [
5  "./app/**/*.{js,jsx,ts,tsx}",
6],
7theme: {
8  extend: {},
9},
10plugins: [],
11}
12
13// For TypeScript (tailwind.config.ts)
14import type { Config } from 'tailwindcss'
15
16export default {
17content: [
18  "./app/**/*.{js,jsx,ts,tsx}",
19],
20theme: {
21  extend: {},
22},
23plugins: [],
24} satisfies Config

Add the Tailwind directives

Create a new CSS file in app/styles/tailwind.css and add the Tailwind directives:

1@tailwind base;
2@tailwind components;
3@tailwind utilities;

Import the styles

Import the styles in your app/root.tsx:

1import type { LinksFunction } from "@remix-run/node";
2import styles from "~/styles/tailwind.css";
3
4export const links: LinksFunction = () => [
5{ rel: "stylesheet", href: styles }
6];
7
8export default function App() {
9return (
10  <html lang="en">
11    <head>
12      <Meta />
13      <Links />
14    </head>
15    <body>
16      <Outlet />
17      <ScrollRestoration />
18      <Scripts />
19      <LiveReload />
20    </body>
21  </html>
22);
23}

Install Material Tailwind

Install @material-tailwind/html:

1npm i @material-tailwind/html

Example Usage

Here's how to use Material Tailwind components in your Remix routes:

1// app/routes/_index.tsx
2import { useEffect } from "react";
3import { useHydrated } from "@remix-run/react";
4import { initAccordion } from "@material-tailwind/html"; // ESM & CJS
5
6export default function Index() {
7const isHydrated = useHydrated();
8
9useEffect(() => {
10  if (isHydrated) {
11    initAccordion();
12  }
13}, [isHydrated]);
14
15return (
16  <div className="w-full">
17    <div className="group block w-full" data-accordion-container data-accordion-mode="exclusive">
18      <button
19        data-accordion-toggle
20        data-accordion-target="#accordion-1"
21        aria-expanded="false"
22        className="flex w-full items-center justify-between p-4 text-left"
23      >
24        <span>What is Material Tailwind?</span>
25        <svg
26          data-accordion-icon
27          className="h-5 w-5 rotate-0 transition-transform"
28          fill="none"
29          stroke="currentColor"
30          viewBox="0 0 24 24"
31          xmlns="http://www.w3.org/2000/svg"
32        >
33          <path
34            strokeLinecap="round"
35            strokeLinejoin="round"
36            strokeWidth="2"
37            d="M19 9l-7 7-7-7"
38          ></path>
39        </svg>
40      </button>
41      <div
42        id="accordion-1"
43        className="overflow-hidden transition-all duration-300"
44      >
45        <div className="p-4">
46          <p>
47            Material Tailwind is an easy to use components library for Tailwind CSS.
48          </p>
49        </div>
50      </div>
51    </div>
52  </div>
53);
54}

TypeScript Support

For TypeScript projects, you can use the typed interfaces and configurations:

1// app/components/Accordion.tsx
2import { useEffect } from "react";
3import { useHydrated } from "@remix-run/react";
4import { Accordion } from "@material-tailwind/html";
5import type { AccordionConfig } from "@material-tailwind/html";
6
7export default function AccordionExample() {
8const isHydrated = useHydrated();
9
10useEffect(() => {
11  if (isHydrated) {
12    const container = document.getElementById("accordion-container");
13    
14    if (container) {
15      const config: AccordionConfig = {
16        exclusive: true,
17        allOpen: false,
18      };
19      
20      new Accordion(container, config);
21    }
22  }
23}, [isHydrated]);
24
25return (
26  <div id="accordion-container" className="group block w-full">
27    <div 
28      className="flex items-center justify-between w-full py-5 text-left font-medium dark:text-white text-slate-800 cursor-pointer"
29      aria-expanded="false"
30      id="button-1">
31      Material Tailwind React
32      <svg data-accordion-icon width="1.5em" height="1.5em" strokeWidth="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="currentColor" className="h-4 w-4 transition-transform duration-300 rotate-180">
33        <path d="M6 9L12 15L18 9" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"></path>
34      </svg>
35    </div>
36    <div id="button-1" className="overflow-hidden transition-all duration-300 border-b border-slate-200 dark:border-slate-700">
37      <p className="mb-5 text-sm text-slate-600 dark:text-slate-400">Material Tailwind is an open-source library crafted with Tailwind CSS. Get Material Tailwind and take advantage of its free components and features.</p>
38    </div>
39
40    <div 
41      className="flex items-center justify-between w-full py-5 text-left font-medium dark:text-white text-slate-800 cursor-pointer"
42      aria-expanded="false"
43      id="button-2">
44      Material Tailwind HTML
45      <svg data-accordion-icon width="1.5em" height="1.5em" strokeWidth="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="currentColor" className="h-4 w-4 transition-transform duration-300 rotate-180">
46        <path d="M6 9L12 15L18 9" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"></path>
47      </svg>
48    </div>
49    <div id="button-2" className="overflow-hidden transition-all duration-300 border-b border-slate-200 dark:border-slate-700">
50      <p className="mb-5 text-sm text-slate-600 dark:text-slate-400">Material Tailwind is an open-source library crafted with Tailwind CSS. Get Material Tailwind and take advantage of its free components and features.</p>
51    </div>
52  </div>
53);
54}

TypeScript Configuration

For TypeScript projects, ensure your tsconfig.json includes:

1{
2"compilerOptions": {
3  "moduleResolution": "node",
4},
5}

Note: The TypeScript configuration above includes Remix-specific settings to ensure proper type checking and module resolution when using Material Tailwind components.


Server-Side Rendering

Since Remix uses server-side rendering, make sure to initialize components after hydration:

1import { useHydrated } from "@remix-run/react";
2import { initAccordion } from "@material-tailwind/html";
3
4export default function Component() {
5const isHydrated = useHydrated();
6
7useEffect(() => {
8  if (isHydrated) {
9    initAccordion();
10  }
11}, [isHydrated]);
12
13return (
14  // Component content
15);
16}

Note: For more examples and detailed documentation of each component, check out the Accordion component.