clauderic / dnd-kit

The modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.
http://dndkit.com
MIT License
13.3k stars 658 forks source link

NextJS Compatibility? #801

Open Eduard-Hasa opened 2 years ago

Eduard-Hasa commented 2 years ago

Considering how popular NextJS is I was wondering if you guys will consider supporting it? I got it working after jumping through a few hoops but unfortunately still facing errors.

First issue was nextjs not allowing global selectors in css modules. I solved that by using a saas compiler to give me pure css. Now facing issues like

  1. keyframes() function not found
  2. document not found
  3. __webpack_require__.a is not a function

Would be so amazing if we could get sortableTree example in nextjs. Would honestly not mind donating a good amount to see this support come to light.

clauderic commented 2 years ago

The library should work with NextJS.

The issues you are mentioning seem to be related to trying to copy examples to NextJS and not the core library.

Eduard-Hasa commented 2 years ago

@clauderic Oh sorry you are right. Could I offer a generous donation for a public nextjs example of sortable tree? Technically I got it working but just feel liked I hacked my way too it and seems finicky.

AMAZING library btw. Great Job!

clauderic commented 2 years ago

I'm actually planning to release the sortable tree examples as a separate @dnd-kit package (something like @dnd-kit/sortable-tree), which should make it much easier to consume anywhere, not just for NextJS. Just haven't had time to prioritize this yet.

Eduard-Hasa commented 2 years ago

@clauderic Oh thats a great idea. Would be awesome if you made sure it works with SSR on NextJS as that is going to be one of the more popular use cases I would imagine.

This library is so amazing. Kudos to you. None others come close to it.

Eduard-Hasa commented 2 years ago

@clauderic Is there any way I can become a donor to prioritize this? Could you email me at Ed@Hasahub.com please? Really interested in coming to an agreement together.

Eduard-Hasa commented 2 years ago

@clauderic after a few hours of focus, I actually was able to quite easily get sortable tree working on nextjs. Let me know if you want a PR. Made some minor tweaks to the styling of the Sortable Tree Items as the height was not defined for some reason and caused a bunch of bugs. Simply setting height to content fit fixed it all. My fork was from your react-18-tweaks branch.

dan852 commented 2 years ago

@Eduard-Hasa , would you mind sharing your fork since i'm facing the same issues using this lib with nextjs? thanks

Eduard-Hasa commented 2 years ago

@dan852 hey certainly let me find a branch that doesn't contain any sensitive project information.

Until then:

You have to wrap the sortable tree component in a NoSSR component that disables serverside rendering since the sortable tree component needs to access to document object.

Also all of the styling needs to be fixed. I simply went to google and used an online sass compiler and converted all of the css to normal css to remove all the errors.

There was another issue with detecting if the device is iOS and I just made that static to true.

Those were the only major issues I found. Rest was easy

NishKebab commented 2 years ago

credit: blog post on disabling SSR

import dynamic from 'next/dynamic';
import React from 'react';

const NonSSRWrapper = (props: { children: any }) => <React.Fragment>{props.children}</React.Fragment>;

export default dynamic(() => Promise.resolve(NonSSRWrapper), {
  ssr: false,
});

And then you wrap the dnd-kit component with it.

const isSSR = () => typeof window === 'undefined';
export default function Container() {
  return (
    <div>
      <NonSSRWrapper>
          {!isSSR() && <MultipleContainers />}
      </NonSSRWrapper>
    </div>
  );
}

Note if you are copying from their storybook examples, the CSS will not work with nextjs and you can use a SCSS -> CSS converter..

You will also need to install the package npm i classnames to get the storybook examples to work in a nextjs project.

jonschlinkert commented 2 years ago

@NishKebab what's dynamic?

edited: sorry, somehow my eyes didn't see the very obvious link to the blog post. I found my answer.

NishKebab commented 2 years ago

import dynamic from 'next/dynamic';

edited: updated the original post.

paulm17 commented 1 year ago

My goal for today was to get the sortable tree working. I utterly failed even when presented with a sandbox example.

Luckily, I found: https://github.com/Shaddix/dnd-kit-sortable-tree

Using that as an example. I was able to get my exact use-case so I thoroughly recommend it.

Also, I'm using NextJS. I did get the SSR issue as well. But I simply use the isMounted Ref trick to ensure that the sortable only runs on client-side.

TotomInc commented 1 year ago

@paulm17 could you please provide more details about the isMounted trick?

Also, did you integrated this on Next.js 13 or 12?

paulm17 commented 1 year ago

@TotomInc You set a ref variable like

const isMountedRef = useRef(false)

and then you have a useEffect only at mount

useEffect(() => {
  isMountedRef.current = true
}, [])

and then what you want to run at mount only

<>
  {
    isMountedRef.current && <>I will only run at mount</>
  }
</>
masterkain commented 1 year ago

for next.js 13 app directory I hacked something like this:

// app/browser/layout.tsx
import { Providers } from '@/app/providers';

export default async function BrowserLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <Providers>{children}</Providers>;
}
// app/providers.tsx
'use client';

import { useDragState } from '@/lib/dragState';
import { DndContext, DragOverlay } from '@dnd-kit/core';
import { ReactNode } from 'react';

export function Providers({ children }: { children: ReactNode }) {
  const { activeId, handleDragStart, handleDragEnd } = useDragState();

  return (
    <DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
      {children}
      <DragOverlay>{activeId ? <h1>{activeId}</h1> : null}</DragOverlay>
    </DndContext>
  );
}
// lib/dragState.ts
'use client';

import type { DragStartEvent } from '@dnd-kit/core';
import { useState } from 'react';

export function useDragState() {
  const [activeId, setActiveId] = useState<string | null>(null);

  function handleDragStart(event: DragStartEvent) {
    setActiveId(event.active.id.toString());
  }

  function handleDragEnd() {
    setActiveId(null);
  }

  return {
    activeId,
    handleDragStart,
    handleDragEnd,
  };
}

also next.js authors recommends starting use client in libs

ghost commented 1 year ago

*** To make CSS nesting rules to work with Next.js:

Option 1 (If you are using Tailwind):

// postcss.config.js
module.exports = {
    plugins: {
        "postcss-import": {}, // add this
        "tailwindcss/nesting": {}, // also add this
        tailwindcss: {},
        autoprefixer: {},
    },
};

Further details if you wanna dive into: https://tailwindcss.com/docs/using-with-preprocessors#nesting

Option 2:

npm install postcss postcss-preset-env

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-preset-env': {
      autoprefixer: {},
      features: {
        'nesting-rules': true,
      },
    },
  },
};


*** To make variables work which are declared inside of CSS modules:

npm install postcss postcss-advanced-variables

// postcss.config.js
module.exports = {
    plugins: {
        "postcss-advanced-variables": {}, // add this
        "postcss-import": {},
        "tailwindcss/nesting": {},
        tailwindcss: {},
        autoprefixer: {},
    },
};

No more "selector is not pure" errors from CSS modules 🙂

kishansripada commented 1 year ago

*** To make CSS nesting rules to work with Next.js:

Option 1 (If you are using Tailwind):

// postcss.config.js
module.exports = {
  plugins: {
      "postcss-import": {}, // add this
      "tailwindcss/nesting": {}, // also add this
      tailwindcss: {},
      autoprefixer: {},
  },
};

Further details if you wanna dive into: https://tailwindcss.com/docs/using-with-preprocessors#nesting

Option 2:

npm install postcss postcss-preset-env

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-preset-env': {
      autoprefixer: {},
      features: {
        'nesting-rules': true,
      },
    },
  },
};

*** To make variables work which are declared inside of CSS modules:

npm install postcss postcss-advanced-variables

// postcss.config.js
module.exports = {
  plugins: {
      "postcss-advanced-variables": {}, // add this
      "postcss-import": {},
      "tailwindcss/nesting": {},
      tailwindcss: {},
      autoprefixer: {},
  },
};

No more "selector is not pure" errors from CSS modules 🙂

Is this for Next.js 13. I just upgraded my project from 12 to 13 and now my DnD context is literally destroying the entire page when active. Certain draggable elements disapear and reappear at random and it causes a ton of random artifacting of the positioning of objects on the rest of my page outside the context. Any tips? I'm using tailwind btw. Also i made sure to dynamically import the entire DND context, so no SSR.

ghost commented 1 year ago

@kishansripada yes, I was working with Next 13. I changed some stuff over time but you can see from old commits that I started with the exact same copy https://github.com/tommy-typos/evernote-clone/tree/main/src/components/DndKitSortable/Tree

kishansripada commented 1 year ago

@kishansripada yes, I was working with Next 13. I changed some stuff over time but you can see from old commits that I started with the exact same copy https://github.com/tommy-typos/evernote-clone/tree/main/src/components/DndKitSortable/Tree

I installed and added tailwindcss/nesting and postcss-import, with no difference. do you think this has something to do with the app directory? I'm sorry for bugging, but there aren't many resources about this specific topic and I'm struggling to troubeshoot.

ghost commented 1 year ago

@kishansripada oh I did with pages directory.

satvikpendem commented 1 year ago

@kishansripada Did you figure it out? I'm thinking about using the app directory as well for a sample project to test out some DnD libraries.

Also, did you add "use client" at the top? I don't think this library works with RSC in Next 13 without adding the "use client" directive.

kishansripada commented 1 year ago

@kishansripada Did you figure it out? I'm thinking about using the app directory as well for a sample project to test out some DnD libraries.

Also, did you add "use client" at the top? I don't think this library works with RSC in Next 13 without adding the "use client" directive.

Everything words fine without any work arounds, I just had other mistakes I made. It even works server side from what I can tell, although they may be a warning in the console.

Megajin commented 2 months ago

Hey everyone,

thank you for your valuable input! I was struggling with Nextjs 14 and DNDKit. However I did discover that you can easily achieve a reasonable good solution with this: https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading just switch between APP or Page directory (left top corner of Sidebar). I am using the App-Directory solution with Suspense and React.lazy. Works perfectly fine. Thank you for this awesome lib!