Hydration error when using ShadCN sidebar example
Answered
Diamond Master posted this in #help-forum
I am trying to use the shadcn fetch data sidebar example, but react is giving me an hydration error in the Skeleton tag because of the style= tag
Example:
https://ui.shadcn.com/docs/components/sidebar#data-fetching
Example:
https://ui.shadcn.com/docs/components/sidebar#data-fetching
Answered by Black Turnstone
You can also do something like this too if you want to. This loaded state will make sure that component is only shown at client side only.
export function NavProjectsSkeleton() {
const [loaded, setLoaded] = React.useState(false);
React.useEffect(() => {
setLoaded(true);
}, []);
if (!loaded) {
return null;
}
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
<NewProjectButton />
</SidebarMenu>
);
}
50 Replies
bump
@Diamond Master I am trying to use the shadcn fetch data sidebar example, but react is giving me an hydration error in the Skeleton tag because of the style= tag
Example:
https://ui.shadcn.com/docs/components/sidebar#data-fetching
delete .next folder and rerun the dev server again.
this is a recent next bug i think, i face this one sometimes
this is a recent next bug i think, i face this one sometimes
Dwarf Hotot
You must be using senior elements in the junior elements like using paragraph in span elements so check elements order is correct
i am using that library
Dwarf Hotot
I have also faced same issue while using shadecn ui
it manages that by itself
Dwarf Hotot
Show the console error
Peterbald
I'm using shadcn sidebar too, but haven't seen this error before.
it's that one
Dwarf Hotot
And the code also
i use it with the theme too
gimme a sec
Peterbald
show code.
export default function Home() {
return (
<>
<SidebarProvider>
<MainSidebar />
<SidebarInset>
<header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12">
<div className="flex items-center gap-2 px-4">
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 h-4" />
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem className="hidden md:block">
<BreadcrumbLink href="#">
Building Your Application
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className="hidden md:block" />
<BreadcrumbItem>
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
</header>
</SidebarInset>
</SidebarProvider>
</>
);
}
Peterbald
go to mainsidebar component
going now
Dwarf Hotot
And console error
Peterbald
ensure your mainsidebar has "use client" at the top.
as a start.
export function MainSidebar() {
return (
<Sidebar collapsible="icon">
<SidebarHeader>
<ThemeToggle />
<SidebarSeparator />
</SidebarHeader>
<SidebarContent>
<SidebarGroup />
<ProjectsSidebarTab />
<Collapsible defaultOpen className="group/mainSidebarManagement">
<SidebarGroup>
<SidebarGroupLabel asChild>
<CollapsibleTrigger>
Management
<ChevronDown className="ml-auto transition-transform group-data-[state=open]/mainSidebarManagement:rotate-180" />
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent>
</SidebarGroupContent>
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
</SidebarContent>
<SidebarFooter>
<SidebarSeparator />
<NavUser />
</SidebarFooter>
<SidebarRail />
</Sidebar>
)
}
i am using "use client"
Dwarf Hotot
Share the console
big mess
export function ProjectsSidebarTab() {
return (
<Collapsible defaultOpen className="group/mainSidebarProjects">
<SidebarGroup>
<SidebarGroupLabel asChild>
<CollapsibleTrigger>
Projects
<ChevronDown className="ml-auto transition-transform group-data-[state=open]/mainSidebarProjects:rotate-180" />
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent>
<React.Suspense fallback={<NavProjectsSkeleton />}>
<NavProjects />
</React.Suspense>
</SidebarGroupContent>
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
);
}
export function NewProjectButton() {
return (
<SidebarMenuItem key="NewProject">
<SidebarMenuButton asChild>
<a href="#">
<SquarePlus />
<span>New Project</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
);
}
export function NavProjectsSkeleton() {
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
<NewProjectButton />
</SidebarMenu>
)
}
export function NavProjects() {
const data = null;
const isLoading = true;
if (isLoading) {
return (
<NavProjectsSkeleton />
)
}
if (!data) {
return null;
}
...
}
this is the error function btw, the NavProjectsSkeleton
@Briard dont use and client side things inside serverside things
it is only used in client side things
bump
@Diamond Master bump
Black Turnstone
Found solution?
Black Turnstone
Try turning ssr off when importing sidebar?
ssr?
Black Turnstone
Can you share the repo?
sec
i'll share a public one
here
Black Turnstone
@Diamond Master This component is causing issue
Mainly, this line
export function NavProjectsSkeleton() {
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
<NewProjectButton />
</SidebarMenu>
)
}
Mainly, this line
<SidebarMenuSkeleton showIcon />
This is the shadcn SidebarMenuSkeleton component code
here
This is causing issue because at every render width keeps changing so server rendered width is not same as client width causing the issue
const SidebarMenuSkeleton = React.forwardRef<
HTMLDivElement,
React.ComponentProps<'div'> & {
showIcon?: boolean;
}
>(({ className, showIcon = false, ...props }, ref) => {
// Random width between 50 to 90%.
const width = React.useMemo(() => {
return `${Math.floor(Math.random() * 40) + 50}%`;
}, []);
return (
<div
ref={ref}
data-sidebar="menu-skeleton"
className={cn('rounded-md h-8 flex gap-2 px-2 items-center', className)}
{...props}
>
{showIcon && (
<Skeleton
className="size-4 rounded-md"
data-sidebar="menu-skeleton-icon"
/>
)}
<Skeleton
className="h-4 flex-1 max-w-[--skeleton-width]"
data-sidebar="menu-skeleton-text"
style={
{
'--skeleton-width': width,
} as React.CSSProperties
}
/>
</div>
);
});
SidebarMenuSkeleton.displayName = 'SidebarMenuSkeleton';
here
const width = React.useMemo(() => {
return `${Math.floor(Math.random() * 40) + 50}%`;
}, []);
This is causing issue because at every render width keeps changing so server rendered width is not same as client width causing the issue
You can either set a fixed value or can turn of ssr by lazy loading https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#with-no-ssr
Check this
Check this
Black Turnstone
You can also do something like this too if you want to. This loaded state will make sure that component is only shown at client side only.
export function NavProjectsSkeleton() {
const [loaded, setLoaded] = React.useState(false);
React.useEffect(() => {
setLoaded(true);
}, []);
if (!loaded) {
return null;
}
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
<NewProjectButton />
</SidebarMenu>
);
}
Answer
@Diamond Master i tought i was already using client only
Black Turnstone
Even if you specify "use client". It doesn't means Component is opted out from server side rendering (ssr)
use client means that our component is not server component
And server component is not same thing as Server Side Rendering
use client means that our component is not server component
And server component is not same thing as Server Side Rendering
ah
Black Turnstone
It becomes very confusing but it is what it is ðŸ˜
i'll try rn
i was actually using states before but they are deleted rn bc i was doing the api first, lol
i don't get any more errors, thx