Next.js Discord

Discord Forum

Trying to create a new CSS scoping feature in nextjs

Answered
Goldstripe sardinella posted this in #help-forum
Open in Discord
Avatar
Goldstripe sardinellaOP
Hey, So I've thought about making a new CSS scoping feature in React/Nextjs that is similiar to how the style scoping works in Vuejs or Angular. Now before I start I want to give the reasons since it's kind of a big deal.

-- CSS IN JS
Now although there are alot of CSS in JS libraries like Styled Components, emotion, linaria etc, you need to install a package and then import {styled} in order to style the element. And writing css in a string is very painful since you need to write everything manually and theres no autocomplete. And CSS in JS libraries usually use hashes to scope the class names.

-- CSS modules
Another very popular way to write css in react to scope your styles, but theres also some issues like the filename is longer, you need to import the styles and you have to write something like className={styles.container} and if there are multiple class names you need to write
className={`${styles.container} ${styles.box}`}
and CSS modules also messes your class name up.

-- Styled jsx
Another style scoping feature that you can use in nextjs without installing packages. But the issue with this method is that again you need to write everything in a string and second you need to use a <style> tag for it which will make your file longer.

Alright so now that I've finished telling my reasons, I've tried making one in plain React, Vite and Typescript (actually chatGPT made it lol) which works.

You basically make a normal css file like home.css and write your styles in there. And theres a hook that basically gets the css source as an arguement and then fetches the css file, gets all the contents in the file, makes a <style> tag and puts the styles inside there. and for the scoping it basically gets a line like .container and replaces it with .container[data-jsx-hash] the hash is generated everytime the hook is called so that the styles get scoped to that hash.

MORE TEXT IN THE CHANNEL SINCE I DONT HAVE NITRO
Answered by Asian black bear
Do not expect anyone to reimplement your entire code to include SSR capabilities for you. If you attempt it yourself and encounter specific issues, you are welcome to ask for assistance with troubleshooting those aspects to get it working.
View full answer

12 Replies

Avatar
Goldstripe sardinellaOP
codes from the plain react typescript and vite project:

hooks/useCreateCssScope.ts
import { useEffect, useState } from "react";

// Utility function to generate a unique hash for the CSS scope
function generateUniqueHash() {
  return Math.random().toString(36).substr(2, 8);
}

// Custom Hook for creating CSS scope using a custom attribute
export const useCreateCssScope = (cssFilePath: string) => {
  const [scopeHash, setScopeHash] = useState<string>("");

  useEffect(() => {
    const hash = generateUniqueHash();
    setScopeHash(hash);

    // Log the CSS file path and scope hash for debugging
    console.log(`Loading CSS from: ${cssFilePath}`);
    console.log(`Generated scope hash: ${hash}`);

    // Fetch CSS content and scope it using the custom attribute
    fetch(`${import.meta.env.BASE_URL}styles/${cssFilePath}`)
      .then((response) => {
        if (!response.ok) {
          throw new Error(`Failed to load CSS file: ${cssFilePath}`);
        }
        return response.text();
      })
      .then((cssText) => {
        // Create a <style> tag and append the scoped CSS
        const styleElement = document.createElement("style");
        const scopedCss = scopeCssWithAttribute(cssText, hash);
        console.log(`Scoped CSS: \n${scopedCss}`); // Log the scoped CSS

        styleElement.textContent = scopedCss;
        document.head.appendChild(styleElement);
      })
      .catch((error) => console.error("Failed to load CSS file:", error));
  }, [cssFilePath]);

  // Return the generated hash attribute object
  return { [`data-jsx-${scopeHash}`]: "" };
};

// Utility function to scope the CSS using a custom attribute
const scopeCssWithAttribute = (cssText: string, scopeHash: string) => {
  // Modify the CSS to include the custom attribute selector with the scope hash
  const attributeSelector = `data-jsx-${scopeHash}`;
  return cssText.replace(
    /\.([a-zA-Z0-9_-]+)\s*{/g,
    `.$1[${attributeSelector}] {`
  );
};
App.tsx
import { useCreateCssScope } from "./hooks/useCreateCssScope"

function App() {
  const css = useCreateCssScope("Root.css");
  const css2 = useCreateCssScope("Text.css");

  return (
    <>
      <div {...css} className={"visual__layout"}>
        <div {...css} className={"visual__header"}>
          <div {...css2} className="heading">hi</div>
        </div>
      </div>
    </>
  )
}

export default App
ive tried using the exact same way in nextjs but theres issues such as it running on Client side only
since I'm no expert in nextjs I decided to come here and to hopefully find someone who knows a solution in making this in nextjs but with SSR support.
---

# Information on what I mean by it running only on Client Side:

Basically, until the page hasnt 100% completed loading the styles just dont apply. the reason for this is because the response in the network tab (before the page 100% loads or SSR) is this:

<div data-jsx-="" class="container"></div>


but when the page 100% loads it outputs something like (and applies the styles)

<div data-jsx-hash class="container"></div>
please do ping me when responding!
Avatar
Asian black bear
Your post contains no question as far as I can tell. What is it that you want exactly? What are your specific questions or issues you need help with?
Avatar
Goldstripe sardinellaOP
thats why I chose the "other" tag since it's not really a question but more like trying to get some like expert or someone to help me out with building what i want. Basically i want the style scoping feature that was written in plain react/ts/vite to be usable in nextjs. but it was only running client side and i dont know how to make it run on server side
btw can you ping me on like each reply if u dont mind? so that i can see that u responded
Avatar
Asian black bear
Do not expect anyone to reimplement your entire code to include SSR capabilities for you. If you attempt it yourself and encounter specific issues, you are welcome to ask for assistance with troubleshooting those aspects to get it working.
Answer
Avatar
Goldstripe sardinellaOP
im just trying to find someone that knows how to do it
Avatar
Goldstripe sardinellaOP
idk how to delete this channel