1

I'm trying to use tw-elements in a nodejs project. If I follow their documentation and just import tw-elements in my _app, I get this error:

ReferenceError: document is not defined

I found a stackoverflow response that said to put this at the start of the index.min.js file of tw-elements:

if (typeof window == "undefined")return;

I did and the error disappeared, but the library still won't work. Any ideas?

krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
Sergiu Tonț
  • 165
  • 13

6 Answers6

2

First, add Tailwind Elements using these NPM steps here.

Here is how to get it to work with Nextjs:

First step is to add this code to your _app.js file:

  useEffect(() => {
    const use = async () => {
      (await import('tw-elements')).default;
    };
    use();
  }, []);

Like this for example:

export default function App({ Component, pageProps }) {
  useEffect(() => {
    const use = async () => {
      (await import('tw-elements')).default;
    };
    use();
  }, []);
return (

Make sure you add import { useEffect } from "react"; to the top of _app.js.

It’s also important that you’re not importing Tailwind Elements anywhere else expect for the _app.js file.

Tailwind Elements should now be working!

Tyrell Curry
  • 373
  • 10
  • Please, I did what you are saying but still no component from tw-elements works for me. I am using Nextjs 13 and all these errors show up: Unhandled Runtime Error TypeError: Cannot read properties of null (reading 'style'), TypeError: Cannot read properties of null (reading 'removeAttribute'),TypeError: Cannot read properties of null (reading 'setAttribute'),Cannot read properties of null (reading 'removeAttribute') – Izzie91 Mar 05 '23 at 18:22
1

I was facing the same issue. I followed Tyrell Curry's answer but It encountered type not found error because I was using typescript. Unfortunately the type definitions were missing for tailwind-elements library.

I made a little change it the function so that type check have to be avoided by using as any.

useEffect(() => {
 const use = async () => {
  (await import("tw-elements" as any)).default;
 };
use();
}, []);
Pranu Pranav
  • 353
  • 3
  • 8
1

I was using the package Collapse and tweaked the other answers to import the specific package and call it. Worked perfectly fist time!

useEffect(() => {
  const initTE = async () => {
    const { default: initTE } = await import('tw-elements');
    const { Collapse } = await import('tw-elements'); // Import the Collapse component if needed
    initTE({ Collapse }); // Call the initTE function with the Collapse component
  };
  initTE();
}, []);
waz
  • 1,165
  • 16
  • 31
0

I ddi why you suggest with useeffect for importing "tw-elemnts"however, it remains unworking. i try to paste any code from tw-elements and nothig works

 content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
    "./src/**/*.{html,js}",
    "./node_modules/tw-elements/dist/js/**/*.js",
    "./node_modules/react-tailwindcss-datepicker/dist/index.esm.js",
  ],
  plugins: [require("tw-elements/dist/plugin"), require("@tailwindcss/forms")],
Izzie91
  • 61
  • 1
  • 2
0

For those still having issues with other answers, you can use this style of loading to make tw-elements work with NextJS:

// initialize tw-elements, we have to use this hack since tw-elements requires document to be defined which
// isn't the case when using SSR
useEffect(() => {
  const _initTE = async () => {
    const use = (await import('tw-elements')).initTE;
    const { Chart } = await import('tw-elements');
    use({ Chart });
  };
  _initTE();
}, []);
CPunkh
  • 99
  • 7
0

updated solution using Next.js 13.4.10 AppRouter

To use the component without errors, you must dynamically import with no server-side rendering. see this page.tsx

import dynamic from "next/dynamic";
const ButtonDy = dynamic(() => import("./mycomponents/Button"), {ssr: false});

export default function Home() {
  return (
    <main>
      <ButtonDy>Epic Button</ButtonDy>
    </main>
  )
}

Here is the 'Button.tsx' component:

'use client'

import React, { useEffect } from "react";
import { initTE, Ripple } from "tw-elements";

const Button: React.FC<{
  children?: React.ReactNode,
}> = ({
  children,
}) => {
  useEffect(() => {
    initTE({ Ripple });
  }, []);
  return(<>
    <button
      type="button"
      data-te-ripple-init
      data-te-ripple-color="light"
      className="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] dark:shadow-[0_4px_9px_-4px_rgba(59,113,202,0.5)] dark:hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)]">
      {children}
    </button>
  </>);
}

export default Button;

original solution on Tailwind Elements Docs https://tailwind-elements.com/docs/standard/integrations/next-integration/

BeToast
  • 28
  • 5