Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Adding selector scoping for generated classNames #760

Closed
ItsJonQ opened this issue Jul 11, 2018 · 10 comments
Closed

Feature: Adding selector scoping for generated classNames #760

ItsJonQ opened this issue Jul 11, 2018 · 10 comments

Comments

@ItsJonQ
Copy link

ItsJonQ commented Jul 11, 2018

Hi there! 👋

I have a feature request :). Would it be possible to provide the ability to (intentionally) scope/increase the specificity of emotion generated classNames?

Full transparency, I also opened up an issue in styled-components, and some of the folks and I are discussing this feature now.

I can't say this strategy/implementation is battle tested… but it's working well for the stuff I'm building for my company 👍 . I believe that it's a nice feature/enhancement for any CSS-in-JS library as it provides additional control and the ability to integrate into older systems.

Use case

The use case for this would be if we wanted to implement emotion React components into an older applications, with hostile pre-existing CSS rules (that probably won't/can't go away soon). The company I work for has this very use-case!!

Solutions

I've refactored the styled-components-like library (I called it Fancy) that I use for my company. It now uses a enhanced forked version of Emotion under the hood.

ScopeProvider 🔎

I went with the strategy of creating a ScopeProvider (wrote some docs here).

Example:

<div>
  <StyledCard />
  ...
  <ScopeProvider scope="html #App">
    <div id="App">
      <StyledCard />
    </div>
  </ScopeProvider>
  ...
</div>

The idea is… anything created with styled should not have to worry about scope… therefore, no need to manually add prefixes (when you create them).

If it appears under a ScopeProvider, it will then get prefixed by anything defined by the ScopeProvider. If it appears outside, it's business as usual. It allows for styled components to seamlessly be used inside/outside of scoped areas.

This strategy allows for scoping to be added to an existing application/system of styled components without changing anything, minus the root(s) where ScopeProvider needs to be added, which is nice.

The way I've written ScopeProvider works very much the same way as how ThemeProvider works (context + internal broadcast + sub/unsub for the styled component). The only tricky bit coordinating and sending that prefix (string) to stylis during the CSS processing phase (if a scope is defined).

Here's the source code. There's not much too it! The heavy lifting comes from the styled-component factory and style rule generator

If you're interested in exploring my fork (aka. HAX, haha)… I copied over various files from Emotion into my own project (thank you for making everything so modular!), and only touched what I needed to. Anything custom I wrote should have comment blocks :).

Link to the source code

Here's a quick demo of ScopeProvider working. If you inspect element, you can see the compiled className is scoped under #App.

ScopeProvider within a ScopeProvider? 🤔

Yo dawg, I heard you like Scope…

I know the strategy ThemeProvider extends previously established theme configs when nesting happens. For scoping, I think it's probably simplest to assume that only the closest ScopeProvider scope will be used. No inheriting/chaining.

Thank you so much for your time!

P.S. If this idea sounds good to you, I can create a PR with this feature 🙌


Side note...

iFrames 🤓

This is out of scope for this feature request, but I took the same strategy and applied it to another tricky issue that libraries like styled-components, emotion, jss, etc… have, and that is correctly rendering styles within iFrames. I did this by creating a FrameProvider.

<App>
  <StyledCard />
  <Frame>
    <FrameProvider>
      <StyledCard />
    </FrameProvider>
  </Frame>
</App>

The FrameProvider is used within your iFrame (folks usually use react-frame-component). If any styled components render within, the FrameProvider will provide the style generator with the correct document to render it's style tags into. (We can discuss this in another GH issue if you're interested)

Here's a quick demo of the FrameProvider working.

Thanks again for your time!!!

@Andarist
Copy link
Member

Scope

I've created stylis-plugin-extra-scope exactly for this. You can see my answer on how to use it here. I believe it should cover your use case completely - using different scopes etc shouldn't be needed I think.

iFrames

Definitely this is an interesting problem, we could discuss it in other issue.

@emmatown
Copy link
Member

Both of these issues are something I'm trying to address with emotion@10 (#637).

With the the current alpha of emotion@10, I was able to create both of these APIs. The implementation isn't perfect, for example it doesn't pass theme down through the providers but that's fixable.

Just a note: The exact APIs will definitely change before the actual release of emotion@10 and you shouldn't rely on them right now.

@Andarist
Copy link
Member

@mitchellhamilton OH DAMN! THIS IS SO GOOD 😍😍😍

@nitin42
Copy link
Contributor

nitin42 commented Jul 12, 2018

@mitchellhamilton this is bonkers 👏🔥🤩

@ItsJonQ
Copy link
Author

ItsJonQ commented Jul 13, 2018

@mitchellhamilton Wow! This is amazing! Those features are exactly what I was trying to build, but you did it way better, haha.

I guess we can close this issue up since you're working on something that resolves these requests :).

Once this is released, if FrameProvider / ScopeProvider aren't going to be part of the core emotion package(s), I'd be more than happy to write an add-on or something based on your implementation!

👏 👏 👏

@stale
Copy link

stale bot commented Sep 11, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

@JulienKode
Copy link

any update regarding this issue ?

I'm trying to move my global scope into a specific part of the page.

@Reklino
Copy link

Reklino commented Jun 12, 2020

Has anyone gotten this to work with with the standard syntax? (className={css...}

Here's a sandbox. Seems like the <style> tags for those applied classes don't get pulled into the iframe.

@Andarist
Copy link
Member

@Reklino you would have to use create-emotion package configured with a custom container.

Emotion is by default bound to document.head of the context in which it got initialized, so to your main page here.

@dparker2
Copy link

stylis-plugin-extra-scope still does not support stylis v4 and therefore cannot be used with emotion v11. Is there a different way to do this in v11?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants