hashicorp / next-mdx-remote

Load MDX content from anywhere
Mozilla Public License 2.0
2.72k stars 141 forks source link

Passing client components doesn't work #455

Closed nehalist closed 7 months ago

nehalist commented 7 months ago

Hey there,

I'd like to create a FAQ page with next-mdx-remote, Next 14.1 and NextUI. NextUI Accordions require use client in order to work - but how to make that in next-mdx-remote?

What I've tried so far:

// faq utility
async function getFaq(locale: string) {
  const file = path.join(process.cwd(), "content", locale, "faq.mdx");
  if (!fs.existsSync(file)) {
    return undefined;
  }

  const { content } = await compileMDX({
    source: fs.readFileSync(file, "utf8"),
    components: {
      Accordion,
      AccordionItem,
    },
  });

  return fs.readFileSync(file, "utf8");
}

// faq page
export default async function FaqPage({
  params,
}: {
  params: { locale: string };
}) {
  const faq = await getFaq(params.locale);

  return <Container>{faq}</Container>;
}

This results in Unknown element <[object Object]> in collection. since the Accordion is not within a client component.

I've tried to wrap my faq within

"use client";

export function Faq({ children }: { children: any }) {
  return <>{children}</>;
}

and pass faq to this component in my page, but that also doesn't work.

My last approach was passing the Faq client component as a component for the MDX and use it like

<Faq> // the client component
  <Accordion variant="bordered">
    <AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
      this is content
    </AccordionItem>
    <AccordionItem key="2" aria-label="Accordion 2" title="Accordion 2">
      this is more content
    </AccordionItem>
    <AccordionItem key="3" aria-label="Accordion 3" title="Accordion 3">
      this is very little content
    </AccordionItem>
  </Accordion>
</Faq>

But that simply renders nothing.

Anyone got an idea?

Thanks!

dstaley commented 7 months ago

@nehalist Would you mind providing a minimal reproduction? I'd be happy to take a look!

nehalist commented 7 months ago

Hey @dstaley,

I created a minimal reproduction repo at https://github.com/nehalist/mdx-remote-client-components

Thanks!

dstaley commented 7 months ago

@nehalist Thank you so much for the reproduction, it was really helpful! It looks like the issue is actually in NextUI. The following example without MDX produces the same error:

import styles from "./page.module.css";
// The exports of @nextui-org/accordion are marked with 'use client' already.
import { Accordion, AccordionItem } from "@nextui-org/accordion";

const Demo = () => {
  return (
    <Accordion variant="bordered">
      <AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
        content
      </AccordionItem>
      <AccordionItem key="2" aria-label="Accordion 2" title="Accordion 2">
        more content
      </AccordionItem>
    </Accordion>
  );
};

export default async function Home() {
  return (
    <main className={styles.main}>
      <Demo />
    </main>
  );
}

Unfortunately I'm not able to see anything immediately obvious that'd cause the error. The good news though is that you already have a minimal reproduction, and I'm sure they'd appreciate the bug report!

nehalist commented 7 months ago

Putting "use client" at the top of this file should solve this issue. But it seems like I can't create client components when using mdx :(