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

Component-based API for global styling #1333

Closed
wmertens opened this issue Nov 29, 2017 · 20 comments
Closed

Component-based API for global styling #1333

wmertens opened this issue Nov 29, 2017 · 20 comments

Comments

@wmertens
Copy link
Contributor

Via #730 (comment)

It would be great to have a React component for global styles that does the actual injecting (rendering null), removing the CSS when it is unmounted.

So instead of

    injectGlobal`...`

you'd do

const GlobalStyle = styled.global`
… (including prop interpolation)
`
...
return (
  <App>
    <GlobalStyle darkBg={this.props.dark} />
    ...
  </App>
)

The only differences with regular styled components would be:

  • Renders null
  • Does not wrap the CSS with an own class

This way:

  • Global styles can be easily modified via props
  • It works without issues in SSR
  • It's obvious what is happening
@mxstbr
Copy link
Member

mxstbr commented Nov 29, 2017

I think this would be a valuable change.

Myself and @geelen originally decided against going down this route because it seemed more tedious to use, but as you said it has a bunch of nice properties. A couple more are:

I'm open to doing this. My only concern is that I don't like overloading the styled.x convention and whether we want to introduce a new API or reuse the old one:

/* First possibility: injectGlobal now just returns a component */
const GlobalStyles = injectGlobal`
  body {
    background: blue;
  }
`

/* Second possiblity: Different API */
const GlobalStyles = injectGlobalAsComponent`
  body {
    background: blue;
  }
`

/* Third possibility: Radium-like <Style /> component */
<Style>{`
  body {
    background: blue;
  }
`}</Style>

I'd personally prefer the first way. I'd rather not we have multiple ways of doing things, and we could break this in a major version without troubles.

@kitten
Copy link
Member

kitten commented Nov 29, 2017

@mxstbr I'm totally down for replacing injectGlobal with sth like your first or second variant. I think both styled.global and <Style>{template string}</Style> are not favourable options.

I do think though that the name injectGlobal should be changed, but maybe we can go for a more succinct name like globalStyles.

I don't think this necessarily depends on #1324, but we do need to implement a way to remove styles from our sheet (or alternatively append & replace classes to body) which might conflict with refactors in #1208.

@mxstbr
Copy link
Member

mxstbr commented Nov 29, 2017

Doesn't depend on #1324 at all, but enables more functionality for the StyleSheetManager!

Yeah you're right, on second thought injectGlobal returning a component is kind of weird. What about const Style = createGlobalStyle or something to that effect?

With appending and replacing that doesn't matter for the first version of this component (though we should really tackle that) since right now people just work around the dynamicism with a function that gets called when the styles should change I assume. So they're injecting a bunch of times anyway.

@wmertens
Copy link
Contributor Author

wmertens commented Nov 29, 2017 via email

@Undistraction
Copy link

You can use the theme dynamically in the global styles

This would be a huge benefit. Unifying the theming of components with global styles like font-face and page background-color is something I'm definitely missing. A clearly defined place to perform global styling that has access to the theme would be great.

@wmertens
Copy link
Contributor Author

wmertens commented Dec 8, 2017

Alright, so it seems that everybody likes e.g.

import {createGlobalStyle} from 'styled-components'

const Style = createGlobalStyle`
  ${p => p.noScroll && `body { overflow: hidden; }`};
`

as an API? What are the next steps to make this happen? Is this a deep change to how the CSS is managed?

@mxstbr
Copy link
Member

mxstbr commented Dec 8, 2017

I don't think so, the only thing I'm not 100% sure about is re: server-side rendering and rehydration—would definitely be worth kicking off a first PR so that @geelen can take a look at that though!

@Fer0x
Copy link
Contributor

Fer0x commented Dec 15, 2017

Continue my thoughts from #1354

Helper keyframes works similar to injectGlobal. They generate componentId from hash of passed styles and inject computed styles through global instance of StyleSheet. We could reuse that componentId for injecting styles in Component-based API without breaking changes of writing global styles / keyframes.

Proposed API examples:

import React from 'react';
import { injectGlobal, StyleInjector } from 'styled-components';

const globalStyles = injectGlobal`
  body: {
    // ...
  }
`;

const MyComponent
<StyleSheetManager target={frame}>
  <div>
    <StyleInjector name={globalStyles} />
  </div>
</StyleSheetManager>
import React from 'react';
import { keyframes, StyleInjector } from 'styled-components';

const animationName = keyframes`
  0% { color: transparent; }
  100% { color: radboats; }
`;

<StyleSheetManager target={frame}>
  <div>
    <StyleInjector name={animationName} />
  </div>
</StyleSheetManager>

StyleInjector will get componentId with provided prop name, then grab corresponding styles from global StyleSheet instance and finally insert them to closest StyleSheetManager target.

@mxstbr
Copy link
Member

mxstbr commented Dec 16, 2017

Something I've realized: The issue with introducing a new API like injectGlobalStyle is that it breaks all our tooling since that relies on the injectGlobal name. (think Babel plugin, stylelint processor,...)

Definitely not ideal... 😕

@wmertens
Copy link
Contributor Author

wmertens commented Dec 16, 2017 via email

@mxstbr
Copy link
Member

mxstbr commented Dec 16, 2017

Yes of course, just a thing to note that it'll be a bit more work after we implement this API.

@mxstbr mxstbr added this to the v3.0 milestone Dec 18, 2017
@mxstbr
Copy link
Member

mxstbr commented Dec 18, 2017

Alright, let's get started on this—anybody want to tackle a first PR that implements this new API?

We already have tests for most of the global behavior, so it should just be a matter of rewriting those tests to use the new API (at which point they'll all fail) and then slowly rebuild the new API until all tests pass again!

@marionebl
Copy link
Member

Just to clarify: is the blessed API the following?

import {createGlobalStyle} from 'styled-components'

const Style = createGlobalStyle`
  ${p => p.noScroll && `body { overflow: hidden; }`};
`

@mxstbr
Copy link
Member

mxstbr commented Feb 5, 2018

Yep! See #1416, would love if you could pick that up and implement some tests so we can ship it 😊

@marionebl
Copy link
Member

I'll give this a shot, might get stuck on some WIP state though.

@quantizor
Copy link
Contributor

This is a thing in v4 :)

@Ky6uk
Copy link

Ky6uk commented Sep 18, 2018

Hmm. Error Use "createGlobalStyle" instead. in SC v3 confuses me. Is createGlobalStyle also available in v3? What if somebody hasn't plans to switch to v4?

@imbhargav5
Copy link
Member

Well you can continue to use injectGlobal in v3. However v4 has a few good features and perf upgrades so in case you want to switch you may have to move to createGlobalStyle.

@Ky6uk
Copy link

Ky6uk commented Sep 18, 2018

@imbhargav5 after latest v3 update it just forces me with severity "error" to use createGlobalStyle, but I am not sure it's possible to do in v3.

I want to say some kind of deprecations should provide a way to switch on the new feature and to remove that deprecation warning. But currently the deprecation warning doesn't provide any alternatives to do that without upgrading to v4.

@quantizor
Copy link
Contributor

Yeah... I think I’m just going to take it out. After more thought it doesn’t make sense to put in a non-actionable warning.

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

9 participants