question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Request: use :global or :local similar to css-modules

See original GitHub issue

I like to use styled-components like this (and I hope many other people do too):

function MyComponent() {
  return (
    <StyledComponent>
      <div className="direct-child">
        <div className="indirect-child"/>
      </div>
    </StyledComponent>
  )
}

const StyledComponent = styled.div`
  & > .direct-child {

  }

  .indirect-child {

  }
`

function TopLevelComponent() {
  return (
    <StyledTopLevel>
      <MyComponent/>
    </StyledTopLevel>
  )
}

const StyledTopLevel = styled.div`
  .indirect-child {
    // the styling here will affect the div inside MyComponent.
    // I want to prevent this from happening.
  }
`

I like to do this because I don’t like making a bunch of styled components for wrappers and children.

The example above is contrived. But this is a pattern which I run into sometimes where it turns out to be simpler to describe class rule as an indirect descendant.

However, declaring rules & .indirectly {} will cause a problem if a top-level component also defines rules for a component of the same name.

I like how this is handled with css-modules where by default, all classes are :local, and you can opt out by using :global, or vise versa depending on your configuration.

Ideally, there is a babel plugin or a webpack plugin that will preprocess files that use styled()(). If it sees a className inside styled()() then it will transform it by prepending it with the filename, or a hash, and then it will find all occurences of that string in any className props on any children of the component create by the call to styled()().

For backwards compatibility, I guess the default behavior is all classNames found inside styled()() are global, but it would be nice to be able to switch that around via configuration like you can with css-modules.

By doing this, then you can easily isolate each component’s namespace.

It would look like this:

function MyComponent() {
  return (
    <StyledComponent>
      <div className="direct-child">
        <div className="indirect-child"/>
        <div className="global-rule"/>
      </div>
    </StyledComponent>
  )
}

const StyledComponent = styled.div`
  & > .direct-child {

  }

  .indirect-child {
    // the className here is automatically transformed to .hh3k34-indirect-child
    // Somehow, all the div className props are also transformed to "hh3k34-indirect-child"
  }
  
  :global(.global-rule) {
  
  }
`

function TopLevelComponent() {
  return (
    <StyledTopLevel>
      <MyComponent/>
    </StyledTopLevel>
  )
}

const StyledTopLevel = styled.div`
  .indirect-child {
    // the className here is automatically transformed to .abcdef-indirect-child
    // it's different from the inner .indirect-child, so it won't have an effect.
  }
  
  :global(.global-rule) {
    // opt out of the namespacing behavior
  }
`

I don’t know much about how babel transform works and what its limitation are and whether or not this is possible, but in case it isn’t, here is an alternative which requires a bit more work to setup:

import styled, {local} from 'styled-components'

const directChild = local('direct-child')
const indirectChild = local('indirect-child')
const I_dont_care_if_its_readable = local() // generate a BEM or Pacomo for source mapping

function MyComponent() {
  return (
    <StyledComponent>
      <div className={directChild}>
        <div className={indirectChild}/>
        <div className={I_dont_care_if_its_readable}/>
        <div className="global-rule"/>
      </div>
    </StyledComponent>
  )
}

const StyledComponent = styled.div`
  & > ${indirectChild} {

  }

  ${indirectChild} {

  }
  
  .global-rule {
  
  }
`

function TopLevelComponent() {
  return (
    <StyledTopLevel>
      <MyComponent/>
    </StyledTopLevel>
  )
}



const StyledTopLevel = styled.div`
  ${indirectChild} {
    
  }
  
  .global-rule {
    
  }
`

What do you think?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
pixelasscommented, Dec 17, 2018

@taylorgoolsby I’m not part of this org or even a contributor but I dare to say that this idea does not really fit into the concept that styled components follows (correct me if I’m wrong).

I created two npm packages that are very similar to styled-components. I wouldn’t recommend either since neither was fully developed for production use. Writing them did however allow me to understand a lot of things that happen under the hood of styled-components.

I think you should look into what you really want to do and then choose a library that does this or create your own. There are several libraries that are very similar but provide different options and/or features. None of them will ever be perfect, it’s an utopian thought. Maybe you even have a great idea and can contribute by making this library. It will also help to understand why styled-components works the way it does and why your requested feature would add more weight than advantage. Styled components is already a big library if you use it at its full scope. The main advantage I see is having a very straight forward set of features and a promising team behind this library, good test coverage and a more or less reliable release schedule.

this is just my opinion

That being said you could look at emotion (e.g. their class-names) feature or Aphrodite.

All these libraries are created by amazing developers and share ideas and concepts. …All of them will be replaced in a few years.

my libs (sadly not meant for production but open-source and maybe an inspiration)

0reactions
mxstbrcommented, Dec 17, 2018

I think this has been answered pretty thoroughly, we’re unlikely to support anything like this in styled components since it conceptually doesn’t really make sense to uniquely scope strings inside the CSS block—how would get them out?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Global vs. Local Styling In Next.js - Smashing Magazine
The answer is surprisingly simple — to write well-structured CSS that balances global and local styling concerns.
Read more >
How to apply global styles with CSS modules in a react app?
The first rule should be to include all global styles, assuming it's kept in /styles/ or similar directory. The second rule is to...
Read more >
A deep dive into CSS Module - LogRocket Blog
Automate tedious naming methods using CSS Module, an extra layer of abstraction that locally scopes class names.
Read more >
Basic Features: Built-in CSS Support - Next.js
CSS Modules locally scope CSS by automatically creating a unique class name. This allows you to use the same CSS class name in...
Read more >
Configuring both CSS Modules and global CSS for ReactJS in ...
For example, I might have a .logo class that are used everywhere, but my Header component needs a different logo. In this case,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found