Request: use :global or :local similar to css-modules
See original GitHub issueI 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:
- Created 5 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
@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)
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?