planttheidea/react-style-tag

The style tag always insert under the component level instead of document head

Closed this issue · 10 comments

The style tag always insert under the component level instead of document head

This is kind of intentional, and should not cause a problem related to styling (either global or local). Are you experiencing a problem with this? As stated, this is just kind of an observation.

This is kind of intentional, and should not cause a problem related to styling (either global or local). Are you experiencing a problem with this? As stated, this is just kind of an observation.

It doesn't cause any problem for now in terms of styling. But it kind violates HTML syntax rules. In my scenario, I try to have the better html structure for SEO and other purposes. I just tried the version 2.05 and it works well. Only happens in version 3.

Oh man, it's been so long since I wrote the original, I forgot that this was something that v2 did! Yes, it looks like as part of the v3 rewrite this did not get migrated, hence introducing a regression. I'll follow up on it this week.

Alright so turns out this is going to be a little trickier than originally thought. Looks like React 18 has gotten a bit more rigid with things in concurrent mode, and moving the DOM nodes around is causing breakages.

In reality, the cleanest solution is just to use Portals ... it works flawlessly if the rendered element is applied in a Portal where the container is document.head. However, internalizing that is going to be tricky because React 18 changed its import structure for react-dom:

// React 16
import { createPortal } from 'react-dom';
// React 18
import { createPortal } from 'react-dom/client';

Since this is a third-party library, doing conditional imports can get very messy very quickly. So, I'll need to experiment with some things to see if I can get Portals working cross-version, or if I can find a safe way to do the manual DOM manipulation I was doing prior.

In the meantime, however, you can work around the issue by simply applying the <Style> tag in a portal yourself:

createPortal(
  <Style>{`h1 { font-size: 24px }`}</Style>,
  document.head
);

This works beautifully, whether in 16.6 or 18.2.

Okay nevermind ... I'm an idiot, the import structure has remained the same. I got my wires crossed in the previous comment. Portals look to be the answer, so PR forthcoming.

I'll sit on this for a day or two so I can look at it with a fresh set of eyes before merging, but it feels pretty solid. Naturally, if you have any feedback on the above PR let me know.

Alright so turns out this is going to be a little trickier than originally thought. Looks like React 18 has gotten a bit more rigid with things in concurrent mode, and moving the DOM nodes around is causing breakages.

In reality, the cleanest solution is just to use Portals ... it works flawlessly if the rendered element is applied in a Portal where the container is document.head. However, internalizing that is going to be tricky because React 18 changed its import structure for react-dom:

// React 16
import { createPortal } from 'react-dom';
// React 18
import { createPortal } from 'react-dom/client';

Since this is a third-party library, doing conditional imports can get very messy very quickly. So, I'll need to experiment with some things to see if I can get Portals working cross-version, or if I can find a safe way to do the manual DOM manipulation I was doing prior.

In the meantime, however, you can work around the issue by simply applying the <Style> tag in a portal yourself:

createPortal(
  <Style>{`h1 { font-size: 24px }`}</Style>,
  document.head
);

This works beautifully, whether in 16.6 or 18.2.

It seems working fine! How about clean up?

React.useEffect(() => {
     createPortal(
       <Style>{`h1 { font-size: 24px }`}</Style>,
   document.head)

      return () => {
         //Remove the Tag created by Style.
        //I may give the Style an id and find the dom to remove.
       // But is there a better way to clean it up?
      }
    }, [])

You should not need to apply via useEffect, and in fact I would consider this an incorrect usage. You want the style to exist immediately, just like all other elements rendered via JSX. I'm curious why you thought the useEffect was necessary?

This will all be moot when I merge the PR (imminently), just trying my best to answer your question.

This should be resolved as-of 3.0.1. If you have any more issues, let me know!

You should not need to apply via useEffect, and in fact I would consider this an incorrect usage. You want the style to exist immediately, just like all other elements rendered via JSX. I'm curious why you thought the useEffect was necessary?

This will all be moot when I merge the PR (imminently), just trying my best to answer your question.

Because I am thinking to remove the style when the component is unmounted. I thought we need to clean the added tags up when the component is unmounted.