radix-ui / primitives

Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
https://radix-ui.com/primitives
MIT License
15.99k stars 840 forks source link

VisuallyHidden does not render in nextjs 13 app dir server component #2430

Closed jpmbvistro closed 9 months ago

jpmbvistro commented 1 year ago

Bug report

Current Behavior

When using utility component in a NextJs 13 App Dir server component you get the following error thrown:

./node_modules\@radix-ui\react-primitive\dist\index.mjs
ReactServerComponentsError:

You're importing a component that needs flushSync. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
Learn more: https://nextjs.org/docs/getting-started/react-essentials

   ╭─[C:\Users\juspo\Documents\ImpactInnovations\impact-innovations-site-1\node_modules\@radix-ui\react-primitive\dist\index.mjs:1:1]
 1 │ import $4q5Fq$babelruntimehelpersesmextends from "@babel/runtime/helpers/esm/extends";
 2 │ import {forwardRef as $4q5Fq$forwardRef, useEffect as $4q5Fq$useEffect, createElement as $4q5Fq$createElement} from "react";
 3 │ import {flushSync as $4q5Fq$flushSync} from "react-dom";
   ·         ─────────
 4 │ import {Slot as $4q5Fq$Slot} from "@radix-ui/react-slot";
 5 │ 
   ╰────

Maybe one of these should be marked as a client entry with "use client":
  ./node_modules\@radix-ui\react-primitive\dist\index.mjs
  ./node_modules\@radix-ui\react-visually-hidden\dist\index.mjs
  ./src\app\@header\page.tsx

Expected behavior

Page renders properly w/o error as a server component

Reproducible example

Add the component in a server component

Suggested solution

Current fix is to abstract the implementation into its own client component and import it into the server component.

Additional context

This was tested in subroutes, root dir, parallel slots, all have the same issue.

Your environment

"dependencies": {
    "@builder.io/dev-tools": "latest",
    "@builder.io/react": "latest",
    "@builder.io/sdk": "latest",
    "@chakra-ui/icons": "^2.0.19",
    "@chakra-ui/next-js": "^2.1.3",
    "@chakra-ui/react": "^2.6.1",
    "@emotion/react": "^11.11.0",
    "@emotion/styled": "^11.11.0",
    "@hookform/resolvers": "^3.3.1",
    "@notionhq/client": "^2.2.5",
    "@radix-ui/react-dialog": "^1.0.5",
    "@radix-ui/react-label": "^2.0.2",
    "@radix-ui/react-navigation-menu": "^1.1.4",
    "@radix-ui/react-slot": "^1.0.2",
    "@radix-ui/react-tooltip": "^1.0.7",
    "@radix-ui/react-visually-hidden": "^1.0.3",
    "@types/node": "20.1.1",
    "@types/react": "18.2.6",
    "@types/react-dom": "18.2.4",
    "@vercel/analytics": "^1.0.1",
    "class-variance-authority": "^0.7.0",
    "clsx": "^1.2.1",
    "encoding": "^0.1.13",
    "eslint": "8.40.0",
    "eslint-config-next": "13.4.1",
    "framer-motion": "^10.12.9",
    "fs": "^0.0.1-security",
    "lucide-react": "^0.279.0",
    "next": "^13.5.4",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-hook-form": "^7.46.2",
    "react-icons": "^4.8.0",
    "tailwind-merge": "^1.14.0",
    "tailwindcss-animate": "^1.0.7",
    "typescript": "5.0.4",
    "zod": "^3.22.2"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.14",
    "postcss": "^8.4.23",
    "sass": "^1.62.1",
    "tailwindcss": "^3.3.2"
  }
Software Name(s) Version
Radix Package(s) See Above
React See Above
Browser Chrome 116.0.5845.188
Assistive tech No
Node n/a v19.6.0
npm/yarn npm 9.4.0
Operating System Windows 10.0.19045
davidkhierl commented 1 year ago

having the same issues as well with AccessibleIcon since it is using VisuallyHidden.

useEffect only works in Client Components. Add the "use client" directive at the top of the file to use it.
yaralahruthik commented 1 year ago

@jpmbvistro @davidkhierl Ideally, you should abstract this out! or create your own visually hidden component with plain css instead of using the radix package.

'use client';

import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';

interface Props {
  children: React.ReactNode;
}

export default function VisuallyHidden({ children }: Props) {
  return (
    <VisuallyHiddenPrimitive.Root>{children}</VisuallyHiddenPrimitive.Root>
  );
}
benoitgrelard commented 9 months ago

@yaralahruthik is correct, the library isn't yet natively supporting RSC (doesn't include use client where needed yet). The recommended solution is still to wrap it and add use client where appropriate.