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

Why are interactions and custom elements global? #128

Closed
KidkArolis opened this Issue Jun 4, 2015 · 111 comments

Comments

Projects
None yet
@KidkArolis

I just started playing with Cycle and it looks really cool!

To me, two things immediately surprised me, so I was wondering if I'm missing something.

  1. interactions.get(selector, eventName) in all examples I've seen pass in a selector (not a dom element) which means those selectors are queried globally in the entire DOM. Surely this is really impractical, you want to scope it all down to specific components, the way you can easily do with React's inline handlers? Wouldn't it be better if say you handle events in the view and then emit to the interactions stream the low level event or a higher level intent?
  2. registerCustomElement seems to register elements globally. Again, this is, imho, mush inferior to how something like React does it where you require components and use them by reference. Is there a way to do that in Cycle? `var Button = require("./button"); Button({}). Sorry if this is documented somewhere, I couldn't find an example/docs.

@staltz staltz added the discussion label Jun 5, 2015

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 5, 2015

Member

Hi, nice that you like it.

interactions.get(selector, eventName) in all examples I've seen pass in a selector (not a dom element) which means those selectors are queried globally in the entire DOM. Surely this is really impractical, you want to scope it all down to specific components

The contract in Cycle should be that selectors are not queried globally because they shouldn't inspect inside a custom element. It also doesn't select from the window as a parent, it selects scoped to the container div you gave to applyToDOM. So it should have both upper and lower boundaries.

Wouldn't it be better if say you handle events in the view and then emit to the interactions stream the low level event or a higher level intent?

There is a reason why events are not handled in the "view". View should only be concerned with rendering, i.e. how things look. Event handling is how it works. Read more here. On the other hand, after #116 is ready, it will be possible to make a React adapter which works like you want. But I recommend first thinking why do you say something is impractical, and why is the other way better. For instance inline styles are often seen as a bad idea, but vjeux explained to the community that sometimes such as in the Virtual DOM case it might make more sense, and might be better.

registerCustomElement seems to register elements globally. Again, this is, imho, mush inferior to how something like React does it where you require components and use them by reference.

This will change with #116, custom elements will not be registered globally with a mutable API, but they still will be specified at the top-most level, and given down through the view hierarchy. If you think it is inferior, please explain why. And again, with #116 it will be possible to have a React adapter and do this the way you want.

Member

staltz commented Jun 5, 2015

Hi, nice that you like it.

interactions.get(selector, eventName) in all examples I've seen pass in a selector (not a dom element) which means those selectors are queried globally in the entire DOM. Surely this is really impractical, you want to scope it all down to specific components

The contract in Cycle should be that selectors are not queried globally because they shouldn't inspect inside a custom element. It also doesn't select from the window as a parent, it selects scoped to the container div you gave to applyToDOM. So it should have both upper and lower boundaries.

Wouldn't it be better if say you handle events in the view and then emit to the interactions stream the low level event or a higher level intent?

There is a reason why events are not handled in the "view". View should only be concerned with rendering, i.e. how things look. Event handling is how it works. Read more here. On the other hand, after #116 is ready, it will be possible to make a React adapter which works like you want. But I recommend first thinking why do you say something is impractical, and why is the other way better. For instance inline styles are often seen as a bad idea, but vjeux explained to the community that sometimes such as in the Virtual DOM case it might make more sense, and might be better.

registerCustomElement seems to register elements globally. Again, this is, imho, mush inferior to how something like React does it where you require components and use them by reference.

This will change with #116, custom elements will not be registered globally with a mutable API, but they still will be specified at the top-most level, and given down through the view hierarchy. If you think it is inferior, please explain why. And again, with #116 it will be possible to have a React adapter and do this the way you want.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

For instance inline styles are often seen as a bad idea, but vjeux explained to the community that sometimes such as in the Virtual DOM case it might make more sense, and might be better.

I wonder how do they propose to style nested tags with this "inline styles" approach? Anyone knows? CSS works how it does (everything is global) because it allows you to traverse into component and change it's inner styles from your app stylesheet.

Contributor

ivan-kleshnin commented Jun 5, 2015

For instance inline styles are often seen as a bad idea, but vjeux explained to the community that sometimes such as in the Virtual DOM case it might make more sense, and might be better.

I wonder how do they propose to style nested tags with this "inline styles" approach? Anyone knows? CSS works how it does (everything is global) because it allows you to traverse into component and change it's inner styles from your app stylesheet.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 5, 2015

Member

You can give styles as props, for instance.

Member

staltz commented Jun 5, 2015

You can give styles as props, for instance.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

That's the thing. Your only way to style nested tag without global CSS is to implement an extremely clunky namespacing solution on your own. I doubt anyone will succeed here for anything bigger than hello-div.

Most web components (in broad terms) contains tenths of nested tags.
With CSS I can easily access any tag inside this structure. I need to know only top-level class name (tag name, whatever).

<div class="clockworkOrange">
  <div>
    <div>
      ..
    </div>
  </div>
</div>

Did I miss the moment restyling of 3-rd party components had become uneeded? I guess no.

How to do this through props?

In app:

<ClockWorkOrange 
  firstDivFromTheTopStyle={firstDivFromTheTopStyle} 
  secondDivFromTheTopFourthSiblingStyle={secondDivFromTheTopFourthSiblingStyle} 
...omg/>

And in library:

<div>
  <div style={firstDivFromTheTopStyle}> 
    ...
    <div style={secondDivFromTheTopFourthSiblingStyle}>
      ...
   </div>
  </div>
<div/>

This is still not gonna work for repeating items... 😞
So I'm very curious why React team is so pushy in enforcing us this local-style vision.

Because React native does support only local styles? That's their limitation. Desktop limitation.
They should better emulate CSS stylesheet there somehow. I'm sure this is possible.

Same thing with Webpack CSS "local scopes". They are worthless in practice. I dunno... maybe there are so many technologies today that people are just starting to loose the track of what they do.

Contributor

ivan-kleshnin commented Jun 5, 2015

That's the thing. Your only way to style nested tag without global CSS is to implement an extremely clunky namespacing solution on your own. I doubt anyone will succeed here for anything bigger than hello-div.

Most web components (in broad terms) contains tenths of nested tags.
With CSS I can easily access any tag inside this structure. I need to know only top-level class name (tag name, whatever).

<div class="clockworkOrange">
  <div>
    <div>
      ..
    </div>
  </div>
</div>

Did I miss the moment restyling of 3-rd party components had become uneeded? I guess no.

How to do this through props?

In app:

<ClockWorkOrange 
  firstDivFromTheTopStyle={firstDivFromTheTopStyle} 
  secondDivFromTheTopFourthSiblingStyle={secondDivFromTheTopFourthSiblingStyle} 
...omg/>

And in library:

<div>
  <div style={firstDivFromTheTopStyle}> 
    ...
    <div style={secondDivFromTheTopFourthSiblingStyle}>
      ...
   </div>
  </div>
<div/>

This is still not gonna work for repeating items... 😞
So I'm very curious why React team is so pushy in enforcing us this local-style vision.

Because React native does support only local styles? That's their limitation. Desktop limitation.
They should better emulate CSS stylesheet there somehow. I'm sure this is possible.

Same thing with Webpack CSS "local scopes". They are worthless in practice. I dunno... maybe there are so many technologies today that people are just starting to loose the track of what they do.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

@ivan-kleshnin If you haven't found a way to make something work, it doesn't make it "worthless". People including me have built, and are building large apps that don't treat CSS globally and rely on props for everything. It works surprisingly well if you embrace the component mentality and create smaller components. In fact you'd rarely, if ever, need to pass explicit styles, and instead control most of the appearance via vanilla props. Encapsulation is a win, nothing clunky about it. For off the shelf components, if you need that custom rendering, a better idea is to let you provide renderItem method like fixed-data-table does.

gaearon commented Jun 5, 2015

@ivan-kleshnin If you haven't found a way to make something work, it doesn't make it "worthless". People including me have built, and are building large apps that don't treat CSS globally and rely on props for everything. It works surprisingly well if you embrace the component mentality and create smaller components. In fact you'd rarely, if ever, need to pass explicit styles, and instead control most of the appearance via vanilla props. Encapsulation is a win, nothing clunky about it. For off the shelf components, if you need that custom rendering, a better idea is to let you provide renderItem method like fixed-data-table does.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

@gaearon so you just verified there is no other way except props 😞

I don't believe this is how the future should look like.

small component mentality

are just marketing words. In reality most of the people still use jQuery because it's the only way to have file loaders and other huge libraries available for them. Not every company has a budget and time to just stop everything and begin to reimplement every library they need in React. People use Angular not because it's better. Because it's more production ready and have all that matherial design libraries already developed and ready-to-use.

"Small components" hype is the same thing as "small modules" hype.
I remember you were wise saying "what is better – depends on the context".

For off the shelf components, if you need that custom rendering, a better idea is to let you provide renderItem method like fixed-data-table does.

Everyone will need that at some moment. That's the problem.
I just don't like when people hide drawbacks for PR or marketing reasons.
Don't we deserve to know the truth about both sides of the coin?

In fact you'd rarely, if ever, need to pass explicit styles, and instead control most of the appearance via vanilla props.

Web is about sharing and restyling. How many props would be enough for video player to
get the desired "look and feel"? Are we going to replicate all famous desktop styling issues in web and call this "progress"? Maybe local styles will win. I dunno. I just want an open discussion instead of declarations. For now we're getting declarations mostly.

If you haven't found a way to make something work, it doesn't make it "worthless".

Of course it doesn't. That's why I'm asking people how to solve my problems.

Contributor

ivan-kleshnin commented Jun 5, 2015

@gaearon so you just verified there is no other way except props 😞

I don't believe this is how the future should look like.

small component mentality

are just marketing words. In reality most of the people still use jQuery because it's the only way to have file loaders and other huge libraries available for them. Not every company has a budget and time to just stop everything and begin to reimplement every library they need in React. People use Angular not because it's better. Because it's more production ready and have all that matherial design libraries already developed and ready-to-use.

"Small components" hype is the same thing as "small modules" hype.
I remember you were wise saying "what is better – depends on the context".

For off the shelf components, if you need that custom rendering, a better idea is to let you provide renderItem method like fixed-data-table does.

Everyone will need that at some moment. That's the problem.
I just don't like when people hide drawbacks for PR or marketing reasons.
Don't we deserve to know the truth about both sides of the coin?

In fact you'd rarely, if ever, need to pass explicit styles, and instead control most of the appearance via vanilla props.

Web is about sharing and restyling. How many props would be enough for video player to
get the desired "look and feel"? Are we going to replicate all famous desktop styling issues in web and call this "progress"? Maybe local styles will win. I dunno. I just want an open discussion instead of declarations. For now we're getting declarations mostly.

If you haven't found a way to make something work, it doesn't make it "worthless".

Of course it doesn't. That's why I'm asking people how to solve my problems.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

"Small components" hype is the same thing as "small modules" hype.

I'm not selling you anything and I don't care about hype. I'm sharing the experience I gained building a complex webapp with complex styles and UI in a team together with a designer in React. What I'm saying is, if you approach components as large templates, like people usually do Backbone views, you're going to have the problems you described above. If you make smaller components and use composition more, you'll find that the <Button color='red' fill /> is much easier to use across the codebase than <Button styles=... />. And that expressing bigger components in terms of smaller components with existing styling is much more convenient than using global CSS styles. But surely you're free to not take my word and insist “composition” is a marketing buzzword I'm trying to fool you with. Whatever :-).

Web is about sharing and restyling. How many props would be enough for video player to
get the desired "look and feel"?

It's a trick question. This is “smart and dumb components” all over again. “Video player”-like stock components made sense in jQuery land, but I don't think they make any sense in React land.

With React, you probably want a <Player> component that manages <video> without any styling and has isPlaying, currentPosition and onChange props so you can build any custom UI for it in an hour. Somehow I wrote a drag and drop library that makes zero assumption about how your components render. fixed-data-table doesn't make those assumptions either. This is because such components are “controllers”.

On the other side of the spectrum are stock components whose only point is to provide style, not functionality. Think “Material design” components. For them, it doesn't make any sense to override the styles because the only reason you'd use them is for their consistent styling.

So yes, “restyling” a component that tangles functionality and styling is hard. But that's a strawman because such components don't make sense in React. Create <Player> and <MyBeautifulPlayerControls>, or <Player> and <PlayerControlsUsingMaterialDesignUnderTheHood>.

PS If you'd like to continue this argument, please create a Gist so we don't spam the Cycle issue tracker.

gaearon commented Jun 5, 2015

"Small components" hype is the same thing as "small modules" hype.

I'm not selling you anything and I don't care about hype. I'm sharing the experience I gained building a complex webapp with complex styles and UI in a team together with a designer in React. What I'm saying is, if you approach components as large templates, like people usually do Backbone views, you're going to have the problems you described above. If you make smaller components and use composition more, you'll find that the <Button color='red' fill /> is much easier to use across the codebase than <Button styles=... />. And that expressing bigger components in terms of smaller components with existing styling is much more convenient than using global CSS styles. But surely you're free to not take my word and insist “composition” is a marketing buzzword I'm trying to fool you with. Whatever :-).

Web is about sharing and restyling. How many props would be enough for video player to
get the desired "look and feel"?

It's a trick question. This is “smart and dumb components” all over again. “Video player”-like stock components made sense in jQuery land, but I don't think they make any sense in React land.

With React, you probably want a <Player> component that manages <video> without any styling and has isPlaying, currentPosition and onChange props so you can build any custom UI for it in an hour. Somehow I wrote a drag and drop library that makes zero assumption about how your components render. fixed-data-table doesn't make those assumptions either. This is because such components are “controllers”.

On the other side of the spectrum are stock components whose only point is to provide style, not functionality. Think “Material design” components. For them, it doesn't make any sense to override the styles because the only reason you'd use them is for their consistent styling.

So yes, “restyling” a component that tangles functionality and styling is hard. But that's a strawman because such components don't make sense in React. Create <Player> and <MyBeautifulPlayerControls>, or <Player> and <PlayerControlsUsingMaterialDesignUnderTheHood>.

PS If you'd like to continue this argument, please create a Gist so we don't spam the Cycle issue tracker.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

I'm not selling you anything and I don't care about hype. I'm sharing the experience I gained building a complex webapp with complex styles and UI in a team together with a designer in React. What I'm saying is, if you approach components as large templates, like people usually do Backbone views, you're going to have the problems you described above. If you make smaller components and use composition more, you'll find that the is much easier to use across the codebase than . And that expressing bigger components in terms of smaller components with existing styling is much more convenient than using global CSS styles. But surely you're free to not take my word and insist “composition” is a marketing buzzword I'm trying to fool you with. Whatever :-).

Imagine that you are a developer and business tells you to integrate this shiny new video player they've just purchased into their site. They require you to be "pixel-perfect". That player is built from small components just as guru teach us.

<VideoPlayer>
  <VideoPlayerHeader>
    ...
  </VideoPlayerHeader>
  <VideoPlayerFooter>
    ...
  </VideoPlayerFooter>
</VideoPlayer>

And then you're starting to tweak it...

<VideoPlayer margin={50} fontFamily="Roboto" lineHeight=...>
  <VideoPlayerHeader pauseIconColorBackground="yellow"...>
    ...
  </VideoPlayerHeader>
  <VideoPlayerFooter ...>
    ...
  </VideoPlayerFooter>
</VideoPlayer>

I wish you good luck doing that.

Don't you extrapolate your specific one-project experience to all cases of all people in the world? Did you use 3-rd party components? What were your styleguides? Did you fallback to global styles every time you met a problem I described and just considered that "edge-cases"?

There is an enterprise world. Like Facebook where they may create everything they need. Even Immutable library instead of Mori. Because of infinite budget. Or take Google+ created just for fun. That's ok. There is also a world of a small and medium business. Which does have limitations. And that is ok again. Problems appear when people start to disguise a strictly enterprise solution for a "normal", "standard" or "definitely better".

“Video player”-like stock components made sense in jQuery land, but I don't think they make any sense in React land.

What are Web Components then? They may be implemented in a "revealing" style for "better control".

<Container><Item/></Container> vs <Component/> 

In any case, that does not provide a 1% of the flexibility you have with CSS stylesheets.

But that's a strawman because such components don't make sense in React.

Are you talking about React or about your own vision of React?

PS If you'd like to continue this argument, please create a Gist so we don't spam the Cycle issue tracker.

I don't think this is a spam. This is important and is related to Cycle components to the same matter as to React. I want to receive more feedback from people about local styles. If you don't have arguments, that's normal. You can unsubscribe from this thread if you're bullet-proof in your opinion.

Contributor

ivan-kleshnin commented Jun 5, 2015

I'm not selling you anything and I don't care about hype. I'm sharing the experience I gained building a complex webapp with complex styles and UI in a team together with a designer in React. What I'm saying is, if you approach components as large templates, like people usually do Backbone views, you're going to have the problems you described above. If you make smaller components and use composition more, you'll find that the is much easier to use across the codebase than . And that expressing bigger components in terms of smaller components with existing styling is much more convenient than using global CSS styles. But surely you're free to not take my word and insist “composition” is a marketing buzzword I'm trying to fool you with. Whatever :-).

Imagine that you are a developer and business tells you to integrate this shiny new video player they've just purchased into their site. They require you to be "pixel-perfect". That player is built from small components just as guru teach us.

<VideoPlayer>
  <VideoPlayerHeader>
    ...
  </VideoPlayerHeader>
  <VideoPlayerFooter>
    ...
  </VideoPlayerFooter>
</VideoPlayer>

And then you're starting to tweak it...

<VideoPlayer margin={50} fontFamily="Roboto" lineHeight=...>
  <VideoPlayerHeader pauseIconColorBackground="yellow"...>
    ...
  </VideoPlayerHeader>
  <VideoPlayerFooter ...>
    ...
  </VideoPlayerFooter>
</VideoPlayer>

I wish you good luck doing that.

Don't you extrapolate your specific one-project experience to all cases of all people in the world? Did you use 3-rd party components? What were your styleguides? Did you fallback to global styles every time you met a problem I described and just considered that "edge-cases"?

There is an enterprise world. Like Facebook where they may create everything they need. Even Immutable library instead of Mori. Because of infinite budget. Or take Google+ created just for fun. That's ok. There is also a world of a small and medium business. Which does have limitations. And that is ok again. Problems appear when people start to disguise a strictly enterprise solution for a "normal", "standard" or "definitely better".

“Video player”-like stock components made sense in jQuery land, but I don't think they make any sense in React land.

What are Web Components then? They may be implemented in a "revealing" style for "better control".

<Container><Item/></Container> vs <Component/> 

In any case, that does not provide a 1% of the flexibility you have with CSS stylesheets.

But that's a strawman because such components don't make sense in React.

Are you talking about React or about your own vision of React?

PS If you'd like to continue this argument, please create a Gist so we don't spam the Cycle issue tracker.

I don't think this is a spam. This is important and is related to Cycle components to the same matter as to React. I want to receive more feedback from people about local styles. If you don't have arguments, that's normal. You can unsubscribe from this thread if you're bullet-proof in your opinion.

@ArnoBuschmann

This comment has been minimized.

Show comment
Hide comment
@ArnoBuschmann

ArnoBuschmann Jun 5, 2015

I just feel the urge to mention, that I extremely appreciate to read the opinion of you both, @ivan-kleshnin and @gaearon. There is no need at all to attack of feel being attacked. It's all about solutions and many ways lead to rome.

Actually I were thinking about on how to handle CSS best in Cycle these days. Thanks again for this discussion, it is interesting and related, so stay and keep it going right here ;)

I just feel the urge to mention, that I extremely appreciate to read the opinion of you both, @ivan-kleshnin and @gaearon. There is no need at all to attack of feel being attacked. It's all about solutions and many ways lead to rome.

Actually I were thinking about on how to handle CSS best in Cycle these days. Thanks again for this discussion, it is interesting and related, so stay and keep it going right here ;)

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

Styling third-party component with custom global CSS is an escape hatch. Escape hatches are cool for solving the problem you described (you are given a black box with bad API and you are ordered to use it).

Another example of a similar escape hatch is monkeypatching. Nobody likes monkeypatching but it's essential for some use cases when you're given something that doesn't work exactly like you want, and offers no extension points.

But this doesn't mean monkeypatching should be the primary means of extending something. Overriding third-party CSS is conceptually the same thing as monkeypatching. Suitable in some situations but you should try to avoid it if possible.

Did you use 3-rd party components? What were your styleguides? Did you fallback to global styles every time you met a problem I described and just considered that "edge-cases"?

We had no styleguides. Our designer worked directly on the components. The styleguide was to use that component palette. This ensured consistency.

Sometimes we used “pre-React” third-party components that had their own styling. Yes, we falled back to patching global styles for them, but wrapped them into React components that encapsulated this implementation detail and had a declarative API. The rest of the codebase would then use React components. When we had time, we'd reimplement these components in React.

We never needed to use third-party React components with built-in styling. I never found them valuable. To have consistent styling, we needed to use our own component palette (that includes our <Button>, etc). We used third-party React components for functionality (think data table, actual video player). They had injection points for rendering custom rows / panels / whatever. It's too trivial to implement “player controls” with declarative paradigm that I don't see any value in using stock ones. (Unless you're forced to do so, in which case, as I said above, you're welcome to use global styles, but yes, it's an escape hatch just like monkeypatching is.)

What are Web Components then?

WCs don't solve my problems. I don't know.

If you don't have arguments, that's normal. You can unsubscribe from this thread if you're bullet-proof in your opinion.

This is an interesting argument, I'm just not sure if it matches what the thread was originally about.

cc @markdalgleish

gaearon commented Jun 5, 2015

Styling third-party component with custom global CSS is an escape hatch. Escape hatches are cool for solving the problem you described (you are given a black box with bad API and you are ordered to use it).

Another example of a similar escape hatch is monkeypatching. Nobody likes monkeypatching but it's essential for some use cases when you're given something that doesn't work exactly like you want, and offers no extension points.

But this doesn't mean monkeypatching should be the primary means of extending something. Overriding third-party CSS is conceptually the same thing as monkeypatching. Suitable in some situations but you should try to avoid it if possible.

Did you use 3-rd party components? What were your styleguides? Did you fallback to global styles every time you met a problem I described and just considered that "edge-cases"?

We had no styleguides. Our designer worked directly on the components. The styleguide was to use that component palette. This ensured consistency.

Sometimes we used “pre-React” third-party components that had their own styling. Yes, we falled back to patching global styles for them, but wrapped them into React components that encapsulated this implementation detail and had a declarative API. The rest of the codebase would then use React components. When we had time, we'd reimplement these components in React.

We never needed to use third-party React components with built-in styling. I never found them valuable. To have consistent styling, we needed to use our own component palette (that includes our <Button>, etc). We used third-party React components for functionality (think data table, actual video player). They had injection points for rendering custom rows / panels / whatever. It's too trivial to implement “player controls” with declarative paradigm that I don't see any value in using stock ones. (Unless you're forced to do so, in which case, as I said above, you're welcome to use global styles, but yes, it's an escape hatch just like monkeypatching is.)

What are Web Components then?

WCs don't solve my problems. I don't know.

If you don't have arguments, that's normal. You can unsubscribe from this thread if you're bullet-proof in your opinion.

This is an interesting argument, I'm just not sure if it matches what the thread was originally about.

cc @markdalgleish

@radubrehar

This comment has been minimized.

Show comment
Hide comment
@radubrehar

radubrehar Jun 5, 2015

I see the css-loader as a solution for styling components in isolation and also providing a way for users of the component to easily extend them.

Say I have a datepicker (which I really do, check out https://www.npmjs.com/package/react-date-picker). I will add both a autogenerated className and a component className. I illustract this with some code:

:local(.picker)
     //picker styles

     .inner
           //picker inner styles
var ClassName = require('./index.styl')
var DatePicker = React.createClass({
    render(){
             var className="date-picker " + ClassName.picker
             return <div className={className}>
                 <div className="inner">
                      //....
                </div>
            </div>
    }
})

In this way, I am certain that my component styles are really isolated (since all my selectors are nested inside the autogenerated/prefixed one), and people can also customize whatever they want (since I also add the static "date-picker" class.

I see this as a very good mix. What's your opinion.

PS: I also use inline-styles quite a lot :)

I see the css-loader as a solution for styling components in isolation and also providing a way for users of the component to easily extend them.

Say I have a datepicker (which I really do, check out https://www.npmjs.com/package/react-date-picker). I will add both a autogenerated className and a component className. I illustract this with some code:

:local(.picker)
     //picker styles

     .inner
           //picker inner styles
var ClassName = require('./index.styl')
var DatePicker = React.createClass({
    render(){
             var className="date-picker " + ClassName.picker
             return <div className={className}>
                 <div className="inner">
                      //....
                </div>
            </div>
    }
})

In this way, I am certain that my component styles are really isolated (since all my selectors are nested inside the autogenerated/prefixed one), and people can also customize whatever they want (since I also add the static "date-picker" class.

I see this as a very good mix. What's your opinion.

PS: I also use inline-styles quite a lot :)

@natew

This comment has been minimized.

Show comment
Hide comment
@natew

natew Jun 5, 2015

I think Pete is getting closer, but @ivan-kleshnin is right about the style issue with tags. This is a problem with inline style encapsulation.

In my experience (writing a UI framework) I ended up having to "tag" all of my inner elements and have a syntax for people to style them, for example, say a Post component:

<div {...props()}>
  <h1 {...props('title')}>Title</h1>
</div>

And then built a mixin of sorts that resolves these if you pass in a styles prop:

<Post styles={{ self: { background: 'black' }, title: { fontSize: 20 } }} />

Because even in small components you would lose this power. Now, given it's a UI kit it's on the extreme. But I think this is important. If I want to borrow any visual component from any npm library right now in React, unknown how I'll be able to style it... props, import CSS, some custom library.

I think this is a big gap in React (it's supposed to be the View right?), and Pete's example actually illustrates it. Now, my hack is not great either. You have to explicitly use a method, it's inconsistent, and more.

Now, this sounds off topic but is related: why are we using <div> everywhere? It has no meaning, and so many of our tags are just <div> or <span>. I'd like to do this for the example above:

<post>
  <title>Title</title>
</post>

And have a standardized way for that to be styled. With small components you can easily have everything unique. If you need to use semantic tags like h1 you can (and they can be styled!). Class names should still be used in the right situation and handled, so I can pass in styles and they all apply automatically.

Just thoughts from experience and experiments in this area.

natew commented Jun 5, 2015

I think Pete is getting closer, but @ivan-kleshnin is right about the style issue with tags. This is a problem with inline style encapsulation.

In my experience (writing a UI framework) I ended up having to "tag" all of my inner elements and have a syntax for people to style them, for example, say a Post component:

<div {...props()}>
  <h1 {...props('title')}>Title</h1>
</div>

And then built a mixin of sorts that resolves these if you pass in a styles prop:

<Post styles={{ self: { background: 'black' }, title: { fontSize: 20 } }} />

Because even in small components you would lose this power. Now, given it's a UI kit it's on the extreme. But I think this is important. If I want to borrow any visual component from any npm library right now in React, unknown how I'll be able to style it... props, import CSS, some custom library.

I think this is a big gap in React (it's supposed to be the View right?), and Pete's example actually illustrates it. Now, my hack is not great either. You have to explicitly use a method, it's inconsistent, and more.

Now, this sounds off topic but is related: why are we using <div> everywhere? It has no meaning, and so many of our tags are just <div> or <span>. I'd like to do this for the example above:

<post>
  <title>Title</title>
</post>

And have a standardized way for that to be styled. With small components you can easily have everything unique. If you need to use semantic tags like h1 you can (and they can be styled!). Class names should still be used in the right situation and handled, so I can pass in styles and they all apply automatically.

Just thoughts from experience and experiments in this area.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

I just can't see “styling” as something separate from “generating markup”. What's the point in being able to attach styles to a <div> if you can't, for example, wrap it into an extra <div> for some flexbox styling?

Thus

If I want to borrow any visual component from any npm library right now in React, it's a total surprise how I'll be able to style it.

becomes

“If I want to borrow any visual component from any npm library right now in React, it's a total surprise how I'll be able to change how it renders.”

And the answer is: use the stock components that let you inject the rendering. <List renderItem={this.renderItem} /> is fine, probably with some default renderItem implementation. Don't use stock components that don't let you inject the rendering if you want to customize it later—it's a recipe for disaster.

No?

gaearon commented Jun 5, 2015

I just can't see “styling” as something separate from “generating markup”. What's the point in being able to attach styles to a <div> if you can't, for example, wrap it into an extra <div> for some flexbox styling?

Thus

If I want to borrow any visual component from any npm library right now in React, it's a total surprise how I'll be able to style it.

becomes

“If I want to borrow any visual component from any npm library right now in React, it's a total surprise how I'll be able to change how it renders.”

And the answer is: use the stock components that let you inject the rendering. <List renderItem={this.renderItem} /> is fine, probably with some default renderItem implementation. Don't use stock components that don't let you inject the rendering if you want to customize it later—it's a recipe for disaster.

No?

@radubrehar

This comment has been minimized.

Show comment
Hide comment
@radubrehar

radubrehar Jun 5, 2015

I totally agree to using props as render/factory functions. It provides people with the flexibility they need to either change styling or bring in a totally new markup!

I totally agree to using props as render/factory functions. It provides people with the flexibility they need to either change styling or bring in a totally new markup!

@natew

This comment has been minimized.

Show comment
Hide comment
@natew

natew Jun 5, 2015

The view layer should handle style. If it did that properly there would be no argument, I could use anyone's logic and markup, something made with love (and accessibility, browser support, etc) and still style every piece of it I need.

If I want to use a really well designed Button and change one color or tweak the font size, I should be able to, no?

natew commented Jun 5, 2015

The view layer should handle style. If it did that properly there would be no argument, I could use anyone's logic and markup, something made with love (and accessibility, browser support, etc) and still style every piece of it I need.

If I want to use a really well designed Button and change one color or tweak the font size, I should be able to, no?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

If I want to use a really well designed Button and change one color or tweak the font size, I should be able to, no?

A well-designed <Button> would probably accept a single tint prop and adjust all its colors based on it (e.g. shadow colors, border colors, etc.) This is proper encapsulation. This is how it works in iOS too. If this customization is not enough, why do you need to use that particular <Button> at all? Clearly it isn't what you wanted..

As for the font size or family, a well designed <Button> shouldn't specify it at all. Thus, the parent element (or even <body>) decides its font size and family. I'm not advocating “no CSS inheritance at all”—it can be useful in situations like this. I'm just advocating “no overriding”.

If particular styles are important to component (such as color), it should expose them as props (such as tint). It particular styles are not important to component (such as fontFamily), it shouldn't specify them at all.

Finally, as the ultimate escape hatch, component may accept styles prop with fields like header, border, content, playerButton etc. This makes such overrides explicit part of component's API.

<SuperFlexibleVideoPlayer styles={{
  pauseButton: { backgroundColor: 'yellow' },
  container: { display: 'flex' },
  ...
}} />

gaearon commented Jun 5, 2015

If I want to use a really well designed Button and change one color or tweak the font size, I should be able to, no?

A well-designed <Button> would probably accept a single tint prop and adjust all its colors based on it (e.g. shadow colors, border colors, etc.) This is proper encapsulation. This is how it works in iOS too. If this customization is not enough, why do you need to use that particular <Button> at all? Clearly it isn't what you wanted..

As for the font size or family, a well designed <Button> shouldn't specify it at all. Thus, the parent element (or even <body>) decides its font size and family. I'm not advocating “no CSS inheritance at all”—it can be useful in situations like this. I'm just advocating “no overriding”.

If particular styles are important to component (such as color), it should expose them as props (such as tint). It particular styles are not important to component (such as fontFamily), it shouldn't specify them at all.

Finally, as the ultimate escape hatch, component may accept styles prop with fields like header, border, content, playerButton etc. This makes such overrides explicit part of component's API.

<SuperFlexibleVideoPlayer styles={{
  pauseButton: { backgroundColor: 'yellow' },
  container: { display: 'flex' },
  ...
}} />
@natew

This comment has been minimized.

Show comment
Hide comment
@natew

natew Jun 5, 2015

I can see that point, though I see no downside in a component system that let you style any element inside a component you import. Only upsides, potentially pretty big just from personal experience.

What if I want to add a inner shadow to the Button? Or round some of the edges based on where I put it? It seems there are a thousand little ways I may want to style it, and to make the authors have consider them all puts the burden in the wrong place.

In other words, a let's make it really easy to have a well-designed Button. It should just get the logic right and the markup. If I like how it works I should be able to use it any way I like, without having to inspect if it's "well designed" enough for me to style it or not.

Edit: (made some edits / added last paragraph after publishing)

natew commented Jun 5, 2015

I can see that point, though I see no downside in a component system that let you style any element inside a component you import. Only upsides, potentially pretty big just from personal experience.

What if I want to add a inner shadow to the Button? Or round some of the edges based on where I put it? It seems there are a thousand little ways I may want to style it, and to make the authors have consider them all puts the burden in the wrong place.

In other words, a let's make it really easy to have a well-designed Button. It should just get the logic right and the markup. If I like how it works I should be able to use it any way I like, without having to inspect if it's "well designed" enough for me to style it or not.

Edit: (made some edits / added last paragraph after publishing)

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

@ArnoBuschmann I just took a walk yesterday and was striked by the thought about local styles.
I wanted to hold on with a new hot debates after my last one in Ramda repo 😄 but Andre mentioned local styles and I could not refrain myself.

Also relevant: https://github.com/petehunt/jsxstyle#what-about-re-theming-off-the-shelf-components
What about re-theming off-the-shelf components?
This is a bug in CSS, not a feature.

Yes. Pete Hunt is always aware how to make our lifes better. Even when against our wills.

Styling third-party component with custom global CSS is an escape hatch. Escape hatches are cool for solving the problem you described (you are given a black box with bad API and you are ordered to use it).

I believe bad API is exactly what you're defending. Component API that exposes styling through attributes is bad. Global CSS is fundamental. I'll give you one example.

There is a popular organizer service Trello.com.
It's quite good but has some issues with UI. People released a lot of browser plugins which improve it's look and feel. I use one of them. This is something you're fundamentally can't do in desktops.

You can't even dream of turning off annoying icons in OSX or recoloring them unless Apple will be so kind to allow you to do it.

And all this is possible thankfully to the global CSS.

Another fundamental reason. Let's be fair, most of the 3-rd party components are broken to some degree. The are either mobile unfriendly or have some issues with older browsers.
You always need to "tweak" them until they work. Unless you're using only your own components.
But this is again "not-invented-in-microsoft" and all about enterprise.

This approach of "hardcoding" styles and letting them go "encapsulated" is so overconfident...
Approach "Provide only behavior, don't provide styles ever" should be critized separately.

In this way, I am certain that my component styles are really isolated (since all my selectors are nested inside the autogenerated/prefixed one), and people can also customize whatever they want (since I also add the static "date-picker" class. I see this as a very good mix. What's your opinion.

@radubrehar If you expose class names that is a classic solution with global CSS. You leave the chance to fix your errors to us. The question is how to achieve the same effect with local styling only?

I just can't see “styling” as something separate from “generating markup”. What's the point in being able to attach styles to a

if you can't, for example, wrap it into an extra
for some flexbox styling?

CSS has it's limitations, that's true, but it evolves. All that wrapping issues are mostly coming from the broken padding / margin calculations from the early ages of the web. From the broken box model before border-box. One div is enough to do an amazing bunch of things. See how Semantic UI has the same markup for horizontal, vertical and inline forms.

I mean... people created a great tool for us. CSS. It's still underestimated and unexplored in power.
Browser plugins are still just miserable shadows of what they can be. Of what they should be.

Don't use stock components that don't let you inject the rendering if you want to customize it later—it's a recipe for disaster.

You can have default styles now, thank gods to Webpack. This styles should be in a separate file.
Not imported by component, but exposed to you. Than you can: apply this global stylesheet, override it with your own rules. You also can parse this file and replace everything in it with something like PostCSS. The only drawback is a global CSS nature.

We're starting to mix two things here. There are TWO approaches I criticise:

Local styling (you-don't-need-styles)

This is Evil. I already put my arguments against.

Zero styling & Zero markip (don't-provide-css-and-html-just-inject-render)

This approach is ok for a lot of cases.
I don't want to blame it too much.

But still. Time is money. I want to use Matherial Design. I want to have both behavior and styles available from the start.

Because both are extremely hard to get right for all use-cases (which are growing). Demands are growing as well. And I also want to be able to tweak it and to be able to fix what is wrong about visual aspect. Because design is the most specific thing you have. You basically never repeat it.

If all that are "corner cases" then the world is built from them.
I prefer to accept Reality rather than struggle against it.

And I believe Future is about customization of everything.

Contributor

ivan-kleshnin commented Jun 5, 2015

@ArnoBuschmann I just took a walk yesterday and was striked by the thought about local styles.
I wanted to hold on with a new hot debates after my last one in Ramda repo 😄 but Andre mentioned local styles and I could not refrain myself.

Also relevant: https://github.com/petehunt/jsxstyle#what-about-re-theming-off-the-shelf-components
What about re-theming off-the-shelf components?
This is a bug in CSS, not a feature.

Yes. Pete Hunt is always aware how to make our lifes better. Even when against our wills.

Styling third-party component with custom global CSS is an escape hatch. Escape hatches are cool for solving the problem you described (you are given a black box with bad API and you are ordered to use it).

I believe bad API is exactly what you're defending. Component API that exposes styling through attributes is bad. Global CSS is fundamental. I'll give you one example.

There is a popular organizer service Trello.com.
It's quite good but has some issues with UI. People released a lot of browser plugins which improve it's look and feel. I use one of them. This is something you're fundamentally can't do in desktops.

You can't even dream of turning off annoying icons in OSX or recoloring them unless Apple will be so kind to allow you to do it.

And all this is possible thankfully to the global CSS.

Another fundamental reason. Let's be fair, most of the 3-rd party components are broken to some degree. The are either mobile unfriendly or have some issues with older browsers.
You always need to "tweak" them until they work. Unless you're using only your own components.
But this is again "not-invented-in-microsoft" and all about enterprise.

This approach of "hardcoding" styles and letting them go "encapsulated" is so overconfident...
Approach "Provide only behavior, don't provide styles ever" should be critized separately.

In this way, I am certain that my component styles are really isolated (since all my selectors are nested inside the autogenerated/prefixed one), and people can also customize whatever they want (since I also add the static "date-picker" class. I see this as a very good mix. What's your opinion.

@radubrehar If you expose class names that is a classic solution with global CSS. You leave the chance to fix your errors to us. The question is how to achieve the same effect with local styling only?

I just can't see “styling” as something separate from “generating markup”. What's the point in being able to attach styles to a

if you can't, for example, wrap it into an extra
for some flexbox styling?

CSS has it's limitations, that's true, but it evolves. All that wrapping issues are mostly coming from the broken padding / margin calculations from the early ages of the web. From the broken box model before border-box. One div is enough to do an amazing bunch of things. See how Semantic UI has the same markup for horizontal, vertical and inline forms.

I mean... people created a great tool for us. CSS. It's still underestimated and unexplored in power.
Browser plugins are still just miserable shadows of what they can be. Of what they should be.

Don't use stock components that don't let you inject the rendering if you want to customize it later—it's a recipe for disaster.

You can have default styles now, thank gods to Webpack. This styles should be in a separate file.
Not imported by component, but exposed to you. Than you can: apply this global stylesheet, override it with your own rules. You also can parse this file and replace everything in it with something like PostCSS. The only drawback is a global CSS nature.

We're starting to mix two things here. There are TWO approaches I criticise:

Local styling (you-don't-need-styles)

This is Evil. I already put my arguments against.

Zero styling & Zero markip (don't-provide-css-and-html-just-inject-render)

This approach is ok for a lot of cases.
I don't want to blame it too much.

But still. Time is money. I want to use Matherial Design. I want to have both behavior and styles available from the start.

Because both are extremely hard to get right for all use-cases (which are growing). Demands are growing as well. And I also want to be able to tweak it and to be able to fix what is wrong about visual aspect. Because design is the most specific thing you have. You basically never repeat it.

If all that are "corner cases" then the world is built from them.
I prefer to accept Reality rather than struggle against it.

And I believe Future is about customization of everything.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

It's up to you as component author to decide on the granularity of the style overriding that you think makes sense for your component.

Maybe the user will be satisfied with tweaking styles for particular DOM elements so you “tag” them and let user provide styles or classNames per “extension point”. Or maybe anticipate the user to want to wrap your <div>s or change them to <p>s, and you might provide renderButton as a prop to <PlayerControls>.

Or maybe you'll anticipate that the user wants to change a lot of stuff, so you export <Button>, as well as <Border>, <Touchable> that it's composed of, so they can be used independently.

It seems there are a thousand little ways I may want to style it

The whole point of having a consistent UI is not to have a thousand ways to style the same thing. Of course creating arbitrarily styled components is not very convenient. But generally you'll want to have a single <Button> in your project with props that make sense to you (e.g. with a rounded prop), and maybe you'll use a stock component with injectable styles to implement it inside. Throughout the project, however, you won't need to care about this anymore.

gaearon commented Jun 5, 2015

It's up to you as component author to decide on the granularity of the style overriding that you think makes sense for your component.

Maybe the user will be satisfied with tweaking styles for particular DOM elements so you “tag” them and let user provide styles or classNames per “extension point”. Or maybe anticipate the user to want to wrap your <div>s or change them to <p>s, and you might provide renderButton as a prop to <PlayerControls>.

Or maybe you'll anticipate that the user wants to change a lot of stuff, so you export <Button>, as well as <Border>, <Touchable> that it's composed of, so they can be used independently.

It seems there are a thousand little ways I may want to style it

The whole point of having a consistent UI is not to have a thousand ways to style the same thing. Of course creating arbitrarily styled components is not very convenient. But generally you'll want to have a single <Button> in your project with props that make sense to you (e.g. with a rounded prop), and maybe you'll use a stock component with injectable styles to implement it inside. Throughout the project, however, you won't need to care about this anymore.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

The whole point of having a consistent UI is not to have a thousand ways to style the same thing.

Exactly. If your site has a module size (line height) of 16px you do want to override every your component to look the same. Set correct font family. Repeat border radius. I have a good imagination and still can't imagine how to replicate all this through props.

This approach works only if the web is built from granular, perfect, production ready, polished kits of elements. Nothing like I see around. There are a bunch of matherial design implementations. Bunch of Bootstrap-like clones. One of them has buttons you need. Other – dropdowns.
All come with tiny visual differences and quirks you are required to handle. And you can.
Unless they hardcoded it with local styles.

Contributor

ivan-kleshnin commented Jun 5, 2015

The whole point of having a consistent UI is not to have a thousand ways to style the same thing.

Exactly. If your site has a module size (line height) of 16px you do want to override every your component to look the same. Set correct font family. Repeat border radius. I have a good imagination and still can't imagine how to replicate all this through props.

This approach works only if the web is built from granular, perfect, production ready, polished kits of elements. Nothing like I see around. There are a bunch of matherial design implementations. Bunch of Bootstrap-like clones. One of them has buttons you need. Other – dropdowns.
All come with tiny visual differences and quirks you are required to handle. And you can.
Unless they hardcoded it with local styles.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

Set correct font family.

I'm not idealistic. Do this in your “reset” stylesheet once for your whole website. (As well as setting the root font size.)

Repeat border radius.

All your components may require a common constants file that has this border radius defined. Whether they set this border radius directly or inject into stock component's styles, is implementation detail of your components.

gaearon commented Jun 5, 2015

Set correct font family.

I'm not idealistic. Do this in your “reset” stylesheet once for your whole website. (As well as setting the root font size.)

Repeat border radius.

All your components may require a common constants file that has this border radius defined. Whether they set this border radius directly or inject into stock component's styles, is implementation detail of your components.

@natew

This comment has been minimized.

Show comment
Hide comment
@natew

natew Jun 5, 2015

@gaearon seems like you are defending that there couldn't exist a better way to handle styles than there is in React? I think all @ivan-kleshnin (or at least I am) saying is there could be a better way and that would be something interesting to discuss.

There are some 18 CSS-in-JS libraries for React now. Plus hundreds of others all doing things inconsistently. It's an area React doesn't handle, which is totally fine (it makes it very flexible). But Cycle could handle it in some way, and I would argue that could dramatically improve how people share components.

natew commented Jun 5, 2015

@gaearon seems like you are defending that there couldn't exist a better way to handle styles than there is in React? I think all @ivan-kleshnin (or at least I am) saying is there could be a better way and that would be something interesting to discuss.

There are some 18 CSS-in-JS libraries for React now. Plus hundreds of others all doing things inconsistently. It's an area React doesn't handle, which is totally fine (it makes it very flexible). But Cycle could handle it in some way, and I would argue that could dramatically improve how people share components.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

These are three different approaches:

  • Compose your app out of a palette of encapsulated components you fully create yourself.
  • Compose your app out of stock components.
  • Compose your app out of stock components, but customize little things in their appearance.

The first approach works best for products with an established brand and identity. (Can you imagine Facebook or Airbnb using stock visual components?) React's encapsulation model works great here.

The second approach is as easy. If you build an internal dashboard, just use Bootstrap. No need for customization. Again, React's encapsulation model works great.

The third approach is “I want to have my cake and eat it too”. CSS and global styles kinda solve this problem, but in return you get all the drawbacks of wanting to both reuse and extremely customize something. You have harder versioning, things breaking other things for no apparent reason, complex overrides, etc, but get what you want in return. It's a tradeoff you choose.

All approaches are valid. There is no single “future”. Either you choose encapsulation (first two approaches), or you choose fragile flexibility (third approach). You can even mix them.

Of course, I prefer the first approach, but I can see why people might choose the second or the third one. It's just wrong IMO to say “style encapsulation doesn't work!” because it's up to you to choose your tradeoffs.

That's probably all I wanted to say in this thread.

gaearon commented Jun 5, 2015

These are three different approaches:

  • Compose your app out of a palette of encapsulated components you fully create yourself.
  • Compose your app out of stock components.
  • Compose your app out of stock components, but customize little things in their appearance.

The first approach works best for products with an established brand and identity. (Can you imagine Facebook or Airbnb using stock visual components?) React's encapsulation model works great here.

The second approach is as easy. If you build an internal dashboard, just use Bootstrap. No need for customization. Again, React's encapsulation model works great.

The third approach is “I want to have my cake and eat it too”. CSS and global styles kinda solve this problem, but in return you get all the drawbacks of wanting to both reuse and extremely customize something. You have harder versioning, things breaking other things for no apparent reason, complex overrides, etc, but get what you want in return. It's a tradeoff you choose.

All approaches are valid. There is no single “future”. Either you choose encapsulation (first two approaches), or you choose fragile flexibility (third approach). You can even mix them.

Of course, I prefer the first approach, but I can see why people might choose the second or the third one. It's just wrong IMO to say “style encapsulation doesn't work!” because it's up to you to choose your tradeoffs.

That's probably all I wanted to say in this thread.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

I'm not idealistic. Do this in your “reset” stylesheet once for your whole website. (As well as setting the root font size.)

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.
What about people proposing to make local scopes default in Webpack? They tend to think they can do everything with local styles. And this sounds weird to me.

All your components may require a common constants file that has this border radius defined. Whether they set this border radius directly or inject into stock component's styles, is implementation detail of your components.

Wait. A few posts ago you've said styles are excessive, props are enough. How to pass styles to some nested tag without some mad namespacing solutions, again?


I believe everything is about fallbacks. @gaearon is right that sometimes CSS is not enough and you do want to replace HTML. But should we base our conclusions on special cases or on common cases. I believe common ones are better. I have nothing against replacing "render" functions if it's required.
I'm only (and strongly) against limitations in the spirit of you don't need this.

Ideal solution (I mean all of this should be at the same time):

  1. Provide component with some HTML.
  2. Accept most common (numeric or string, not CSS-specific) settings through props
  3. Provide separate "default" stylesheet.
    Possible to parse and tweak. Possible to replace alltogether. Possible to override with CSS.
  4. Provide ways to replace rendering. Can be solved by monkey-patching.
  5. Provide ways to tweak logic. Use function input arguments
  6. Provide ways to replace logic. Can be solved by monkey-patching.

What's wrong?

Either you choose encapsulation (first two approaches), or you choose fragile flexibility (third approach).

You forgot to put "rigid" adjective before "encapsulation" noun.

Contributor

ivan-kleshnin commented Jun 5, 2015

I'm not idealistic. Do this in your “reset” stylesheet once for your whole website. (As well as setting the root font size.)

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.
What about people proposing to make local scopes default in Webpack? They tend to think they can do everything with local styles. And this sounds weird to me.

All your components may require a common constants file that has this border radius defined. Whether they set this border radius directly or inject into stock component's styles, is implementation detail of your components.

Wait. A few posts ago you've said styles are excessive, props are enough. How to pass styles to some nested tag without some mad namespacing solutions, again?


I believe everything is about fallbacks. @gaearon is right that sometimes CSS is not enough and you do want to replace HTML. But should we base our conclusions on special cases or on common cases. I believe common ones are better. I have nothing against replacing "render" functions if it's required.
I'm only (and strongly) against limitations in the spirit of you don't need this.

Ideal solution (I mean all of this should be at the same time):

  1. Provide component with some HTML.
  2. Accept most common (numeric or string, not CSS-specific) settings through props
  3. Provide separate "default" stylesheet.
    Possible to parse and tweak. Possible to replace alltogether. Possible to override with CSS.
  4. Provide ways to replace rendering. Can be solved by monkey-patching.
  5. Provide ways to tweak logic. Use function input arguments
  6. Provide ways to replace logic. Can be solved by monkey-patching.

What's wrong?

Either you choose encapsulation (first two approaches), or you choose fragile flexibility (third approach).

You forgot to put "rigid" adjective before "encapsulation" noun.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

seems like you are defending that there couldn't exist a better way to handle styles than there is in React?

No. I just don't see how this is a problem about styles, or about React. The way I see it, it is a problem about passing parameters in the functions, or letting functions read global variables instead for extra customization.

gaearon commented Jun 5, 2015

seems like you are defending that there couldn't exist a better way to handle styles than there is in React?

No. I just don't see how this is a problem about styles, or about React. The way I see it, it is a problem about passing parameters in the functions, or letting functions read global variables instead for extra customization.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

The way I see it, it is a problem about passing parameters in the functions, or letting functions read global variables instead for extra customization.

That's because you're mixing visual and behavior paradigms. Visual is more variable in the orders of magnitude. That is like passing 100 arguments to each function. I bet you will choose globals than.

Contributor

ivan-kleshnin commented Jun 5, 2015

The way I see it, it is a problem about passing parameters in the functions, or letting functions read global variables instead for extra customization.

That's because you're mixing visual and behavior paradigms. Visual is more variable in the orders of magnitude. That is like passing 100 arguments to each function. I bet you will choose globals than.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

Visual is more variable in the orders of magniture. That is like passing 100 arguments to each function.

I think working with a designer who found a way to create a few basic components with a few custom props that were used throughout the app really changed the way I see it. Customization may be great, but it's good to put a rigid facade in front of it so the rest of the app doesn't care.

gaearon commented Jun 5, 2015

Visual is more variable in the orders of magniture. That is like passing 100 arguments to each function.

I think working with a designer who found a way to create a few basic components with a few custom props that were used throughout the app really changed the way I see it. Customization may be great, but it's good to put a rigid facade in front of it so the rest of the app doesn't care.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.
What about people proposing to make local scopes default in Webpack? They tend to think they can do everything with local styles. And this sounds weird to me.

Default doesn't mean you can't override it. Default just means “exceptional cases look exceptional”. When you need a global style, do this explicitly. I think local-by-default is sane because it keeps everyone more aware of what is global, make globals visible in code reviews, so they are less dangerous and likely to bite.

Whatever's default, people will use the most, and in most cases (not the styling-stock-component case which isn't very common in a large app compared to styling internal components), the locals are better.

gaearon commented Jun 5, 2015

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.
What about people proposing to make local scopes default in Webpack? They tend to think they can do everything with local styles. And this sounds weird to me.

Default doesn't mean you can't override it. Default just means “exceptional cases look exceptional”. When you need a global style, do this explicitly. I think local-by-default is sane because it keeps everyone more aware of what is global, make globals visible in code reviews, so they are less dangerous and likely to bite.

Whatever's default, people will use the most, and in most cases (not the styling-stock-component case which isn't very common in a large app compared to styling internal components), the locals are better.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

By the way, I'm sorry if I sounded passive-aggressive in the earlier posts. I didn't intend to.

I only speak from the experience of building a product from the ground up together with a designer following this approach and, before that, having a lot of trouble with CSS breaking in unexpected places.

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here. I'm eager to learn more from @ivan-kleshnin and @natew and I agree they raise very valid points.

gaearon commented Jun 5, 2015

By the way, I'm sorry if I sounded passive-aggressive in the earlier posts. I didn't intend to.

I only speak from the experience of building a product from the ground up together with a designer following this approach and, before that, having a lot of trouble with CSS breaking in unexpected places.

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here. I'm eager to learn more from @ivan-kleshnin and @natew and I agree they raise very valid points.

@natew

This comment has been minimized.

Show comment
Hide comment
@natew

natew Jun 5, 2015

I would argue for option 4:

  • Rigid input for logic (props)
  • Flexible, but consistent, input for style (style prop, or something else)

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here.

I've only done it very recently through reapp, but speaking just from that experience I can see huge potential. I think the reason people don't use "stock" components (stock seems a bit derogatory, let's just say component), in a few cases at least, is because of inflexibility with style. Granted at Facebook's scale you probably don't mind re-writing everything and that's fine, but they may even want to share a complex component internally between teams (think data tables) and have a nice consistent way for teams to restyle it without using CSS.

Granted I've been working on some stuff in this area (though not quite exactly this part yet) so I've had a lot of time to think about it. Hopefully some stuff to show soon!

natew commented Jun 5, 2015

I would argue for option 4:

  • Rigid input for logic (props)
  • Flexible, but consistent, input for style (style prop, or something else)

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here.

I've only done it very recently through reapp, but speaking just from that experience I can see huge potential. I think the reason people don't use "stock" components (stock seems a bit derogatory, let's just say component), in a few cases at least, is because of inflexibility with style. Granted at Facebook's scale you probably don't mind re-writing everything and that's fine, but they may even want to share a complex component internally between teams (think data tables) and have a nice consistent way for teams to restyle it without using CSS.

Granted I've been working on some stuff in this area (though not quite exactly this part yet) so I've had a lot of time to think about it. Hopefully some stuff to show soon!

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

Compose your app out of encapsulated components you fully create yourself.
Compose your app out of stock components.
Compose your app out of stock components, but customize little things in their appearance.

The first approaches works best for products with an established brand and identity. (Can you imagine Facebook or Airbnb using some stock visual components?) React's encapsulation model works great here.

Yes. I agree here.

The second approach is as easy. If you build an internal dashboard, just use Bootstrap. No need for customization. Again, React's encapsulation model works great.

Disagree. Boostrap is not a dogma. It's common to restyle components to be more "Bootstrapy" than official version.

The third approach is “I want to have my cake and eat it too”. CSS and global styles kinda solve this problem, but in return you get all the drawbacks of wanting to both reuse and extremely customize something. You have harder versioning, things breaking other things for no apparent reason, complex overrides, etc, but get what you want in return. It's a tradeoff you choose.

There are a lot of bad things about CSS. I just see local styling as worse. Much worse.

Dear readers, please do not confuse local styling and local scopes. They are totally different.
Last one is about exposing class names which can still be hooked up in the global space in the emergency case. First one is about creating emergency cases 😉

Of course, I prefer the first approach, but I can see why people might choose the second or the third one. It's just wrong IMO to say “style encapsulation doesn't work!” because it's up to you to choose your tradeoffs.

Whatever's default, people will use the most, and in most cases (not the styling-stock-component case which isn't very common in a large app compared to styling internal components), the locals are better.

Of course it's better to be rich and healthy. If you're agree that global stylesheets are required to be kept, I'm with you. But then you're starting to undermine React's "best-practices"... The question of exact percentages of global and local CSS code is another matter. I don't have strong opinion here.

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here. I'm eager to learn more from @ivan-kleshnin and @natew and I agree they raise very valid points.

I also ask your forgiveness if I offended you somehow.
I have a great personal respect to you.

Contributor

ivan-kleshnin commented Jun 5, 2015

Compose your app out of encapsulated components you fully create yourself.
Compose your app out of stock components.
Compose your app out of stock components, but customize little things in their appearance.

The first approaches works best for products with an established brand and identity. (Can you imagine Facebook or Airbnb using some stock visual components?) React's encapsulation model works great here.

Yes. I agree here.

The second approach is as easy. If you build an internal dashboard, just use Bootstrap. No need for customization. Again, React's encapsulation model works great.

Disagree. Boostrap is not a dogma. It's common to restyle components to be more "Bootstrapy" than official version.

The third approach is “I want to have my cake and eat it too”. CSS and global styles kinda solve this problem, but in return you get all the drawbacks of wanting to both reuse and extremely customize something. You have harder versioning, things breaking other things for no apparent reason, complex overrides, etc, but get what you want in return. It's a tradeoff you choose.

There are a lot of bad things about CSS. I just see local styling as worse. Much worse.

Dear readers, please do not confuse local styling and local scopes. They are totally different.
Last one is about exposing class names which can still be hooked up in the global space in the emergency case. First one is about creating emergency cases 😉

Of course, I prefer the first approach, but I can see why people might choose the second or the third one. It's just wrong IMO to say “style encapsulation doesn't work!” because it's up to you to choose your tradeoffs.

Whatever's default, people will use the most, and in most cases (not the styling-stock-component case which isn't very common in a large app compared to styling internal components), the locals are better.

Of course it's better to be rich and healthy. If you're agree that global stylesheets are required to be kept, I'm with you. But then you're starting to undermine React's "best-practices"... The question of exact percentages of global and local CSS code is another matter. I don't have strong opinion here.

I don't have the experience of building websites out of stock components, or building UI toolkits. So forgive me if I'm showing ignorance here. I'm eager to learn more from @ivan-kleshnin and @natew and I agree they raise very valid points.

I also ask your forgiveness if I offended you somehow.
I have a great personal respect to you.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

@natew

I would argue for option 4

I meant all that may and should be available for a developer from an "ideal" toolkit.

Contributor

ivan-kleshnin commented Jun 5, 2015

@natew

I would argue for option 4

I meant all that may and should be available for a developer from an "ideal" toolkit.

@clessg

This comment has been minimized.

Show comment
Hide comment
@clessg

clessg Jun 5, 2015

Local/inline styles aren't much different from well-established and accepted CSS architectures such as BEM. There's a reason knowledge of CSS architectures is often a job requirement: they prevent the problems caused by global CSS.

Does this mean you should avoid global CSS all the time? Of course not. But I feel like you're fighting a strawman here. I've never heard anybody suggest we completely get rid of global CSS. But yes, global CSS should be avoided whenever possible in your application.

I think style encapsulation is useful mostly in the context of your own applications. If you're writing a UI framework or a stock component that provides visuals, then maybe not. I don't know for sure. But I doubt it has to be that way.

clessg commented Jun 5, 2015

Local/inline styles aren't much different from well-established and accepted CSS architectures such as BEM. There's a reason knowledge of CSS architectures is often a job requirement: they prevent the problems caused by global CSS.

Does this mean you should avoid global CSS all the time? Of course not. But I feel like you're fighting a strawman here. I've never heard anybody suggest we completely get rid of global CSS. But yes, global CSS should be avoided whenever possible in your application.

I think style encapsulation is useful mostly in the context of your own applications. If you're writing a UI framework or a stock component that provides visuals, then maybe not. I don't know for sure. But I doubt it has to be that way.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 5, 2015

If this customization is not enough, why do you need to use that particular <Button> at all? Clearly it isn't what you wanted..

My vote goes to making the process of re-designing something easier. That is to say, if I don't like the styling of something I've grabbed off the shelf - I should in fact not grab that thing off the shelf.

If the process of building my own <Button> is made (infinitely) easier by locally scoped styling (it is), then this approach is better for me (disclaimer: I'm a designer).

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.

From the Body tag, it's just boxes all the way down... A global style is simply local to the top level of your app, no? So if you need to make something global, write it there. If you need to make something re-usable, then it's already a component - re-use the component, not the style (aka css tags).

If the component is sort of like another component but kind of not really and customising it is cumbersome through props ... it's probably a new component.

If this customization is not enough, why do you need to use that particular <Button> at all? Clearly it isn't what you wanted..

My vote goes to making the process of re-designing something easier. That is to say, if I don't like the styling of something I've grabbed off the shelf - I should in fact not grab that thing off the shelf.

If the process of building my own <Button> is made (infinitely) easier by locally scoped styling (it is), then this approach is better for me (disclaimer: I'm a designer).

Ok, that's good. But what about people saying "forgot about global CSS"? I have already meet them.

From the Body tag, it's just boxes all the way down... A global style is simply local to the top level of your app, no? So if you need to make something global, write it there. If you need to make something re-usable, then it's already a component - re-use the component, not the style (aka css tags).

If the component is sort of like another component but kind of not really and customising it is cumbersome through props ... it's probably a new component.

@leoasis

This comment has been minimized.

Show comment
Hide comment
@leoasis

leoasis Jun 5, 2015

Within all this conversation, seems like we agree that all approaches should exist, that have their best use in different contexts (own components vs third party components). I'm on the fence of @gaearon here saying that the majority of your styling should be in your leaf-most components, and they should just expose higher level props to tweak the modes it can be styled. If you then need to style third party stuff, either pick the ones that provide you a way to do that properly, or fall back to styling by selecting their internals with css selectors.

Having said that, and coming back to the original discussion about the interactions, I also think it could be improved in Cycle following, as @staltz mentioned, a parallel between this and local styling.

I guess I agree that events should not be handled by the views, but I also think that the interactions should not be concerned about where that interaction element appears inside the rendered component. Just like with styling, where a good practice is to define the local styles outside the components in a plain object that defines a high level name, and the value is another object with the actual styles, like this:

var styles = {
  container: {
    // style properties for container
  },
  submitButton: {
    // style properties for submitButton
  },
  lead: {
    // style properties for lead
  }
}

And then the component is responsible for placing those styles in the respective elements. So here the component is responsible for knowing where the styles should be placed, not how (that is the responsibility for the styles object, by defining which style props each reference have).

The same way with interactions, I think the component should be responsible for exposing the elements that you can interact with, with a high level name, so that the interactions can refer to them and specify how we'll interact with them. So that's why I think providing a selector is similar to having styles like div p .class, instead of just local references.

I think it should just be a high level way to refer to it, without exposing a way to specify where that element is.

leoasis commented Jun 5, 2015

Within all this conversation, seems like we agree that all approaches should exist, that have their best use in different contexts (own components vs third party components). I'm on the fence of @gaearon here saying that the majority of your styling should be in your leaf-most components, and they should just expose higher level props to tweak the modes it can be styled. If you then need to style third party stuff, either pick the ones that provide you a way to do that properly, or fall back to styling by selecting their internals with css selectors.

Having said that, and coming back to the original discussion about the interactions, I also think it could be improved in Cycle following, as @staltz mentioned, a parallel between this and local styling.

I guess I agree that events should not be handled by the views, but I also think that the interactions should not be concerned about where that interaction element appears inside the rendered component. Just like with styling, where a good practice is to define the local styles outside the components in a plain object that defines a high level name, and the value is another object with the actual styles, like this:

var styles = {
  container: {
    // style properties for container
  },
  submitButton: {
    // style properties for submitButton
  },
  lead: {
    // style properties for lead
  }
}

And then the component is responsible for placing those styles in the respective elements. So here the component is responsible for knowing where the styles should be placed, not how (that is the responsibility for the styles object, by defining which style props each reference have).

The same way with interactions, I think the component should be responsible for exposing the elements that you can interact with, with a high level name, so that the interactions can refer to them and specify how we'll interact with them. So that's why I think providing a selector is similar to having styles like div p .class, instead of just local references.

I think it should just be a high level way to refer to it, without exposing a way to specify where that element is.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 5, 2015

Contributor

I think style encapsulation is useful mostly in the context of your own applications. If you're writing a UI framework or a stock component that provides visuals, then maybe not. I don't know for sure. But I doubt it has to be that way.

Very important remark. If you make an app you're free to do whatever you want.
I'm just afraid of Facebook practice to disguise their app cases as common cases.
They never detail it's about apps. They never detail it's about enterprise. Strange, right?
And their Relay library is going to enforce this pattern once again. App cases in disguise.

That is to say, if I don't like the styling of something I've grabbed off the shelf - I should in fact not grab that thing off the shelf.

Idealistic approach. It works well... if you're your own boss. If some library suits your requirements about behavior and does not suit about visuals are you going to avoid it just for the matter of principle?!

Within all this conversation, seems like we agree that all approaches should exist, that have their best use in different contexts (own components vs third party components). I'm on the fence of @gaearon here saying that the majority of your styling should be in your leaf-most components, and they should just expose higher level props to tweak the modes it can be styled. If you then need to style third party stuff, either pick the ones that provide you a way to do that properly, or fall back to styling by selecting their internals with css selectors.

Kinda like that. But the difference is that I'm not going to expose styling attributes at all.
You have CSS for that. My API will be clean.

Contributor

ivan-kleshnin commented Jun 5, 2015

I think style encapsulation is useful mostly in the context of your own applications. If you're writing a UI framework or a stock component that provides visuals, then maybe not. I don't know for sure. But I doubt it has to be that way.

Very important remark. If you make an app you're free to do whatever you want.
I'm just afraid of Facebook practice to disguise their app cases as common cases.
They never detail it's about apps. They never detail it's about enterprise. Strange, right?
And their Relay library is going to enforce this pattern once again. App cases in disguise.

That is to say, if I don't like the styling of something I've grabbed off the shelf - I should in fact not grab that thing off the shelf.

Idealistic approach. It works well... if you're your own boss. If some library suits your requirements about behavior and does not suit about visuals are you going to avoid it just for the matter of principle?!

Within all this conversation, seems like we agree that all approaches should exist, that have their best use in different contexts (own components vs third party components). I'm on the fence of @gaearon here saying that the majority of your styling should be in your leaf-most components, and they should just expose higher level props to tweak the modes it can be styled. If you then need to style third party stuff, either pick the ones that provide you a way to do that properly, or fall back to styling by selecting their internals with css selectors.

Kinda like that. But the difference is that I'm not going to expose styling attributes at all.
You have CSS for that. My API will be clean.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

The same way with interactions, I think the component should be responsible for exposing the elements that you can interact with, with a high level name, so that the interactions can refer to them and specify how we'll interact with them. So that's why I think providing a selector is similar to having styles like div p .class, instead of just local references.

Yes, I totally agree here. I want to see this (along with non-global components) in Cycle. It sounds much more reasonable to me than the CSS selector thing.

gaearon commented Jun 5, 2015

The same way with interactions, I think the component should be responsible for exposing the elements that you can interact with, with a high level name, so that the interactions can refer to them and specify how we'll interact with them. So that's why I think providing a selector is similar to having styles like div p .class, instead of just local references.

Yes, I totally agree here. I want to see this (along with non-global components) in Cycle. It sounds much more reasonable to me than the CSS selector thing.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 5, 2015

They never detail it's about apps. They never detail it's about enterprise. Strange, right?

Come on :-). Obviously the stuff Facebook releases is proven to work good in products like Facebook.

gaearon commented Jun 5, 2015

They never detail it's about apps. They never detail it's about enterprise. Strange, right?

Come on :-). Obviously the stuff Facebook releases is proven to work good in products like Facebook.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 6, 2015

Contributor

Why? Can you provide a code example?

By pure logic it's people who think it's possible should provide an example.
I already asked how to style something complex like video player and got 3 types of answers:

  1. You don't need this
  2. You should create it from scratch
  3. You should use it as is or choose another library

So I conclude noone can do it without stylesheets.

Contributor

ivan-kleshnin commented Jun 6, 2015

Why? Can you provide a code example?

By pure logic it's people who think it's possible should provide an example.
I already asked how to style something complex like video player and got 3 types of answers:

  1. You don't need this
  2. You should create it from scratch
  3. You should use it as is or choose another library

So I conclude noone can do it without stylesheets.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 6, 2015

I see a lot of place for global CSS:

I undestand the benefits of being able to do 2 & 3 - I don’t think local style really prevents any of that. At the end of the day all you’re doing with those third party sites is stealing their content and styling it yourself. If anything local style would assist that because it would be clearer what any given class was being applied to. I would also re-iterate that the general site / app reset / normalisers are just local style to the top level of your html tree.

With library component restyling, however, I cannot see how allowing global access to the component classes is useful. To allow style change - just expose the entire style to a level up.

This way, you’re still encapsulating a local concept of style when patching it - but it’s being driven by the wrapping context. The wrapper becomes the new local context.

Here's an example:

https://gist.github.com/haustraliaer/85aced44471109b3db09

I see a lot of place for global CSS:

I undestand the benefits of being able to do 2 & 3 - I don’t think local style really prevents any of that. At the end of the day all you’re doing with those third party sites is stealing their content and styling it yourself. If anything local style would assist that because it would be clearer what any given class was being applied to. I would also re-iterate that the general site / app reset / normalisers are just local style to the top level of your html tree.

With library component restyling, however, I cannot see how allowing global access to the component classes is useful. To allow style change - just expose the entire style to a level up.

This way, you’re still encapsulating a local concept of style when patching it - but it’s being driven by the wrapping context. The wrapper becomes the new local context.

Here's an example:

https://gist.github.com/haustraliaer/85aced44471109b3db09

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 6, 2015

Member

With library component restyling, however, I cannot see how allowing global access to the component classes is useful. To allow style change - just expose the entire style to a level up.

I agree.

My position is simple – you can't style something complex through props.

Yes you can because of the above. Good components-as-libraries will expose all relevant styling attributes as props.

Member

staltz commented Jun 6, 2015

With library component restyling, however, I cannot see how allowing global access to the component classes is useful. To allow style change - just expose the entire style to a level up.

I agree.

My position is simple – you can't style something complex through props.

Yes you can because of the above. Good components-as-libraries will expose all relevant styling attributes as props.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 6, 2015

I already asked how to style something complex like video player and got 3 types of answers:

Here's a perfect example of a fully customizable player:

https://github.com/soundblogs/react-soundplayer

Granted, it's a sound player, but everything is there: a set of “dumb” components, a managing component, and you can replace any parts you deem necessary.

gaearon commented Jun 6, 2015

I already asked how to style something complex like video player and got 3 types of answers:

Here's a perfect example of a fully customizable player:

https://github.com/soundblogs/react-soundplayer

Granted, it's a sound player, but everything is there: a set of “dumb” components, a managing component, and you can replace any parts you deem necessary.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 6, 2015

I honestly envision that once I migrate my build workflow over to a stable enough version of postcss... I'll be using global styles about as much as I use #ids (never) and actual selectors to style things (a reset for the browser styles).

Of course all of this requires quite a lot of boilerplate and knowledge to get going, but I don't think that is a justification for it being a worse way of doing things - especially when the benefits are highly evident to me as the developer.

Facebook team do it wrong spreading FUD and trying to enforce Web to be like React Native instead of the opposite.

The benefit of the web isn't it's "hackability", most people couldn't care less about adjusting stylesheets for the things they use. Facebook are pushing what they do because in their experience it's a better way to build things. And I don't think the scale of their team is relevant - it simply means they've got more people doing more things to figure this stuff out.

I've worked mostly in a 1-2 person team my whole career, and I can definitely see how their approach helps me do things faster and with far more confidence.

I honestly envision that once I migrate my build workflow over to a stable enough version of postcss... I'll be using global styles about as much as I use #ids (never) and actual selectors to style things (a reset for the browser styles).

Of course all of this requires quite a lot of boilerplate and knowledge to get going, but I don't think that is a justification for it being a worse way of doing things - especially when the benefits are highly evident to me as the developer.

Facebook team do it wrong spreading FUD and trying to enforce Web to be like React Native instead of the opposite.

The benefit of the web isn't it's "hackability", most people couldn't care less about adjusting stylesheets for the things they use. Facebook are pushing what they do because in their experience it's a better way to build things. And I don't think the scale of their team is relevant - it simply means they've got more people doing more things to figure this stuff out.

I've worked mostly in a 1-2 person team my whole career, and I can definitely see how their approach helps me do things faster and with far more confidence.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 6, 2015

Member

I can see the benefit of hackability, but to me it's secondary. (I still think these approaches are not making hacking impossible, just less friendly to hack)
The priority benefit is: getting things done quickly while not sacrificing maintainability in the long run. Automatic state management (Rx) is about getting things done quickly. Readability, elegance, simplicity, sliceability are about keeping maintainability in the long run.

Member

staltz commented Jun 6, 2015

I can see the benefit of hackability, but to me it's secondary. (I still think these approaches are not making hacking impossible, just less friendly to hack)
The priority benefit is: getting things done quickly while not sacrificing maintainability in the long run. Automatic state management (Rx) is about getting things done quickly. Readability, elegance, simplicity, sliceability are about keeping maintainability in the long run.

@RnbWd

This comment has been minimized.

Show comment
Hide comment
@RnbWd

RnbWd Jun 7, 2015

Damn, this is a long discussion thread 😔

I've been contemplating this topic for over a year now - it all started with web components, not React. However, React developed the best implementation of web components (IMO) and should be considered the de facto standard of how to build this abstraction.

React is built upon functional programming idioms (influenced by Rich Hickey?) and JSX code transformations. JS style objects are a much simpler abstraction for encapsulating styles compared with Polymer's API. However, the cost of adding additional libraries to React to handle all the edge cases of styling (mobile, etc.) seems too high compared to just using CSS.

My intuition led me to explore postcss as a potential candidate for code transformations ala JSX that can traverse between object styles and CSS - either converting CSS to inline styles or inline styles to global CSS. The goal is to reduce boilerplate associated with writing custom inline styles and put logic (like autoprefixer) as a pre-compilation step to prevent the need for unnecessary style logic in the JS runtime environment, and also reuse existing CSS libraries inside of inline styles so that we can leverage the CSS ecosystem without polluting the global environment.

Interesting discussion - doesn't look like an ideal solution exists yet. Maybe soon ✌️

RnbWd commented Jun 7, 2015

Damn, this is a long discussion thread 😔

I've been contemplating this topic for over a year now - it all started with web components, not React. However, React developed the best implementation of web components (IMO) and should be considered the de facto standard of how to build this abstraction.

React is built upon functional programming idioms (influenced by Rich Hickey?) and JSX code transformations. JS style objects are a much simpler abstraction for encapsulating styles compared with Polymer's API. However, the cost of adding additional libraries to React to handle all the edge cases of styling (mobile, etc.) seems too high compared to just using CSS.

My intuition led me to explore postcss as a potential candidate for code transformations ala JSX that can traverse between object styles and CSS - either converting CSS to inline styles or inline styles to global CSS. The goal is to reduce boilerplate associated with writing custom inline styles and put logic (like autoprefixer) as a pre-compilation step to prevent the need for unnecessary style logic in the JS runtime environment, and also reuse existing CSS libraries inside of inline styles so that we can leverage the CSS ecosystem without polluting the global environment.

Interesting discussion - doesn't look like an ideal solution exists yet. Maybe soon ✌️

@peterjoel

This comment has been minimized.

Show comment
Hide comment
@peterjoel

peterjoel Jun 16, 2015

@staltz:

There is a reason why events are not handled in the "view". View should only be concerned with rendering, i.e. how things look. Event handling is how it works.

I don't buy this argument.

Ideally the view should be able to operate only on component abstractions, which hide the DOM implementation. But using selectors to receive events means both a dependency on the underlying DOM structure and shifting that knowledge outside of the view.

On a more practical level, this method means that most React components do not work. Any events or callbacks in a React component become unavailable to business logic.

Having a view understand its own high level structure and map high level events into intentions just makes sense. If it breaks some convention or best practice, I still can't see the downside and I would question the applicability of the convention in this case.

What if user input is not related to your view at all? When you consider voice commands, then it becomes clear that depending on DOM selectors breaks the desired abstraction. Handling events in the view, and mapping them to intentions, preserves the abstraction in the place where you actually want it.

(See pH200/cycle-react#8)

@staltz:

There is a reason why events are not handled in the "view". View should only be concerned with rendering, i.e. how things look. Event handling is how it works.

I don't buy this argument.

Ideally the view should be able to operate only on component abstractions, which hide the DOM implementation. But using selectors to receive events means both a dependency on the underlying DOM structure and shifting that knowledge outside of the view.

On a more practical level, this method means that most React components do not work. Any events or callbacks in a React component become unavailable to business logic.

Having a view understand its own high level structure and map high level events into intentions just makes sense. If it breaks some convention or best practice, I still can't see the downside and I would question the applicability of the convention in this case.

What if user input is not related to your view at all? When you consider voice commands, then it becomes clear that depending on DOM selectors breaks the desired abstraction. Handling events in the view, and mapping them to intentions, preserves the abstraction in the place where you actually want it.

(See pH200/cycle-react#8)

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 16, 2015

Member

Ideally the view should be able to operate only on component abstractions, which hide the DOM implementation.

Your idea of View includes rendering + events. My idea of View doesn't, it is just rendering and nothing else. If you look at the original idea in MVC from Smalltalk, View makes sense as ONLY the translation from digital information to "user language". Check this https://youtu.be/1zj7M1LnJV4?t=1092 Intent does the opposite translation. Your idea of View does both. Because the user is bridged by the DOM, we need to interface with the DOM, not hide it. View translates to DOM, and Intent translates from the DOM. That is where the dependency with the DOM comes from, but there isn't any state encoding and no state reads done from the DOM.

But using selectors to receive events means both a dependency on the underlying DOM structure

What is the real problem with this on a practical level? Me and Ryan Florence discussed this here and at the end it is just a matter of taste and convention.

On a more practical level, this method means that most React components do not work. Any events or callbacks in a React component become unavailable to business logic.

Cycle is not React and Cycle doesn't need to support React-like workflow. Event handling callbacks are a mechanism that "close the loop" with regard to user interface mechanics, and would undermine the need to have Cycle.js in the first place. The whole point is to model the user as a function and we lose that by doing event handling callbacks (even if it is of the form onClick={subject.onNext()}).

Having a view understand its own high level structure and map high level events into intentions just makes sense.

Makes sense to you. As I said, I understand View as the translation function from state to screen pixels, and Intent is the translation from peripheral devices to (new) state. To me, Views handling events makes no sense.

What if user input is not related to your view at all? When you consider voice commands, then it becomes clear that depending on DOM selectors breaks the desired abstraction.

This case is even better to show how Cycle.js is a good abstraction. Voice commands would be Intents, translated from some driver (imagine here WebAudioDriver instead of DOMDriver). No dependency on DOM elements whatsoever.

I am guessing you haven't watched this: https://youtu.be/1zj7M1LnJV4 it explains the "why" of everything in Cycle.

Member

staltz commented Jun 16, 2015

Ideally the view should be able to operate only on component abstractions, which hide the DOM implementation.

Your idea of View includes rendering + events. My idea of View doesn't, it is just rendering and nothing else. If you look at the original idea in MVC from Smalltalk, View makes sense as ONLY the translation from digital information to "user language". Check this https://youtu.be/1zj7M1LnJV4?t=1092 Intent does the opposite translation. Your idea of View does both. Because the user is bridged by the DOM, we need to interface with the DOM, not hide it. View translates to DOM, and Intent translates from the DOM. That is where the dependency with the DOM comes from, but there isn't any state encoding and no state reads done from the DOM.

But using selectors to receive events means both a dependency on the underlying DOM structure

What is the real problem with this on a practical level? Me and Ryan Florence discussed this here and at the end it is just a matter of taste and convention.

On a more practical level, this method means that most React components do not work. Any events or callbacks in a React component become unavailable to business logic.

Cycle is not React and Cycle doesn't need to support React-like workflow. Event handling callbacks are a mechanism that "close the loop" with regard to user interface mechanics, and would undermine the need to have Cycle.js in the first place. The whole point is to model the user as a function and we lose that by doing event handling callbacks (even if it is of the form onClick={subject.onNext()}).

Having a view understand its own high level structure and map high level events into intentions just makes sense.

Makes sense to you. As I said, I understand View as the translation function from state to screen pixels, and Intent is the translation from peripheral devices to (new) state. To me, Views handling events makes no sense.

What if user input is not related to your view at all? When you consider voice commands, then it becomes clear that depending on DOM selectors breaks the desired abstraction.

This case is even better to show how Cycle.js is a good abstraction. Voice commands would be Intents, translated from some driver (imagine here WebAudioDriver instead of DOMDriver). No dependency on DOM elements whatsoever.

I am guessing you haven't watched this: https://youtu.be/1zj7M1LnJV4 it explains the "why" of everything in Cycle.

@peterjoel

This comment has been minimized.

Show comment
Hide comment
@peterjoel

peterjoel Jun 16, 2015

Thanks for responding.

I understand View as the translation function from state to screen pixels

I don't think this is reasonable in the context of web technologies. We operate on the DOM, not on pixels. The DOM has interactive behaviour intrinsically tied to its elements, whereas pixels do not. Working with existing component structures (e.g. React elements) is a reality for anyone who wants to make something based on real life requirements, as opposed to toy examples.

If I use a 3rd party Grid component, and I need to respond to a cell selection, I want to use a high level event, which is part of the component's API. I cannot imagine trying to figure out a selector to reliably identify cells, and then somehow map click events back to the data they represent. Even if you can pull that off, bug-free, good luck maintaining it one year from now.

I am guessing you haven't watched this: https://youtu.be/1zj7M1LnJV4 it explains the "why" of everything in Cycle.

I haven't. I will watch it before making any more comments.

Thanks for responding.

I understand View as the translation function from state to screen pixels

I don't think this is reasonable in the context of web technologies. We operate on the DOM, not on pixels. The DOM has interactive behaviour intrinsically tied to its elements, whereas pixels do not. Working with existing component structures (e.g. React elements) is a reality for anyone who wants to make something based on real life requirements, as opposed to toy examples.

If I use a 3rd party Grid component, and I need to respond to a cell selection, I want to use a high level event, which is part of the component's API. I cannot imagine trying to figure out a selector to reliably identify cells, and then somehow map click events back to the data they represent. Even if you can pull that off, bug-free, good luck maintaining it one year from now.

I am guessing you haven't watched this: https://youtu.be/1zj7M1LnJV4 it explains the "why" of everything in Cycle.

I haven't. I will watch it before making any more comments.

@pH200

This comment has been minimized.

Show comment
Hide comment
@pH200

pH200 Jun 16, 2015

Contributor

If I use a 3rd party Grid component, and I need to respond to a cell selection, I want to use a high level event, which is part of the component's API. I cannot imagine trying to figure out a selector to reliably identify cells, and then somehow map click events back to the data they represent. Even if you can pull that off, bug-free, good luck maintaining it one year from now.

Well, the documentation isn't clear on how to work with events. Let's say you have a grid component like this:

<Grid onCellSelected={...} />

In the latest Cycle.js (not Cycle-React), you will subscribe events like this:

function app({dom}) {
  // '.jsevent-' is just a convention for the key of event mapping
  var cellSelectedObservable$ = dom.get('.jsevent-grid', 'onCellSelected');
  // ...
  return {
    dom: stateObservable$.map(state => <Grid className="jsevent-grid" />)
  };
}

So, you can use the high level event from the component, and it doesn't break as long as you don't change the element's className. Many people have questioned about the usage of className. And Staltz has explained why he took className for events.

Contributor

pH200 commented Jun 16, 2015

If I use a 3rd party Grid component, and I need to respond to a cell selection, I want to use a high level event, which is part of the component's API. I cannot imagine trying to figure out a selector to reliably identify cells, and then somehow map click events back to the data they represent. Even if you can pull that off, bug-free, good luck maintaining it one year from now.

Well, the documentation isn't clear on how to work with events. Let's say you have a grid component like this:

<Grid onCellSelected={...} />

In the latest Cycle.js (not Cycle-React), you will subscribe events like this:

function app({dom}) {
  // '.jsevent-' is just a convention for the key of event mapping
  var cellSelectedObservable$ = dom.get('.jsevent-grid', 'onCellSelected');
  // ...
  return {
    dom: stateObservable$.map(state => <Grid className="jsevent-grid" />)
  };
}

So, you can use the high level event from the component, and it doesn't break as long as you don't change the element's className. Many people have questioned about the usage of className. And Staltz has explained why he took className for events.

@jessehattabaugh

This comment has been minimized.

Show comment
Hide comment
@jessehattabaugh

jessehattabaugh Jun 16, 2015

I share @peterjoel's concerns over separating intent definition from the view. My complaint is mainly that it isn't ergonomic for the developer. Declaring a button in one place, and what happens when it's pressed in another feels disjointed.

I know you want to treat the user as a function, but users don't take arguments or have return values. They just generate anonymous UI events. We have to label these events and give them context in order to affect the user's intent. Like it or not, web developers have done this inline with the declaration of UI since 1995. That may violate the principles that you set out to build Cycle with, but I'm not sure it really violates the principle of reactivity.

If a View module outputs DOM with event listeners attached and those event listeners interactively change the Model; that's not reactive, but if all the event listeners do is trigger specific action events with context data then the Model can listen for those and react. I suppose you wouldn't want to couple the Model to specific DOM events, but if you think of DOM events like the Observables you'd otherwise be returning from the Intent layer, it's not that different architecturally. It just kinda cuts the User function out of the equation.

I share @peterjoel's concerns over separating intent definition from the view. My complaint is mainly that it isn't ergonomic for the developer. Declaring a button in one place, and what happens when it's pressed in another feels disjointed.

I know you want to treat the user as a function, but users don't take arguments or have return values. They just generate anonymous UI events. We have to label these events and give them context in order to affect the user's intent. Like it or not, web developers have done this inline with the declaration of UI since 1995. That may violate the principles that you set out to build Cycle with, but I'm not sure it really violates the principle of reactivity.

If a View module outputs DOM with event listeners attached and those event listeners interactively change the Model; that's not reactive, but if all the event listeners do is trigger specific action events with context data then the Model can listen for those and react. I suppose you wouldn't want to couple the Model to specific DOM events, but if you think of DOM events like the Observables you'd otherwise be returning from the Intent layer, it's not that different architecturally. It just kinda cuts the User function out of the equation.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 16, 2015

Member

I know you want to treat the user as a function, but users don't take arguments or have return values.

Yes they do and in my presentation I explicitly denotated those arguments. Input argument is an Observable of VTree, and return value is an Observable of DOM events (what you called "anonymous UI events").

We have to label these events and give them context in order to affect the user's intent.

The events are well labeled. It's a pair of selector and eventType. Instead of naming event channels, you just name the container element which emits that event, and you name the event itself. There isn't much difference other than taste/preference.

It just kinda cuts the User function out of the equation.

The User function is there no matter what. Cycle is a framework that acknowledges that instead of using a different abstraction.

Member

staltz commented Jun 16, 2015

I know you want to treat the user as a function, but users don't take arguments or have return values.

Yes they do and in my presentation I explicitly denotated those arguments. Input argument is an Observable of VTree, and return value is an Observable of DOM events (what you called "anonymous UI events").

We have to label these events and give them context in order to affect the user's intent.

The events are well labeled. It's a pair of selector and eventType. Instead of naming event channels, you just name the container element which emits that event, and you name the event itself. There isn't much difference other than taste/preference.

It just kinda cuts the User function out of the equation.

The User function is there no matter what. Cycle is a framework that acknowledges that instead of using a different abstraction.

@jessehattabaugh

This comment has been minimized.

Show comment
Hide comment
@jessehattabaugh

jessehattabaugh Jun 16, 2015

I still think that most developers are going to prefer to label the events in the place where they originate, and not after they occur. Especially entry level developers who are often the ones working on the View layer.

I still think that most developers are going to prefer to label the events in the place where they originate, and not after they occur. Especially entry level developers who are often the ones working on the View layer.

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 16, 2015

Member

most developers are going to prefer

I'm going to repeat my core argument I mentioned in this thread:

given that inline styles is a better solution for Virtual DOM approaches, we can use classNames (and/or ids) to give names to vtree elements, so that they can be observable on all kinds of interaction events without having to alter the vtree element's implementation. This follows the open-closed principle. If you need to change logic code to grab new kinds of events from the vtree element, you don't need to modify code in the vtree element. Because vtree element implementation should be concerned only with "how it looks", and because we want to follow the open-closed principle. Another problem with naming only specific events on the vtree element is that whenever you want to refactor/modify it, you do not know who is using those specific named events, or if they aren't used at all, hence you need to search throughout the code for all usages of those named events, and this is leakage of responsibility. Event handling responsibility should be separated. None if this is "I feel it is better".


Especially entry level developers who are often the ones working on the View layer.

Cycle.js already has a learning curve and that's RxJS. This isn't a framework that beginners will pick up easily. And that's the disadvantage of this framework. Other frameworks such as Ractive.js are focused on beginner-friendliness. RxJS is all about a mindset change. Once you overcome the paradigm shift, everything starts to make sense. And the selector-based intent events handling is one of these paradigm shifting challenges. The issue itself isn't hard or complex, it's just the mindset change which is hard because people are used to thinking in a certain way. Cycle.js is already a paradigm shift, making this change won't remove that, but it will water down the purpose and goals of the framework.

Member

staltz commented Jun 16, 2015

most developers are going to prefer

I'm going to repeat my core argument I mentioned in this thread:

given that inline styles is a better solution for Virtual DOM approaches, we can use classNames (and/or ids) to give names to vtree elements, so that they can be observable on all kinds of interaction events without having to alter the vtree element's implementation. This follows the open-closed principle. If you need to change logic code to grab new kinds of events from the vtree element, you don't need to modify code in the vtree element. Because vtree element implementation should be concerned only with "how it looks", and because we want to follow the open-closed principle. Another problem with naming only specific events on the vtree element is that whenever you want to refactor/modify it, you do not know who is using those specific named events, or if they aren't used at all, hence you need to search throughout the code for all usages of those named events, and this is leakage of responsibility. Event handling responsibility should be separated. None if this is "I feel it is better".


Especially entry level developers who are often the ones working on the View layer.

Cycle.js already has a learning curve and that's RxJS. This isn't a framework that beginners will pick up easily. And that's the disadvantage of this framework. Other frameworks such as Ractive.js are focused on beginner-friendliness. RxJS is all about a mindset change. Once you overcome the paradigm shift, everything starts to make sense. And the selector-based intent events handling is one of these paradigm shifting challenges. The issue itself isn't hard or complex, it's just the mindset change which is hard because people are used to thinking in a certain way. Cycle.js is already a paradigm shift, making this change won't remove that, but it will water down the purpose and goals of the framework.

@jessehattabaugh

This comment has been minimized.

Show comment
Hide comment
@jessehattabaugh

jessehattabaugh Jun 16, 2015

I appreciate your idealism, seriously :-)

I appreciate your idealism, seriously :-)

@peterjoel

This comment has been minimized.

Show comment
Hide comment
@peterjoel

peterjoel Jun 17, 2015

I think discussing learning curves is a distraction. There is a shift happening towards FRP and functional style in general, so this will become less of a problem. The ideas aren't hard, they're just different from what people are used to. Let people make wrappers and adapters if they are concerned about that, but don't compromise the core ideas now.

I think discussing learning curves is a distraction. There is a shift happening towards FRP and functional style in general, so this will become less of a problem. The ideas aren't hard, they're just different from what people are used to. Let people make wrappers and adapters if they are concerned about that, but don't compromise the core ideas now.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 26, 2015

Contributor

I would also re-iterate that the general site / app reset / normalisers are just local style to the top level of your html tree.

There are rules like * { box-sizing: border-box } which you have to apply with * selector.
How would you classify them? 😉

Interesting discussion - doesn't look like an ideal solution exists yet. Maybe soon

The important problem, totally not solved at this moment, is how to pass variables between CSS layer and JS layer. A set of a component styles more often than not contains a derivative of a whole site styling. Border radius of component "panel" should repeat the common (global) border radius to give you an example.

Possible approaches are:

  1. Use only local styles and keep all style-related variables in JS. This is what Facebook team promotes. Not solves but "avoids" the problem. I believe this is impractical at the current stage of the web technologies where HTML is still an assembly point. As soon as you would be able to direct your browser to http://your-site.com/page.js and get the whole app running it may change. For now I see this is as an another subjective tradeoff where you give up old (familiar) problems and pick up new.
  2. Find a way to pull LESS / postCSS variables from the stylesheet file into JS to reuse them later in local styles. This is theoretically possible with bundlers like Webpack or task runners like Gulp but I'm not aware of any activity in this direction.
  3. Find a way to pull JS variables to the stylesheet file. This is theoretically possible with postCSS.
  4. Find a way to push JS variables into LESS / postCSS stylesheets. As it boils down to the host language (JS) module system, this approach seems impossible without "parameterized modules" concept. Which exist in only a few programming languages (e.g. Racket)...

Here's a perfect example of a fully customizable player:
https://github.com/soundblogs/react-soundplayer

This project uses "revealing components" pattern I described above. +1 for a real example of it.
What we see in the code is a mix of local styles, classes to hook up global stylesheets and... global stylesheets.

Components may be customizable through props if some argument should influence HTML + CSS and there are solid reasons against further revealing (splitting to subcomponents).
Nothing is wrong about it. But haven't you said that a general approach is to pass raw CSS styles (as objects) to and between components? I don't see here any sign of a raw "style passing".

P.S.
People who complain about globals in CSS should take a look at Unix terminal first. Everything is global there (probably an important reason why package naming in Java spirit org.clojure.your.package.name fails to become standard: you still need to come up with a memorizable "unique" name for CLI).

Same thing with NPM package name. It's global and it's an obvious candidate for "conventional" className prefix.

Contributor

ivan-kleshnin commented Jun 26, 2015

I would also re-iterate that the general site / app reset / normalisers are just local style to the top level of your html tree.

There are rules like * { box-sizing: border-box } which you have to apply with * selector.
How would you classify them? 😉

Interesting discussion - doesn't look like an ideal solution exists yet. Maybe soon

The important problem, totally not solved at this moment, is how to pass variables between CSS layer and JS layer. A set of a component styles more often than not contains a derivative of a whole site styling. Border radius of component "panel" should repeat the common (global) border radius to give you an example.

Possible approaches are:

  1. Use only local styles and keep all style-related variables in JS. This is what Facebook team promotes. Not solves but "avoids" the problem. I believe this is impractical at the current stage of the web technologies where HTML is still an assembly point. As soon as you would be able to direct your browser to http://your-site.com/page.js and get the whole app running it may change. For now I see this is as an another subjective tradeoff where you give up old (familiar) problems and pick up new.
  2. Find a way to pull LESS / postCSS variables from the stylesheet file into JS to reuse them later in local styles. This is theoretically possible with bundlers like Webpack or task runners like Gulp but I'm not aware of any activity in this direction.
  3. Find a way to pull JS variables to the stylesheet file. This is theoretically possible with postCSS.
  4. Find a way to push JS variables into LESS / postCSS stylesheets. As it boils down to the host language (JS) module system, this approach seems impossible without "parameterized modules" concept. Which exist in only a few programming languages (e.g. Racket)...

Here's a perfect example of a fully customizable player:
https://github.com/soundblogs/react-soundplayer

This project uses "revealing components" pattern I described above. +1 for a real example of it.
What we see in the code is a mix of local styles, classes to hook up global stylesheets and... global stylesheets.

Components may be customizable through props if some argument should influence HTML + CSS and there are solid reasons against further revealing (splitting to subcomponents).
Nothing is wrong about it. But haven't you said that a general approach is to pass raw CSS styles (as objects) to and between components? I don't see here any sign of a raw "style passing".

P.S.
People who complain about globals in CSS should take a look at Unix terminal first. Everything is global there (probably an important reason why package naming in Java spirit org.clojure.your.package.name fails to become standard: you still need to come up with a memorizable "unique" name for CLI).

Same thing with NPM package name. It's global and it's an obvious candidate for "conventional" className prefix.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 26, 2015

There are rules like * { box-sizing: border-box } which you have to apply with * selector.
How would you classify them?

Hah, I'd classify them as hacks - if everyone has to write * { anything } then it probably should be the default... But even still - using local style doesn't prevent you from using those features of css... You could still define a global class and assign it to a bunch of html elements.

But the main argument for local style is that more often than not this will come back to haunt you and should generally be considered bad practice.

There are rules like * { box-sizing: border-box } which you have to apply with * selector.
How would you classify them?

Hah, I'd classify them as hacks - if everyone has to write * { anything } then it probably should be the default... But even still - using local style doesn't prevent you from using those features of css... You could still define a global class and assign it to a bunch of html elements.

But the main argument for local style is that more often than not this will come back to haunt you and should generally be considered bad practice.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 26, 2015

Contributor

Hah, I'd classify them as hacks - if everyone has to write * { anything } then it probably should be the default...

If CSS is broken this is rather a fix...
I may ask it in other way: how would you classify h4 { font-size: 2em }?
It's totally required and it's totally can't be described in terms of "trees" and "components".

If you stylize every paragraph through local styles your designer becomes unable to make live experiments. He needs to make N changes to replace font family in the whole visible area of the screen. My designer needs only 1...

But even still - using local style doesn't prevent you from using those features of css...

How about Facebook team saying "global CSS is a bug"?
Do you agree they're wrong about this?

But the main argument for local style is that more often than not this will come back to haunt you and should generally be considered bad practice.

"Bad practice" is a bad term. Some parts of web app (or page) like text styling are naturally global and so are better described by global styles, and some parts like unique widgets are probably better described by local styles. The question is how to pass constants / variables from one layer to another.
And how not to confuse that global and local parts.

Contributor

ivan-kleshnin commented Jun 26, 2015

Hah, I'd classify them as hacks - if everyone has to write * { anything } then it probably should be the default...

If CSS is broken this is rather a fix...
I may ask it in other way: how would you classify h4 { font-size: 2em }?
It's totally required and it's totally can't be described in terms of "trees" and "components".

If you stylize every paragraph through local styles your designer becomes unable to make live experiments. He needs to make N changes to replace font family in the whole visible area of the screen. My designer needs only 1...

But even still - using local style doesn't prevent you from using those features of css...

How about Facebook team saying "global CSS is a bug"?
Do you agree they're wrong about this?

But the main argument for local style is that more often than not this will come back to haunt you and should generally be considered bad practice.

"Bad practice" is a bad term. Some parts of web app (or page) like text styling are naturally global and so are better described by global styles, and some parts like unique widgets are probably better described by local styles. The question is how to pass constants / variables from one layer to another.
And how not to confuse that global and local parts.

@hugobessaa

This comment has been minimized.

Show comment
Hide comment
@hugobessaa

hugobessaa Jun 26, 2015

how would you classify h4 { font-size: 2em }?

It can be a component. And often you don't want a "heading number 4", but a Subtitle, SectionHeading and so on.

It would even be better for your designer and your markup, as you would be free to use any h* with the semantics without having to take care not to break another places where that h* is used.

In most projects that helped me and the designers.

how would you classify h4 { font-size: 2em }?

It can be a component. And often you don't want a "heading number 4", but a Subtitle, SectionHeading and so on.

It would even be better for your designer and your markup, as you would be free to use any h* with the semantics without having to take care not to break another places where that h* is used.

In most projects that helped me and the designers.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 26, 2015

+1 @hugobessaa - once you think in components with your whole UI, local styling makes a lot more sense. Global css could be considered a bug because the cons of using it far outweigh the benefits.

+1 @hugobessaa - once you think in components with your whole UI, local styling makes a lot more sense. Global css could be considered a bug because the cons of using it far outweigh the benefits.

@hugobessaa

This comment has been minimized.

Show comment
Hide comment
@hugobessaa

hugobessaa Jun 27, 2015

@haustraliaer it can led to bugs. But as global states in JS apps, they can be useful at some point.

But surely is a beast waiting to bite you.

@haustraliaer it can led to bugs. But as global states in JS apps, they can be useful at some point.

But surely is a beast waiting to bite you.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 27, 2015

Contributor

It would even be better for your designer and your markup, as you would be free to use any h* with the semantics without having to take care not to break another places where that h* is used.

In my experience (and not only mine) the problem is exactly the opposite. The problem is that any long-developed site has 100+ shades of gray, 100+ variants of margins etc. And the question is how to unify them, how to reduce them to minimal set of global settings. Not how to pile one more variation of each.

And the funniest thing of all. This was precisely the Facebook problem. Read how Nicole Sullivan optimized their site along with Yahoo if you care.

once you think in components with your whole UI, local styling makes a lot more sense
Global CSS could be considered a bug because the cons of using it far outweigh the benefits.

"Once you think how God loves you, whole life makes a lot more sense..."
I see it's a matter of faith for a lot of people here. "And then Facebook said..."
So I'm helpless.

Contributor

ivan-kleshnin commented Jun 27, 2015

It would even be better for your designer and your markup, as you would be free to use any h* with the semantics without having to take care not to break another places where that h* is used.

In my experience (and not only mine) the problem is exactly the opposite. The problem is that any long-developed site has 100+ shades of gray, 100+ variants of margins etc. And the question is how to unify them, how to reduce them to minimal set of global settings. Not how to pile one more variation of each.

And the funniest thing of all. This was precisely the Facebook problem. Read how Nicole Sullivan optimized their site along with Yahoo if you care.

once you think in components with your whole UI, local styling makes a lot more sense
Global CSS could be considered a bug because the cons of using it far outweigh the benefits.

"Once you think how God loves you, whole life makes a lot more sense..."
I see it's a matter of faith for a lot of people here. "And then Facebook said..."
So I'm helpless.

@clessg

This comment has been minimized.

Show comment
Hide comment
@clessg

clessg Jun 27, 2015

"Once you think how God loves you, whole life makes a lot more sense..."
I see it's a matter of faith for a lot of people here. "And then Facebook said..."
So I'm helpless.

That's a very wrong assertion. I suggest it's a matter of experience. Professional developers have been doing their best for years to avoid the problems of global CSS - specificity wars, code bloat, indeterministic style resolution, non-debuggability, silent clashing of styles, dead code, etc. Local styles merely codify the best practices professionals were already using. These practices weren't created by Facebook and they weren't written in the Bible. They solve a real problem.

The experience of many is that this approach works. I can't imagine going back to global CSS and specificity wars, just like I can't imagine going back to two-way binding and templates.

clessg commented Jun 27, 2015

"Once you think how God loves you, whole life makes a lot more sense..."
I see it's a matter of faith for a lot of people here. "And then Facebook said..."
So I'm helpless.

That's a very wrong assertion. I suggest it's a matter of experience. Professional developers have been doing their best for years to avoid the problems of global CSS - specificity wars, code bloat, indeterministic style resolution, non-debuggability, silent clashing of styles, dead code, etc. Local styles merely codify the best practices professionals were already using. These practices weren't created by Facebook and they weren't written in the Bible. They solve a real problem.

The experience of many is that this approach works. I can't imagine going back to global CSS and specificity wars, just like I can't imagine going back to two-way binding and templates.

@hugobessaa

This comment has been minimized.

Show comment
Hide comment
@hugobessaa

hugobessaa Jun 27, 2015

Of course you should take care to not create 100+ shades of gray. There are a number of ways, different than global definitions, to share consistency. Variables are an example.

@ivan-kleshnin there is an infinite number of ways to solve different problems. Not every one has the same problems. On my blog I use global styles like your h4 example, and on other websites I use the one I said before.

As I think you said, there is many solutions. I'm with you when you say global CSS shouldn't be considered a bug. Global vars in JS are quite useful sometimes too.

Of course you should take care to not create 100+ shades of gray. There are a number of ways, different than global definitions, to share consistency. Variables are an example.

@ivan-kleshnin there is an infinite number of ways to solve different problems. Not every one has the same problems. On my blog I use global styles like your h4 example, and on other websites I use the one I said before.

As I think you said, there is many solutions. I'm with you when you say global CSS shouldn't be considered a bug. Global vars in JS are quite useful sometimes too.

@haustraliaer

This comment has been minimized.

Show comment
Hide comment
@haustraliaer

haustraliaer Jun 27, 2015

And when using a module system in JS - you can access the global vars fairly easily by specifying window object (in a browser).

Once you think how God loves you..

Gimme a break, we're talking about building websites not faith in some higher local power...

And when using a module system in JS - you can access the global vars fairly easily by specifying window object (in a browser).

Once you think how God loves you..

Gimme a break, we're talking about building websites not faith in some higher local power...

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 28, 2015

Contributor

@haustraliaer, ok I have this code to style a list of alerts

.index-alert {
  position: fixed;
  z-index: @zindex-modal;
  &.top-right {
    top: @line-height-computed / 2;
    right: @line-height-computed;
  }
  &.top-left {
    top: @line-height-computed / 2;
    left: @line-height-computed;
  }
  &.bottom-left {
    bottom: @line-height-computed / 2;
    left: @line-height-computed;
  }
  &.bottom-right {
    bottom: @line-height-computed / 2;
    right: @line-height-computed;
  }
  .item {
    position: relative;
    margin: @line-height-computed / 2;
  }
}

It can't be placed or passed to <AlertIndex/> component directly because it relies on LESS variables.

This variables are going from (or derive from) Bootstrap variables

@line-height-computed: floor((@font-size-base * @line-height-base)); 

and depend on global settings like font size or line height.

Now all mainstream frameworks we have being it Bootsrap or Foundation or SemanticUI are built by the same principle. They require a looong list of LESS or SASS variables to be defined.

How exactly do you propose to reorganize it with local styles?

Contributor

ivan-kleshnin commented Jun 28, 2015

@haustraliaer, ok I have this code to style a list of alerts

.index-alert {
  position: fixed;
  z-index: @zindex-modal;
  &.top-right {
    top: @line-height-computed / 2;
    right: @line-height-computed;
  }
  &.top-left {
    top: @line-height-computed / 2;
    left: @line-height-computed;
  }
  &.bottom-left {
    bottom: @line-height-computed / 2;
    left: @line-height-computed;
  }
  &.bottom-right {
    bottom: @line-height-computed / 2;
    right: @line-height-computed;
  }
  .item {
    position: relative;
    margin: @line-height-computed / 2;
  }
}

It can't be placed or passed to <AlertIndex/> component directly because it relies on LESS variables.

This variables are going from (or derive from) Bootstrap variables

@line-height-computed: floor((@font-size-base * @line-height-base)); 

and depend on global settings like font size or line height.

Now all mainstream frameworks we have being it Bootsrap or Foundation or SemanticUI are built by the same principle. They require a looong list of LESS or SASS variables to be defined.

How exactly do you propose to reorganize it with local styles?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 28, 2015

Member

@ivan-kleshnin take a look at some "global" styles and variables in JavaScript that I have in RxMarbles: https://github.com/staltz/rxmarbles/tree/master/src/styles

Member

staltz commented Jun 28, 2015

@ivan-kleshnin take a look at some "global" styles and variables in JavaScript that I have in RxMarbles: https://github.com/staltz/rxmarbles/tree/master/src/styles

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 28, 2015

Contributor

@staltz this is the "built everything from scratch" kind of solution. Pretty ok when you have no forms and limited number of pages and widgets. Is there any way to generalize it to combine with existing ecosystem and libraries?

Contributor

ivan-kleshnin commented Jun 28, 2015

@staltz this is the "built everything from scratch" kind of solution. Pretty ok when you have no forms and limited number of pages and widgets. Is there any way to generalize it to combine with existing ecosystem and libraries?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 28, 2015

Member

You mean integration with this e.g.?

Now all mainstream frameworks we have being it Bootsrap or Foundation or SemanticUI are built by the same principle. They require a looong list of LESS or SASS variables to be defined.

Member

staltz commented Jun 28, 2015

You mean integration with this e.g.?

Now all mainstream frameworks we have being it Bootsrap or Foundation or SemanticUI are built by the same principle. They require a looong list of LESS or SASS variables to be defined.

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 28, 2015

Contributor

Yeah. Imagine I'm talking to my boss that we need to refactor our CSS with local styles. I show him an article "Global CSS is dead". He says "ok but is it compatible with Bootstrap or any existing framework? How much time is it going it take? What budget should we reserve for it?"

What should I answer him?

Contributor

ivan-kleshnin commented Jun 28, 2015

Yeah. Imagine I'm talking to my boss that we need to refactor our CSS with local styles. I show him an article "Global CSS is dead". He says "ok but is it compatible with Bootstrap or any existing framework? How much time is it going it take? What budget should we reserve for it?"

What should I answer him?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 28, 2015

Member

"Bootstrap and similar frameworks are incompatible with new best practices (refer to article), hence if we refactor/rework Bootstrap to convert it to JavaScript styles, we will benefit in the long-run (refer to article)"

Member

staltz commented Jun 28, 2015

"Bootstrap and similar frameworks are incompatible with new best practices (refer to article), hence if we refactor/rework Bootstrap to convert it to JavaScript styles, we will benefit in the long-run (refer to article)"

@ivan-kleshnin

This comment has been minimized.

Show comment
Hide comment
@ivan-kleshnin

ivan-kleshnin Jun 28, 2015

Contributor

That's what I'm talking about.

  1. Who decided that those practices are "best" if there is still no ecosystem around it?
    "Bootstrap and similar frameworks" are 90% of the web... + 9% of legacy sites.
    Who is so brave to talk for all developers and decide for them what is "better"?

Personally, I admit it may be "better" or even "best". But engineering is all about practice so we need proofs and success stories from common people. Only a few (2-3) people shared their positive experience but without details and with the "we're right, you're wrong" aplomb. How this should decrease my skepticism?

It's obvious that such dramatic change will bring a lot of drawbacks.
Why not a word about them from promoters?
How global CSS can be dead if there is still no practical replacement for it except for
"do it yourself" cases?

  1. Noone can accuse me I'm only criticize. In most of my replies I was trying to shape a bridge between one approach and another. If we could pass variables between JS and LESS the whole transition could be made much more painless and cheap. And maybe the whole transition wouldn't be required at all, because two approaches could converge. Don't see any reaction on those propositions.
Contributor

ivan-kleshnin commented Jun 28, 2015

That's what I'm talking about.

  1. Who decided that those practices are "best" if there is still no ecosystem around it?
    "Bootstrap and similar frameworks" are 90% of the web... + 9% of legacy sites.
    Who is so brave to talk for all developers and decide for them what is "better"?

Personally, I admit it may be "better" or even "best". But engineering is all about practice so we need proofs and success stories from common people. Only a few (2-3) people shared their positive experience but without details and with the "we're right, you're wrong" aplomb. How this should decrease my skepticism?

It's obvious that such dramatic change will bring a lot of drawbacks.
Why not a word about them from promoters?
How global CSS can be dead if there is still no practical replacement for it except for
"do it yourself" cases?

  1. Noone can accuse me I'm only criticize. In most of my replies I was trying to shape a bridge between one approach and another. If we could pass variables between JS and LESS the whole transition could be made much more painless and cheap. And maybe the whole transition wouldn't be required at all, because two approaches could converge. Don't see any reaction on those propositions.
@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Jun 28, 2015

Member

@ivan-kleshnin I can't add much to this discussion other than vjeux's presentation about CSS problems, which I think covers everything technical. You're asking more from the social or dev community perspective, and I don't know what to say about that.

Member

staltz commented Jun 28, 2015

@ivan-kleshnin I can't add much to this discussion other than vjeux's presentation about CSS problems, which I think covers everything technical. You're asking more from the social or dev community perspective, and I don't know what to say about that.

@benoneal

This comment has been minimized.

Show comment
Hide comment
@benoneal

benoneal Aug 6, 2015

So imagine you live in a hypothetical world where dozens of developers are working on a Cycle.js single page app. Every event is globally scoped and all event selectors are just global CSS selectors.

Let's say there's a bug in the app. All your unit tests are green, but it's behaving erratically, but only in a few contexts. How easy would it be to debug this, to discover that, uh oh, it's a simple namespace collision is causing it to pick up unrelated events from other elements that only appear on some pages?

Do you think you'd pick that up immediately? Or after many hours pouring over everything trying to duplicate and isolate the collision?

benoneal commented Aug 6, 2015

So imagine you live in a hypothetical world where dozens of developers are working on a Cycle.js single page app. Every event is globally scoped and all event selectors are just global CSS selectors.

Let's say there's a bug in the app. All your unit tests are green, but it's behaving erratically, but only in a few contexts. How easy would it be to debug this, to discover that, uh oh, it's a simple namespace collision is causing it to pick up unrelated events from other elements that only appear on some pages?

Do you think you'd pick that up immediately? Or after many hours pouring over everything trying to duplicate and isolate the collision?

@staltz

This comment has been minimized.

Show comment
Hide comment
@staltz

staltz Aug 6, 2015

Member

@benoneal If you are referring to DOM.get(selector, eventType) in hierarchies of custom elements, global selection is a bug, should be fixed.

That said, I am starting to bet on hierarchical MVI, a new approach where selectors are locally scoped.

In any case, these two approaches are not the same as global selection bugs that you typically see in large jQuery-spaghetti SPAs.

Member

staltz commented Aug 6, 2015

@benoneal If you are referring to DOM.get(selector, eventType) in hierarchies of custom elements, global selection is a bug, should be fixed.

That said, I am starting to bet on hierarchical MVI, a new approach where selectors are locally scoped.

In any case, these two approaches are not the same as global selection bugs that you typically see in large jQuery-spaghetti SPAs.

@staltz staltz closed this Aug 8, 2015

@giogonzo giogonzo referenced this issue Aug 24, 2015

Closed

Use Radium #51

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment