Styled-jsx: dynamic styles mode

Created on 18 Jan 2017  ยท  12Comments  ยท  Source: vercel/styled-jsx

@rauchg and I discussed about possible ways to support dynamic styles i.e. allow props and other dynamic values which #80 doesn't.

From slack:

@g and I are contemplating a "dynamic" mode for styled-jsx where you pay a small penalty in performance but you can write stuff like

``jsx <style jsx dynamic>{
p {
width: 100%;
color: ${someProp ? 'red' : 'blue'}
}
`}


Basically this mean separate static css from dynamic one, render static css with the current system and inline the dynamic one i.e. each instance will get its own styles.

In order to do so we would need a CSS parser to split things up so that the example above becomes:

```javascript
[
  {
    dynamic: false,
    css: 'p { width: 100% }'
  },
  {
    dynamic: true,
    css: 'p { color: ___styled-jsx-expression_placeholder_n_1___ }'
  }
]

which eventually compiles down to

<_JSXStyle styleId={woot} css={"p[data-jsx=\"woot\"] {width: 100%;}"} />
<_JSXStyle dynamic styleId={woot2} css={`p[data-jsx=\"woot2\"] {color: ${someProp ? 'red' : 'blue'}}`} />

When dynamic is set our component renders a regular style tag instead of returning null.

To parse the CSS we could write a tiny parser or use something like CSSTree since it seems to be fairly fast https://csstree.github.io/docs/validator.html (we could reuse this for the css transformation as well).

discussion help wanted

Most helpful comment

@rstacruz I've got a branch which adds support for dynamic styles almost ready :) I might publish a beta this week.

All 12 comments

@lahmatiy showed me how this could be done with CSSTree

https://gist.github.com/giuseppeg/2699094fc7f9f355e4289f6432266a83

@thysultan would it be as easy to do so with a new Stylis middleware?

@giuseppeg Could add to the existing middleware

var selector = '', collection = '', dynamic = {};

function middlware (context, value) {
    // selector
    if (context === 1) selector = value;

    // property, and some rule to only pull actual dynamic props
    if (context === 2) {
        if (dynamic[selector] === void 0) dynamic[selector] = [];

        dynamic[selector].push(value);

        // removes dynamic property
        return '';
    }

    // complete
    if (context === 6) {
        selector = '';
        collection = '';
                dynamic = {};

        for (var key in dynamic) collection += key + dynamic[key].join('') + '}';

        // now you have all dynamic rule sets stored in collection
        // selector { ...dynamic props } ...etc
    }
}

@thysultan ๐Ÿ‘ that's indeed really easy, thank you!

render static css with the current system and inline the dynamic one i.e. each instance will get its own styles

@rauchg does this make sense? or can you think of a better way to optimize and avoid instance based styles?

Instead of allowing expressions like this ${ someProp ? 'red' : 'blue' } should we add support for functions only? ${ ({someProp}) => (someProp ? red : blue) }?

Also I think that we could auto detect dynamic styles if we want, do you still want to make it explicit?

I would love to see support for the styled-components-like function interpolation. Ideally using (props, context) => to match React in other places. It feels like it enables some powerful things.

Yeah, this is the only thing that makes me even slightly hesitant to commit to styled-jsx. Praying styled-jsx-postcss sticks around too.

Dynamic styles via props + PostCSS = ๐Ÿ˜๐Ÿ˜๐Ÿ˜

@ianstormtaylor Thumb for the issue? Might bump it up in priority. :X

Dynamic styles via props + PostCSS

This is going to be hard-ish to do since dynamic parts and in general expressions are replaced with placeholders. Also PostCSS runs at compile time not runtime.

@ianstormtaylor yup we are going to adopt a similar api (props, context) => {}. Are you using styled-jsx at Segment by any chance? If so maybe you guys can contribute? I could use some help.

About the priority this is going to happen after #148 (blocking) and a bunch of bug fixes and other minor features.

This is going to be hard-ish to do since dynamic parts and in general expressions are replaced with placeholders.

Do you have any ideas for how to approach this? I experimented a bit with a similar concept (template literals in CSS). My approach ran the file in a VM, somehow ignored the CSS (I forget exactly), captured via regex/parsed the JS and inserted it back where it was expressed.

I'm sure it's possible and could help out with this in the future (swamped for the next week at least) if you're interested in a proof of concept.

There's actually a lot of interesting stuff revolving around template literals + VMs. I feel like I was circling something really cool but never finished it.

Also PostCSS runs at compile time not runtime.

styled-jsx doesn't compile? How can it SSR? I thought SSR meant it just outputted a bunch of static (compiled) stuff. ๐Ÿค”

Sure why not, I would take a look at what you've got.

To be clear the problem is that in order for Stylis1 to work we need to replace expressions with placeholders so that the parser gets a simple (valid) CSS string.

This means that any expression (including dynamic styles in the future) is not processed by Stylis โ€“ not a big deal with plain styled-jsx probably since Stylis only adds scope (and autoprefixes) but in the case of PostCSS it could be worse.

182 could solve this problem I think.

[1] (the css processor which adds scoping by rewriting selectors to .foo[data-jsx="id"])

:+1:, the style attribute can't always account for things, like hover states and such.

/* doesn't work at the moment */
function ColorSwatch ({ color }) {
  return <div className='root'>
    <style jsx>{`
      .root { background: ${color}; }
      .root:hover { background: ${lighten(0.10, color)}; }
    `}</style>
  </div>
}

<ColorSwatch color='#aaddff' />

...defining a dynamic color for a hover state isn't possible in any way, at the moment.

@rstacruz I've got a branch which adds support for dynamic styles almost ready :) I might publish a beta this week.

Fixed by #288

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaydenseric picture jaydenseric  ยท  5Comments

loick picture loick  ยท  4Comments

TonyHYK picture TonyHYK  ยท  4Comments

giuseppeg picture giuseppeg  ยท  4Comments

pungggi picture pungggi  ยท  4Comments