styled-components / styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
https://styled-components.com
MIT License
40.12k stars 2.48k forks source link

StyleSheetManager `shouldForwardProp` does not prevent prop forwarding #4251

Open charlie-at-deaglo opened 3 months ago

charlie-at-deaglo commented 3 months ago

System:

Reproduction

Code Sandbox

Steps to reproduce

Expected Behavior

The Next application in the linked Code Sandbox is configured to use the app directory with StyleSheetManager to enable SSR, as is described in the Next.js docs. In v6, prop forwarding is controlled via the shouldForwardProp prop on the StyleSheetManager. To prevent invalid props from being sent to the DOM, the FAQs section of the docs recommends using isPropValid from @emotion/is-prop-valid to validate props, which I have setup in the Code Sandbox. Providing this callback to the StyleSheetManager should prevent invalid props from being forwarded to the DOM. In the Code Sandbox, this would mean that the someProp prop on the <Component /> component is not sent to the DOM.

Actual Behavior

someProp is forwarded to the DOM, which causes the following warnings to be printed to the console:

styled-components: it looks like an unknown prop "someProp" is being sent through to the DOM, which will likely trigger a React console error. If you would like automatic filtering of unknown props, you can opt-into that behavior via `<StyleSheetManager shouldForwardProp={...}>` (connect an API like `@emotion/is-prop-valid`) or consider using transient props (`$` prefix for automatic filtering.)

Warning: React does not recognize the `someProp` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `someprop` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
goosewin commented 2 months ago

+1. It looks like the only way to avoid console spam with warnings right now is to use $transientProps

Kobol909 commented 2 months ago

Actually it does work.

The issue you're facing is caused by the fact you're returning the children on client, as is, without any props filtering. if (typeof window !== "undefined") return <>{children}</>;

While many docs suggest writing that, it's not doing any filtering.

You can leverage the StyleSheetManager to also filter props on the client like below:

const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return styles;
  });

  const shouldForwardProp = (propName: string, target: any) => {
    return typeof target === "string" ? isPropValid(propName) : true;
  };

  if (typeof window !== "undefined") {
    return (
      <StyleSheetManager
        enableVendorPrefixes
        shouldForwardProp={shouldForwardProp}
      >
        {children}
      </StyleSheetManager>
    );
  }