I want to render styled-components by server-side in Next.13. How i do?
Asked Answered
W

2

1

the component is being rendered before styling at a certain time

I want to render the styled-components on the server side

Watthour answered 1/2, 2023 at 14:7 Comment(3)
If you want to use styled-components in server components, I don't think that is possible yet. See Next.JS CSS-in-JS docs. It also says If you want to style Server Components, we recommend using CSS Modules or other solutions that output CSS files, like PostCSS or Tailwind CSS.Heft
Does anyone know if this is being worked on, and if so, when it is planned to be working again?Hoist
Will it be supported someday?Hulda
A
-4

The answer in documentation: https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-components

create lib/registry.tsx with this code

'use client';
 
import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
 
export default function StyledComponentsRegistry({
  children,
}: {
  children: React.ReactNode;
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
 
  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });
 
  if (typeof window !== 'undefined') return <>{children}</>;
 
  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
}

and wrap the child in global layout (app/layout.tsx)

import StyledComponentsRegistry from './lib/registry';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
      </body>
    </html>
  );
}
Anosmia answered 27/5, 2023 at 18:1 Comment(1)
This doesn't render the component on the server side. It renders the styles into the html so the client component can hydrate. In version 12 this would mean the components rendered html was in the source but in version 13 only components fully rendered on server can do this so no way currently to do this with css-in-js.Uracil
M
-1

In summary, when the styled function is used each time, the generated CSS style text is recorded in memory. The getCssText method returns all the CSS style texts that are produced by using styled.

Given the existence of server-side components and client-side components, which invoke the styled function in different environments, it naturally follows that the storage location for the CSS style texts differs as well. The style texts generated by styled within server-side components reside in the server's memory; therefore, the getCssText called within components marked with "use client" does not have access to these styles. This is why the 'stitches registry' approach is only applicable to client-side components.

Consequently, we need to execute getCssText in the server environment too, to retrieve the corresponding CSS style texts and inject them into the .

import { getCssText } from "@/stitches.config.ts";
export default function RootLayout({}) {
  return <html>
    <head>
        <style
          id="stitches"
          dangerouslySetInnerHTML={{ __html: getCssText() }}
        />
      </head>
      <body>
        {/* ... */}
      </body>
  </html>
}

then ,use the answer above to active styled in client component.

Milanmilanese answered 1/2, 2024 at 12:8 Comment(0)
A
-4

The answer in documentation: https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-components

create lib/registry.tsx with this code

'use client';
 
import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
 
export default function StyledComponentsRegistry({
  children,
}: {
  children: React.ReactNode;
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
 
  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });
 
  if (typeof window !== 'undefined') return <>{children}</>;
 
  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
}

and wrap the child in global layout (app/layout.tsx)

import StyledComponentsRegistry from './lib/registry';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
      </body>
    </html>
  );
}
Anosmia answered 27/5, 2023 at 18:1 Comment(1)
This doesn't render the component on the server side. It renders the styles into the html so the client component can hydrate. In version 12 this would mean the components rendered html was in the source but in version 13 only components fully rendered on server can do this so no way currently to do this with css-in-js.Uracil

© 2022 - 2025 — McMap. All rights reserved.