Styled-jsx: Expressions within template literal don't work

Created on 7 Dec 2016  Â·  23Comments  Â·  Source: vercel/styled-jsx

I would understand if dynamic properties didn't work, but dynamic values don't seem to be working either. Compiling succeeds, but the pieces with the expression seem to be omitted from the inserted script tag.

<div>
    <div id={this.state.calendarId}></div>
    <style jsx>{`
            #${this.state.calendarId} .fc-button.fc-state-default {
                border: 2px solid ${buttonColor};
            }
    `}</style>
</div>

image


const buttonColor = 'red';

return (
    <div>
        <div id="foo"></div>
        <style jsx>{`
            #foo .fc-button.fc-state-default {
                border: 2px solid ${buttonColor};
            }
        `}</style>
    </div>
);

image


<div>
    <div id="foo"></div>
    <style jsx>{`
        #foo .fc-button.fc-state-default {
            border: 2px solid red;
        }
    `}</style>
</div>

image

Thank you!

enhancement

Most helpful comment

@rauchg Yeah this would work and indeed add basic support for constants.
Maybe we can allow anything except for inline (anonymous) functions? The following should all be valid:

`p { color: ${myColor)}; }`
`p { color: ${darken(myColor))}; }`
`div { width: ${5*gridCellSize}px; }`

I assume that any constant in the module scope is valid right? or were you thinking about restricting to the innermost scope? (the render one usually)

All 23 comments

Yeah this is something that could definitely work, but it's going to take some work. @hzoo, is it possible to create a babel template literal expression from _text_ that includes ${}? That way we can pass the raw text to the css compiler containing the ${}, and then pass it back to babel

The problem is that the css gets added only once per component, so the CSS can't really be dynamic

We'd have to think about a way of bypassing the deduping if properties are used, but the problem there is that it would really hurt performance

This is a problem with styled-components as well at the moment

Ah I see, thank you for the explanation

Would it be possible to insert the style tag where it's indicated instead of appending to the <head>, and then scoping for each instantiated component instead? That could potentially increase the amount of outputted HTML/CSS substantially, but shouldn't hurt runtime performance extremely badly, unless I'm missing something.

Er I guess not appending to the head doesn't really solve any problems, that would be just the same as not deduping at all, never mind.

Essentially we need to dedupe based on the resulting CSS string as opposed to the hash. But then components could conflict. Therefore, we would need to figure out a way of targeting elements within a specific component

In general, if you ask me, the power of CSS is in it _not being dynamic_, because it can be heavily optimized. For example, you declare a bunch of classes, and all your event handlers do is _toggle them_.

I'm keeping this open in case we figure a workaround, but otherwise I'm keeping it open because we need to warn the user during compilation

That's true. I'm mainly trying to do this to easily style a dom element I don't have control over, but I guess I can just as easily do it directly with JS instead.

That's reasonable, I think it would be nice to mention in the README somewhere that expressions aren't supported in addition to a compile-time warning. Having never used styled-components before I just assumed this would work and I imagine others might too. Thanks!

Unless it is mentioned somewhere in the docs and I'm just blind, I apologize if that's the case.

See #26

@rauchg actually you can with styled-components.
You can do this:

import styled from 'styled-components';

const orangeColor = 'orange';
const align = 'right';

const Title = styled.h1`
  font-size: 1.5em;
  text-align: ${align};
  color: ${orangeColor};
`;

To be able to do this is very important. Otherwise, we cannot use javascript to manipulate colors, units, custom mixins like sass and other things like that...
Just toggle class is not enough.

Yep but dynamic stuff in CSS has serious performance tradeoffs. it's
something I might consider but being static is also an advantage for
predictable perf

On Sun, Dec 18, 2016 at 4:16 PM Bruno Lourenço notifications@github.com
wrote:

@rauchg https://github.com/rauchg actually you can with
styled-components.

You can do this:

import styled from 'styled-components';

const orangeColor = 'orange';

const align = 'right';

const Title = styled.h1`

font-size: 1.5em;

text-align: ${align};

color: ${orangeColor};

`;

To be able to do this is very important. Otherwise, we cannot use
javascript to manipulate colors, units, custom mixins like sass and other
things like that...

Just toggle class is not enough.

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/zeit/styled-jsx/issues/25#issuecomment-267857842, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAAy8T5GvaWDcknTutAiCloJxQB_p4Zaks5rJczpgaJpZM4LGyuw
.

I'm thinking code sharing and being static. One simple pattern that's been possible for a while by using CSS preprocessors (and I guess post processors too) is the ability to f.ex. declare all used colors in one place and then use these colors across the app by referencing the variable name that holds the color code. As these colors are declared once and used all around the app it's really easy to tweak them when necessary.

If you don't follow this kind of pattern and you f.ex need to change a color you either need to go through all components on your app and update the color by hand or do a really careful search & replace. In bigger codebases without a centralized solution for things like colors, z-indexes etc. seeing the bigger picture becomes hard and it will lead to fragmentation.

Though the case here is very different I've always seen CSS pre and post processors as static code generators. Though I understand why you're avoiding dynamic stuff I don't understand why it should stand in way of code sharing. Or is there currently a way to achieve something close to what I've described above with styled-jsx?

Yes I realized the other day that we can support expressions from outside
the closure (i.e.: not from props) for shared constants like colors and
fonts

On Wed, Dec 21, 2016 at 11:50 AM Joonas Salovaara notifications@github.com
wrote:

I'm thinking code sharing and being static. One simple pattern that's been
possible for a while by using CSS preprocessors (and I guess post
processors too) is the ability to f.ex. declare all used colors in one
place and then use these colors across the app by referencing the variable
name that holds the color code. As these colors are declared once and used
all around the app it's really easy to tweak them when necessary.

If you don't follow this kind of pattern and you f.ex need to change a
color you either need to go through all components on your app and update
the color by hand or do a really careful search & replace. In bigger
codebases without a centralized solution for things like colors, z-indexes
etc. seeing the bigger picture becomes hard and it will lead to
fragmentation.

Though the case here is very different I've always seen CSS pre and post
processors as static code generators. Though I understand why you're
avoiding dynamic stuff I don't understand why it should stand in way of
code sharing. Or is there currently a way to achieve something close to
what I've described above with styled-jsx?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/zeit/styled-jsx/issues/25#issuecomment-268621919, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAAy8V1fQb-_PDwdOCsgJu1qKmC7YNlgks5rKYMSgaJpZM4LGyuw
.

@rauchg So this is in the roadmap? 🙂

@rauchg how would you calculate the hash in that case? Are you thinking of resolving expressions by hand before hashing the css?

Basically we'd do as much as we can to ensure people are using _constants_ (by preventing usage of expressions that only live within the scope), and we'd hash with the name of the constant, not the value (to avoid complexity).

Obviously there are edge cases where people will have their expectations of dynamism not met, but if we prevent props / state from being used, we cover most potential surprises.

Would you agree?

@rauchg Yeah this would work and indeed add basic support for constants.
Maybe we can allow anything except for inline (anonymous) functions? The following should all be valid:

`p { color: ${myColor)}; }`
`p { color: ${darken(myColor))}; }`
`div { width: ${5*gridCellSize}px; }`

I assume that any constant in the module scope is valid right? or were you thinking about restricting to the innermost scope? (the render one usually)

🤔 I'm beginning to wonder if using CSS variables (especially for top level themes) would be the best choice for me. It does impose an implicit API on the components for css variables to be predefined.

I tend to leverage css variables for dynamic values such as this.

Something like the following:

MyComponent.jsx

function MyComponent({ children, color, fontSize }){
    return <p class='MyComponent' style={{
        '--MyComponent-color': color,
        '--MyComponent-fontSize': fontSize
    }}>{children}</p>
}

MyComonent.css

.MyComponent {
    color: var(--MyComponent-color);
    font-size: var(--MyComponent-fontSize);
}

```

Was this page helpful?
0 / 5 - 0 ratings

Related issues

straxico picture straxico  Â·  4Comments

corysimmons picture corysimmons  Â·  4Comments

soulchainer picture soulchainer  Â·  5Comments

callumlocke picture callumlocke  Â·  5Comments

adamyonk picture adamyonk  Â·  3Comments