Material-ui: [Core] There should be a more sophisticated styling solution.

Created on 22 Apr 2016  ·  100Comments  ·  Source: mui-org/material-ui

@callemall/material-ui please leave some input here when you can 👍

We need to decide on a styling solution for 0.16.0 that will help address long standing issues. Outside of performance issues, there are hacks and props all over the place to make up for the fact that we are missing out on some of the powerful features in CSS that cannot be used with inline styles -- pseudo classes, media queries (without matchmedia), etc.

From what I understand, the general consensus is that we want a JS style solution that has the capability to write styles to an actual stylesheet in the DOM.

Here are a few of the maintained solutions that do this:
https://github.com/rofrischmann/react-look
https://github.com/Khan/aphrodite
https://github.com/jsstyles/react-jss

Here are some points we need to consider when implementing the new solution (IMO):

  1. Does it align with our goals? (lightly touched on above)
  2. Implementing media queries that follow the high level breakpoints detailed in the spec that can be easily used in components with a stylesheet mixin (or whatever the implementation we use calls them). If we're overhauling the style implementation, it is the opportune moment to plant the seed for much better responsive UI support in this library. It would be even better if these tools are available in userland too 👍
  3. Should we create layout helper components and/or mixins to help unify flexbox layout implementations across the lib?
  4. Does theming needs to change to maximize best use of the new solution? While theming is one component of consistent styling, we should also look into creating variables for many of the common material styles such as global keylines/font sizes/spacing/margins/etc. I strongly recommend we improve our typography consistency by creating predefined type styles matching the material-ui typography guide, and try match up component elements like titles etc as best possible to these global type style variables as a default.
  5. If using a library as large as react-look, try and see how we can import modules for a minimal build size. The full build size is 16kb gzipped which is fairly large. It would be great if we can minimize the impact on build size. I realized that 9kb of that is https://github.com/rofrischmann/inline-style-prefixer which we already use... 😄
discussion performance umbrella

Most helpful comment

Is the styling solution finalized?

All 100 comments

Some further questions:
6) Will we remove or aim to remove xxxxStyle props and have users pass in an xxxClassName for overriding styles? Or will these be complimentary?
7) Will we allow override of styles via CSS and simplify our components interfaces. So if I want to override menuItemStyle in IconMenu, do I create a style = StyleSheet.create({ IconMenu: {MenuItem: { color:red }}) type override?

@chrismcv My personal opinion is that we definitely need to leverage the solution to remove these super specific props we're seeing proposed: [TextField] add floatingLabelFocusStyle prop #4043

Before we know it, people are going to be asking for props for subcomponent styles for every possible focus/active/hover/whatever state.

I see so many issues that are "how to style XXXX", "can't style XXX inside YYYY", "add somethingInsideToTheLeftButSlightlyMiddleFocusHoverActiveStyle prop to XXX please"

@chrismcv in 6. regarding the more general xxxxStyle props vs classNames, what do you think? with some of our components you're gonna need to be able to reach in one way or another (fortunately we'll be able to use :hover etc though!).

@chrismcv I think that xxxxStyle props should go in the style property, not the className-ified style object.

@nathanmarks Thanks for bootstrapping the conversation. That's definitely one of the major issues we need to address for the next releases 💯 .

Outside of performance issues

For me, that's one of the main concern I have with the solution we will choose.
We don't have many benchmarks, be we can easy imagine that we lost many CPU cycles with our current approach. The CPU cycles are lost into memory allocations and garbage collection for our inline style object.

@oliviertassinari

I am playing around with a couple of the JS style solutions at the moment. It's interesting but clear that it is still "early days" so to speak.

One thing I was thinking -- outside of dynamic style properties (for eg, if the component has a color prop), should we be changing the way we create the base style object?

It seems as though with the JS style libs, to get maximum performance you should use their StyleSheet.create() method once and have keys (css "classes") in that object for props/states such as open={true} rather than dynamically building the style object literal with a couple of conditional properties and passing it to the stylesheet factory method every render for every single style.

Even though the stylesheet selectors get cached in the sense that they are written only once to the DOM (and in some libs only written to the DOM when needed for the render()), we're still wasting resources with some calculations + object creation + garbage collection as you mentioned above if we are creating a new style object each render just to have it thrown out.

Hmmm... I left a comment here yesterday (Sunday). Did it get deleted?

@rvbyron I remember it clearly. I certainly didn't delete it though.

@rvbyron I do remember it too. I have no idea what happened.

@rvbyron - had it in my email, so back here in quoted form!

Well, I for one would like to see a number of things take place.

A) Yes, by all means get rid of using the element's style parameter at the library level. All of the components should be defined using className. Having the components use style destroys all of the power CSS offers.
B) It would be great to have classNames automatically attached to the root element of each component (e.g. The RaisedButton component would implicitly have className="mui-raised-button"on the component's root element). It would make styling a whole lot easier. That could even be configurable.
C) Get themeing out of the muiTheme.js files altogether. A themeing muiTheme.SCSS file would be much better in that it would allow any properties chosen by the theme creator to be applied and not just the ones specifically allowed by the component. Of course this would probably require that B be implemented and active.
D) React-look appears to be a good compromise as it converts JSON objects containing style properties into classNames. It makes things easier to override. However, as I said in C above, I would still like the themeing base to be created in SCSS. I am pretty open on which CSS assist package to use. But I would stay away from anything that wanted to use the element's style parameter over the className parameter.

@chrismcv Thanks dude!

I think that what @rvbyron has to say is important because in some ways, JS styling is very much a paradigm shift from regular CSS. Most people are not using JS styling in their day job and it requires a different way of thinking + makes it harder for designers who may usually contribute to projects that aren't so proficient in JS.

It's important to consider all the angles here.

@oliviertassinari @chrismcv

One thing I realised about react-look is that you need to wrap all of your components in the look HoC. This seems pretty invasive, it even hijacks the render() function, stores super.render() in a const and performs style resolution operations that way. Some other solutions such as Khan/aphrodite just require a function wrapper around the styles.xxxx reference from Stylesheet.create() inside className={}.

Hijacking the render() function just for css seems over-engineered to me. It tells me that the React built in tooling/support for this sort of deeply integrated styles functionality is just not there, I'm not sure about the idea of a CSS helper HoC controlling the render for all of our components.

Thoughts?

Hi Material-UI team!

Have been following you for a while and now, seeing this topic, I also wanted to contribute with some thoughts why moving from inline-styles to css might be a good idea. I have read a lot of discussions in this repo that cover the rendering performance, styling children/nested elements, the media queries, pseudo-elements, etc., so I'll focus on something else that I haven't met discussed yet, but which I think is also relevant. And it is styles organization. Here is what I mean:

  • Some styles come from from the component defaults (which are set in the node folder and are not touchable)
  • Some come from component parameters (for example Avatar component parameter size={40} sets width, height and line-height to 40px)
  • When the component defaults are customized (the theme colours) the styles come from theme customization place
  • When the the rest of component styles are modified the styles come from a component implementation, which is another part in the code

When it comes to adjust the styles there are at least 4 different locations (👆 ) to look at, which makes it hard to investigate issues.

When styles come with css you'd see the selector and know exactly where to fix. With inline-styles it takes time to understand where the particular property comes from, and where and what should be modified. And if developer modifies it in the wrong place (let's say in the styles area instead of size parameter, since nothing actually tells that size is the style) it will affect the whole width=height=line-height=40px block performance, or will lead to writing again width/height/line-height which will make size parameter inapplicable.

In addition it also makes it hard to investigate which of the parent elements have specific properties applied, because all you can see in the inspector is element.style.
image

When styles come with selectors (class names) it gives much more control over the styles structure than inline-styles.

Update: Forgot to mention the suggestion (which this topic is about):

/component
--component.js
--component.css (or sass that is converted to css when the page is rendering)

This structure will keep component in the scope, but will give more control over styling. And a BEM className convention will help to avoid unnecessary nesting:

.mui-component {}
.mui-component__child {}

Which overall will help to implement, adjust and maintain Material-UI styles.

@chrismcv

Thanks for finding the email and placing it into the commentary!

Best of both worlds behavior approach?

What about a "behavior" concept of importing the styling technique that best suits your needs. An import of "StyleTheme" or "ClassTheme" could be used to select the behavior. StyleTheme could refer to the muiTheme object material-ui has today and make the component centric styling developers happy. Or, ClassTheme that would use an SCSS file that is built from the muiTheme.js object (synced) making the CSS centric developers happy. That would mean that all components would then need to accommodate {...theme.ComponentName} in the render elements.

To offer a very simplified example, a RoundButton component would have the render method like:

render() {
    return (<button {...theme.RoundButton} />);
}

For the StyleTheme behavior, theme.RoundButton would contain:

{ 
    style: {
        display: 'inline-block';
        borderRadius: '20px';
        width: '40px';
        height: '40px';
    }
}

For the ClassTheme behavior, theme.RoundButton would contain:

{ 
    className: 'mui-round-button'
}

A combination of the two could be retrieved as ClassStyleTheme behavior, theme.RoundButton would contain both:

{ 
    className: 'mui-round-button',
    style: {
        display: 'inline-block';
        borderRadius: '20px';
        width: '40px';
        height: '40px';
    }
}

The mui-theme.scss file would be generated from the muiTheme.js file and reflect in SCSS the exact properties the JS file contains. The camel casing of the JS names would be converted to more standard class names:

mui-round-button {
    display: inline-block;
    border-radius: 20px;
    width: 40px;
    height: 40px;
}

Any CSS customization to the MUI components would simply be identical classes loaded after the mui-theme.scss file was loaded, thereby overriding the mui-theme properties.

@oliviertassinari

I think that using something like scss (+ css modules for namespacing/hashing) has a lot of benefits. Is this something you are 100% opposed to? I'm probably slightly biased because it is what I am accustomed to using at work, but a lot of people are in the same boat.

My main problem with the JS styling situation is it feels like all of the solutions are still a work in progress. There are not a lot of real world performance evaluations out there to look at, the libs we are looking at are unproven and I feel as though we are spending a lot of our time trying to figure out how to do styles in JS properly. The main goal of this lib is to implement the material design spec and I can't help but feel that this is hamstringing us at the moment. (we def need to sort the perf impact issues)

I think we have different concerns regarding this.

  1. Where to put the static styles (easy, a css file can do)
  2. How to switch some styles depending on input (className switch)
  3. How to apply dynamic styles (inline styles can do that)

All seem good when you're writing an application, no one outside your code needs to change anything.

But with libraries things are different, all the above concerns are there, plus the following:

  1. How to enable users to customize the static styles?
  2. How to implement theme in a way that it's easy to switch, customize and isolated (different subtree different theme)?
  3. How to avoid polluting the global namespace so we can play well with others?
  4. How can the users override the inlined dynamic styles?
  5. transformers! (rtl, prefixer, etc)

What we have right now somehow handles all those concerns with these caveats:

  1. Performance!
  2. Deeply nested components are hard to customized, as @nathanmarks said: somethingInsideToTheLeftButSlightlyMiddleFocusHoverActiveStyle
  3. We can't utilize the power of some css features.

If we change our styling approach we'll have to do it all over again. If it comes to that we should be sure to answer all those before starting migration.

In my humble opinion, I think CSS and what ever that compiles to it are not parts of the future. I think we all agree that inline-styles made our lives a lot easier. Honestly, the only limitation I see with inline-styles is :hover!

We can solve those issues with doing a bit of design.

  1. memoize the styles object, for components that have state, we can break down the state and put it in a smaller component so that the style object in it can be memoized based on the passed props that are the higher component's state. This is easily solvable!
  2. break them down! why do we have a ListItem with a LOT of small functionalities embedded in it? we can break it down and make it composable, then we don't have to add monstrosities like somethingInsideToTheLeftButSlightlyMiddleFocusHoverActiveStyle
  3. meh! all we get performance with is :hover I think we can live with that until browsers or react does something about it.

My point is, we already address a huge number of concerns with our current styling approach. It has limitations because we don't follow all the patterns around inline-styles. if we start breaking down our components and make them a lot more composable then we don't really have to worry about anything. take MeuItem I took that out and made it composable, you see how easy it is to use and how performance can be improved for it using pure rendering!

So instead of changing our approach and solving all these issues again let's invest the time improving what we already have. we don't need to support media queries, we can change our components in a way that's easy for others to implement responsiveness upon them. Hard to debug? if we break down our components then the inlined styles will be smaller and easier to read. debatable though! I mean all you need is a break point to see what participates in Object.assign to see where the styles are coming from.

That's of course my own opinion I'm very open to discussion.

@alitaheri

You raise some great points. Thanks. I'm wondering if some sort of hybrid solution is a possibility. Seems that no matter what angle we take there are a bunch of issues 😆

I have time to work on this next week -- let's have a chat and see if we can come up with a clever idea.

I agree with trying to minimize the amount of change and having to re-solve already solved issues. There's 2 important goals here in my mind:

  1. Performance
  2. Developer experience (JS style libs help a lot here by enabling developers to use classes in their applications with ease)

Need to think about this more 😄 but as long as we manage to solve those 2 points I'll be happy with our solution.

Another random note -- it would be great if we had an automated way to enforce certain code conventions and design patterns for inline/jsstyle/whatever across the lib.

Is this something you are 100% opposed to?

@nathanmarks I'm not 100% opposed to use SCSS (_I'm using it at work_). But from my point of view, it's a dead-end.
One of the main advantages of React is to abstract away the rendering specificity of browsers: the DOM.
As far as I know, the long term goal of the React Core Team is to provide an API to write cross-platform component. Actually, they are currently experimenting into this direction. SCSS won't help.

I completely agree with @alitaheri. We could start with those two steps:

  • Use the getStyles pattern everywhere so we can more easily migrate later.
    Will we be able to use a codemod? Who knows.
  • Breaking down each component as proposed by @alitaheri.

@oliviertassinari I agree with the dead-end conclusion -- it's not the future. I brought it up largely to stimulate the conversation about how to make JS styles work for us. I knew some people around here had some good ideas surrounding the issues 😄 Wish FB were a _tiny bit_ further along with their experiments!

I actually think the getStyles() pattern we currently employ has it's own problems. @alitaheri and I had a pretty good chat today about what to do to improve our JS style setup (including theming!). I'll reply back tomorrow with some more info once I get a chance to jot down some notes!

Next week I'm on vacation and I'm going to experiment with a solution to our current problems while keeping all styles JS based.

Just read this post on Lessons Learned At React Amsterdam (https://medium.com/@kitze/lessons-learned-at-react-amsterdam-51f2006c4a59#.o12h794or) and one of presentations was about solutions for styling in React: http://slides.com/kof/javascript-style-sheets#/ A timely presentation for this discussion.

One requirement that I keep thinking about and that I haven't seen explicitly stated (at least that I recall) is the need to support web-only vs. web and react native. If the intent is web-only (i.e. react native isn't a requirement) then solutions that leverage what browsers already efficiently and robustly support and people are very familiar would be a good thing. If supporting react native is a must then that opens up a different set of needs & requirements. Just something to think about and keep in mind as the technology choices, compromises, etc. are evaluated.

@hburrows

Thanks for sharing that presentation!

@alitaheri

We may want to look at the lib mentioned in that presentation (here's a demo). It could save us a lot of work. I was looking at it previously but there were a few things I didn't like (such as the requirement of wrapping every single component in a proprietary HoC). However, there is some discussion about some of that happening here . He mentions that implementing changes like this would allow for HoC-free use. I do prefer that method/design for the sheet writing (also seen in aphrodite).

Alternatively, we could always create our own react bindings for jss that can work with mixout.

The lib author also said this, which falls in line with my own thoughts on the matter 👍 :

However you need to understand that not everything makes sense to be style sheets. For the most dynamic changes you should use inline styles.

@nathanmarks The implementation is rather very small and very easy to mixout :grin:
https://github.com/jsstyles/react-jss/blob/master/src/index.js
I think this library can help us out :+1:

@alitaheri Yeah I agree!

I'm experimenting with some custom bindings for jss as well -- there's a couple of issues/limitations I want to try tackle. (One though may require work on the core lib)

There seems to be a prevailing sentiment in the React community that JavaScript styling is the best solution. That sentiment is fine, I am not in disagreement with those who have it. However, the way JavaScript styling is implemented is almost always without regard to the CSS developer. The implementation all too often favors style=/[element property]= over className= and prevents the CSS developer from doing their job.

As I offered in a previous comment, I think the two could live nicely together. One must simply take a behavioral approach to applying the style properties. The library must accommodate the direct application of style properties to an element, or it must allow the indirect approach of creating a className comprised of those style properties. A library that allows the developer to choose the behavior seems like an ideal solution.

There are many reasons CSS deveoper's don't want to simply ditch their approach. Search for "why use css" to see about why people find it beneficial. You will find abstraction of styles and a powerful selector language to be among its benefits. Let's not forget the enormous amount of code that exists today that benefits CSS users.

Again, this is not intended to be a pro CSS commentary by any means. There are those of us that would like to use CSS for styling. This comment is intended to encourage an architecturally neutral styling approach that empowers developers to have the choice.

@rvbyron One of the main reasons we want to change our current approach is to make it easier to customize the components using css too. using a library like jss will allow us to use the css features while taking advantage of js-styles. And since it turns those styles into css, they can be easily overriden with an extra classname without the ugly !important hack.

@alitaheri Great to hear! I am really looking forward to seeing material-ui accommodate a className based approach.

Again, fantastic to hear on the className approach. With this in mind, I have some questions on how it might be implemented:

  • What do you believe the class name naming convention might look like?
  • Will all class names have an "mui-" or other prefix on them?
  • Will the class be dash notation of the component name?
  • Will a class name be applied on the root element of each component?

@rvbyron

Ideally:

Customizable prefix. Dash notation of some sort for better dev experience and a hashed suffix which can be also be set to a fixed string (so won't change if the theme settings are changed) using a custom theme ID. Including a less verbose production option, or even a callback function to customize. And I'd assume a class on the root is usually always gonna be necessary anyways.

I think there are many requirements listed and suggestions offered. So, is there a take away from all of this discussion? What is the next course of action? Is there any work being done on implementing react-jss into this material-ui?

@rvbyron Yep, we're experimenting with a couple of rough ideas behind the scenes. Will update this issue when we've got some more concrete ideas.

In my humble opinion, I think CSS and what ever that compiles to it are not parts of the future. I think we all agree that inline-styles made our lives a lot easier. Honestly, the only limitation I see with inline-styles is :hover!

The issue is that :hover is a very basic, very vital part of styles. Futurism aside, it might be prudent to avoid premature commitment to a solution that must resort to cheats and work-arounds to reimplement a native feature.

@wtgtybhertgeghgtwtg we're working towards a solution that uses real stylesheets so functionality such as :hover is supported.

Given that the major points have been decided (JSS styling via className and root element classNames), is there any roadmap and timeline for material-ui v0.16.0 release?

@rvbyron We don't have a promised timeline, but as of now, styling approach and performance is our primary focus for the v0.16.0 release and something we're actively working on now. We will likely use this issue in the near future for community feedback once we've settled on the right direction in a few other areas as it relates to internals, API, migration, etc.

@newoga Thanks Neil! I appreciate the update. As for the other issues, I would like to add that just going to a className based system can be a visually breaking change for many and I would suggest confining this release to just that. Other changes in addition to that might really impede a migration. However, I know your team will pick the best balance.

@newoga over here jss has been called out as the future of the styling system for material-ui. Is this a concrete enough plan that others could start onboarding jss into our projects now, in anticipation of the 16.0 release?

@sorahn not yet

@sorahn This issue is designed to get community feedback about what is still a really challenging problem to solve. No official decisions have been made. As of now, everyone should only be picking and using a style library or approach that they have assessed is best for them and their project.

For the record, the goal of this styling change isn't to migrate everyone to some different standard, but to make it easier to use and style Material-UI components regardless of what styling approach you use with it.

tl;dr No! Do what's best for you, not what anyone else says :)

@nathanmarks @newoga Thanks for the update!

We're running into the limitations of responsive design + server side rendering with all inline styles, so we're investigating the alternatives. No particularly strong opinions about (s)css-modules or csx or whatever, but we love material-ui so it'd be great to just follow along with whatever you guys are going to do :)

I ran into media queries, read this thread (and others). I dove into some of the potential solutions and articles.

I really like the JSS + CSX solution (from a developer _joy_ perspective).

JSS benefits & performance

Similar to @sorahn, I'd be happy to adopt a material-ui standard, I hope @nathanmarks work in this direction validates this approach. Also, it seems that both the CSX/JSS developers are eager to help and promote adoption of their libraries.

@rosskevin Working on it as we speak -- there's things to consider here that haven't been covered in any of the solutions to date.

Our requirements are much broader than the existing solutions are capable of supporting because of design limitations or opinions. This is largely because the existing solutions have been developed with apps in mind where you have full control over the consumption of your component APIs versus a library where you have a diverse set of users wanting to style their components with different tools.

@sorahn Quick question -- what are you doing about vendor prefixes with server side rendering? Are you just rendering all prefixes on the server? Or are you passing the UA?

@nathanmarks We are sending the user agent to the browser, but I personally don't like relying on that. What about just putting them all in by default, and allow people to override them via props on muiTheme object, or the opposite, do none by default, and allow people to opt in.

muiTheme: {
  // other stuff...
  stylePrefixes: ['webkit', 'moz', 'ms']
}

@sorahn You'll be able to do whatever you want, prefix, not prefix, pass all, pass a UA, etc.

@nathanmarks I have just released [email protected]. Most important change - deterministic id's generation, here is an example of ssr with react http://jsstyles.github.io/examples/index.html

Just throwing in my $.02 here... while I really like the idea of inline styles and aphrodite appeals to me, it almost feels like it would be easier if the styles were based in a library format in scss like bootstrap 4.

What I usually do is literally copy the bootstrap.scss file and the _variables.scss file while creating a _mixins.scss file... with that copy under ./lib/style, I update the local bootstrap.scss file to reference the local variables and mixins, while using the path to the node_modules's versions of everything else...

I then setup my webpack config to make ./lib/style part of the search path for the sassLoader config.

In this way, I can have a main.scss file that loads bootstrap, etc... I can from there reference variables and/or mixins within the rest of my project, and when I build/bundle the output, the appropriate styles are included.

The down side to this, is it would prescribe using material-ui as source (not pre-build) and webpack for including scss in the bundles. That said, it would probably be the most straight forward path of using existing variables, classes and styling mixins.

Again, I really like the idea of JS styling, and tbh like what Aphrodite has to offer... I was working through something similar (was going to call it derma) as a styling library for inline styles, but Aphrodite already does everything I planned on and more.

Is the styling solution finalized?

Are there any updates on this?

Yep, the next branch is using jss

I just came across this project and I was extremely excited about it because it looked great, the example page made it very easy to figure out how to use the components and it looked like it was widely used; however, I am very disappointed with the inline stiles and I'm glad to see you guys are getting away from them. One of the things I'd like to point out is that anything to do with layout outside of these components should be removed and let the styling of the parent component handle that. The lowest level component should not have margins or padding on it in any way that would push surrounding elements away... especially since it's about impossible to override without messing with the inline stiles which means I need to dig around and find out how to do that. I haven't really dug much further into this project because I unfortunately find it unusable. I certainly read a lot of the discussions of inline versus css styling. Anyway, you lost me at TextField. There's a margin on top that's 14px and bottom that's 16px. I wouldn't mind TOO much writing a simple style to override that, but that's impossible because of inline styling and it would be completely crazy to me to have to create a higher level component just to reverse that as in wrapping your component with a div and doing margin: -14px 0 -16px or slightly adjust it with a calculation to the way I want it, but having to correct for that in any way shouldn't really be necessary. I would prefer it much more if you would allow a className to be passed as a prop like you already do so the layout styling could be applied to the component the way your community wants to style it. Anyway, that's my $.02.

Just to add to that, creating layout type components for these or making additional props to handle the layout properties might be ideal such as using a grid system like foundation and bootstrap do. For instance using props like size, gutter, width, columns, etc., but start with no styling around the outside of what is visible with the component.

I am completely with @jbsmith969

it would be completely crazy to me to have to create a higher level component just to reverse that as in wrapping your component with a div and doing margin: -14px 0 -16px or slightly adjust it with a calculation to the way I want it

@jbsmith969 I do agree that low level components shouldn't have any layouting logic. However, creating a higher abstracted component for your app specificity doesn't sound crazy at all.
IMHO, that's one of the most powerful patterns that React enables (thanks to the isolation properties).

@oliviertassinari @jbsmith969 Thats exactly what we did! We created our CustomTextField component which I pass like 2 params to (field name, and color), and it just does a tiny bit of logic around those, then renders out a material-ui/TextField with whatever we want.

It's components all the way down!

So with react we are taking our html and putting it into our js and that is fine and dandy. But taking our css and shoving it into our html? Does that not sit well with anyone else?

What was the advantage of moving off of sass?

Call me old fashioned, but what is so wrong about keeping our js/html and css separate?

I am legitimately looking for some answers here...

Related to https://github.com/callemall/material-ui/issues/3614#issuecomment-249095805, styling simply becomes components.

I see CSS classes as new components: (eg btn-danger-like from boostrap)

const DangerButton = ({ hoverColor, style, ...others }) => {
    return (
        <MUI.FlatButton
            hoverColor={hoverColor || Colors.pink100}
            style={{ color: Colors.black, ...style }}
            {...others}
        />
    );
};

Transitions are a pain though..

(for @jbsmith969, MUI follows the Material Design spec. If I wouldn't want to follow the spec, I would expect to do some workaround. However, I agree that MUI is hard to hack around, but it's mainly because of inconsistent weird component props, not because their styles are inline)

@vizath right I definitely have the same thought. But what are the advantages of this solution?

If there was a solution that actually worked at least as well as just CSS does, I would consider giving it a shot. However, since there is not currently a solution (that I know of) that can do that without caveat, I don't really see the apeal.

Why is this repo trying to adopt what seems to be an alpha stage idea for a solution into an otherwise very useful codebase? I just don't think we are there with the tec yet, nor do I think that this is the proper testbed for that tec.

@nathanmarks can you advise on how to override component's styles using JSS? I'm using the latest code in next

EDIT: Okay, only figured out that it's still not fully implemented. My bad! 😬

I didn't find a good way yet to eliminate dead code in object keys, and with JSS it makes it mandatory to use objects to store styles.

Random example in a component of the next branch (which is not finished): https://github.com/callemall/material-ui/blob/b372f6223ec2528dbe02f100e4802334f88445b7/src/IconButton/IconButton.js#L36
I can't find a way to reliably find that primary and accent classes are not used.

I didn't like either the way MUI was managing inline styles before, for the same reason (lint would have catch unsued variables if the styles were defined separately, see https://github.com/callemall/material-ui/blob/60a202fdc9645aa00f20c52e5152f168a1b0031b/src/IconButton/IconButton.js#L26).

What was the advantage of moving off of sass?

@gdaunton It depends on the side you are one regarding not using the inline-style / sass approach.

From a user point of view, it's going to provide the following improvement:

  • Faster react rendering method, as we are going to rely on cached generated CSS sheets.
  • Simplified style overriding, as the CSS precedence is lower than the inline style one and users can use the DevTools to identify the sheet to change.
  • Faster first paint when doing server side rendering.

    • Users will be able to inline the critical CSS sheets, and only the used one in the page. That's something you CAN'T do with _Bootstrap_ as it's big monolith 🙈 .

    • Users should be able to uglify the class names keys in production.

  • No built-chain dependency like _scss-loader_ or _Webpack_.

From a contributor / maintainer point of view, it's going to provide the following improvements:

  • No more CSS linter
  • No more pre-processor CSS
  • No CSS syntax to learn
  • A much more powerful language to style the component: JavaScript
  • Open the possibility to abstract away the style engine. E.g. by using react-with-styles

Why is this repo trying to adopt what seems to be an alpha stage idea

Depends on what you mean by alpha stage idea.
We are far from being the only one to used this approach. E.g. AirBnB, Khan Academy, ReactNative.

worked at least as well as just CSS does

CSS was designed from the beginning to style documents, not components.
That's a major shift in our industry.

From my point of view, It sucks for styling components.
People behind the web specification are well aware of this issue and are trying to address it with the local scoped style of _Web Components_.
Have you noticed all those new projects since React was launched around improving CSS and writing component-based style?

Yep, the next branch is using jss

@nathanmarks where can I go to get caught up on this change?

Found it: https://github.com/callemall/material-ui/blob/next/docs/customization/themes.md

@bramick seems it's not about next because this is working started from 0.15.0

Ok, so I'm missing what's new... Anybody?

@bramick next isn't fully documented yet (however it does have a documentation site). For now you'll have to read source and you can reference the documentation site source code to see how it works. Just realize some of it may still be a moving target.

@oliviertassinari Wow! Thanks for the in-depth response.

I can't say I entirely agree, but you defiantly cleared up a few questions I had.

I do agree, we should be (and are) moving toward a world where our styles are component based, and css is not great for that. However, (in my opinion) there are still a few wrinkles to iron out before we should be adopting this at scale.

I am curious though, has anyone looked to see if there is a performance difference between this and standard css? I feel like css might still have an edge on javascript; after loading it still has to generate and inject its styles.

@gdaunton read about jss performance at https://github.com/cssinjs/jss/blob/master/docs/performance.md

It is standard css as rendered, added to the page, but authored within the component. I'm using the next branch and it is working quite well.

@newoga can you send me a link to what you're referring to?

@bramick OMG! That's really simple, isn't it? For example, for Button in next look here.

I understand the appeal of putting CSS inside the JavaScript file, after the success of JSX, but I'm not sure if it's a good idea to do the same with all the CSS of an application. I know that JSS has some good use cases, for instance when dealing with super complex dynamic styles.

My biggest concern is that the style information will end up cluttering the component definition. The CSS expressed with JavaScript objects is a lot more verbose and harder to organise. For instance, in the Button component referenced in the previous post, almost half the code is style information. There is no separation of concerns anymore. I know you can move the style code to a separate file, but then there's no point of having it in JavaScript int he first place.

For developers, the biggest disadvantage is that they lose all the intelli sense information for the CSS properties and their values. Actually, I like all that nice code structure and expressiveness that a CSS preprocessor can give you, if used correctly.

I don't mind adding complexity to my projects, if that brings more value. So I never minded the extra CSS linter, pre-processor, loader and the extra syntax that I had to learn. I'm also trying to remain open about JSS, it's just that after the first look it didn't convince me.

My biggest concern is that the style information will end up cluttering the component definition.

This is entirely up to you, depends on how you organize your code, if you stick to some rules, nothing bad happens (talking from production experience of 2 years).

The CSS expressed with JavaScript objects is a lot more verbose and harder to organise.

It is actually less verbose because you have a higher level of code reuse and less repeatitions.

For developers, the biggest disadvantage is that they lose all the intelli sense information for the CSS properties and their values.

I think the goal here is to give the users of material-ui a choice to use whatever they want for styling. Autocompletes for CSS is an argument I hear often. Mostly it comes from people who didn't use any cssinjs a lot and its just fear of loosing some conveniences they used to.

I don't mind adding complexity to my projects, if that brings more value.

I think the whole point is reducing complexity and making the codebase more consistent and easy to use and understand, but all complex scenarios covered at the same time.

My biggest concern is that the style information will end up cluttering the component definition.

In our project we extracted the style information of the components in seperate files and loaded them with webpack. Main benefit is that all is well organized and that webpack can bundle the code per component, so code splitting of js code AND style information is possible.

Also seperation of concerns is given, when you seperate the logic to produce your styling rules. One example is, that we introduced style factory functions which produce stlying much like mixins in well known css preprocessors.
My point is, that you gain so much more flexibility to model your own specific workflows and adapt best to the needs of the project and the team.

It's pretty late in the game to change technologies, but I agree that styled-components is very promising. Handles SSR, media queries, pretty nice syntax and so on. Compared to JSS it also handles autoprefixing and theming.

As far as I know it uses postcss inside, which will not give an acceptable performance when used at runtime, because it is a full css parser with lots of edge cases handling and plugins. I could imagine to preprocess this to JSS JSON, but to be honest I don't see much value in using CSS language and mixing it with JS variables and function calls vs. just using JS all the way down.

Just to mention, the current build of styled-components is 250kb, already minified. To be fair that's because they bundle React and co, but still, even the PostCSS parser alone has 13kb (unminified, might be 2kb~) which already is almost the size of JSS or Fela.

It's lovely for quick & simple prototyping of (presentational) component though, but I don't see any benefit/feature other solutions can't provide.

I agree, I tried it out in a library I develop and it was much too heavy to publish. I'm sure they'll make progress with that, but it appears the JSS work here is nearly complete and offers most of the same benefits.

I've used react-toolbox lately, they use CSS modules for theming that basically just relies on webpack's sassLoader. For me it worked really well. Maybe it's worth investigating.

Hey, i have to second the opinion of @mgcrea, react-toolbox theming support is simply amazing – im switching over as customizing how components look is the most important aspect of the frontend story.

I do not think anyone should ever expect good old CSS styling to ever be a first class citizen in Material UI, that is the reason react-toolbox was started

At least that is my impression after reading lots of issues and posts about this topic. I can vaguely remember things like the team strives to better React Native compatibility and many comments on styling edge cases that are just way easier to solve with JSS.

However that information is lost among many discussions. Because this is such a controversial topic, I think it would be of an incredible value if one could have a Wiki page about the project goals and philosophy (written by the core maintainers) with a strong remark on why Javascript styling is so ingrained into the framework.

I really like Material UI because it is the most active and polished material styling framework for React. However the JSS all the way through causes me lots of headaches when I want to keep a unified style with third party components.

For myself, I appreciate the way Material-UI does the styling as opposed to something like react-toolbox, and here's why: In one of our projects, we have the ability for the user to select dynamic themes:

Imgur

Because the user might select a color pair we cannot determine ahead of time, whatever theming scheme we use must be highly dynamic. With , changes to the theme can happen live, b/c all the styles are generated inline: all I have to do is give it primary/accent colors.

In react-toolbox et. al., this seems to be more of a chore from what I can see.

@jrop yeah in this very special case you need dynamic JSS but for many applications that's not an important requirement and the current story of customizing (not even speaking about UI testing) material-ui is simply not acceptable. We are building a highly visual and designed app that cannot just use the default material-ui look, as we mostly need/want the behavior parts of it.

@DominikGuzei you can customize next branch using jss. This is _not_ what you see on the current release.

Folks, I feel like we are beating a dead horse here. The next branch has has chosen a different (much improved) path with theming and allows for overrides. It is not using inline styles any more and provides the flexibility I have seen requested. For others that want more customizability, they can use an HOC over the next components and write their own stylesheets.

@nathanmarks, since this decision has been made (as far as I can tell, and works quite well 👍 ), I suggest you write a summary and close/lock this issue so those that find it understand the way forward.

if one could have a Wiki page about the project goals and philosophy (written by the core maintainers) with a strong remark on why Javascript styling is so ingrained into the framework.

@fgarcia I have given a presentation at a local event in Paris earlier this week regarding the evolution of the styling approach used by Material-UI. You might be interested having a look at the slides and the _notes_: A Journey toward better style. I focus on the Challenges, Problems and Solutions.

the user to select dynamic themes

The static style generation aspect of CSS-Modules has quite some consequences.
Injecting style at runtime is less cost efficient but allow us to:

  • Gives us more flexibility with the style implementation. E.g. The CircularProgress has a fixed thickness linked to how the CSS keyframe animation is implemented. With dynamic style, we can add a thickness property so users can change the value dynamically. ⚠️ not to be abused.
  • On large scale app, it allows to inject only the needed styles for the displayed component on the screen. Reducing the amount of worked needed by the browser to bootstrap the page. Hence, faster time to first paint after interaction. E.g. inlining critical CSS with SSR.
  • Allow users to use dynamic theme and variation of components. E.g. changing the color of a button with all the color variations needed.

@oliviertassinari That is awesome to hear. I may have a non-standard point-of-view regarding CSS modules, but I don't think they are worth all the fuss. I was excited to hear of JSS through material-ui for this reason. It seems much more inline with the philosophy of JavaScript than CSS modules.

@oliviertassinari thanks for the summary of benefits. It's definitely interesting when you look at these aspects. The downside of JSS and it's ecosystem (also postcss) at the moment is that all that is bleeding edge and you cannot rely on the well established tool chain and knowledge base like with simple css-modules + SASS. But that's the price you pay for innovation, it just depends if you have certain requirements / are willing to pay the price of bugs and the less documented path.

JSS has been created prior to css-modules. CSS-modules has become popular faster because it solved a problem for a majority users without changing the syntax too radically.

That being said, you are using react, which is also kinda "new" technology. If you want SASS, maybe you should also pick vanilajs or backbonejs)

@kof React is a very different story as it is used by hundreds of thousands of devs and is managed by Facebook (it won't go away over night), so it might be "new" but very solid (haven't run into many issues with it so far).

SASS is one of the most established css preprocessor and can be used in any project – it's very solid and brings a lot of value to the table. So i would only choose something like JSS if absolutely necessary (e.g: because of dynamic themes) but dislike to throw out years of experience / frameworks / knowledge base etc. in a commercial software project with several devs. So i would even consider building only the dynamic theme aspect in JSS and the rest with sass / css-modules.

I understand this way of thinking, but also I consider it as contra-productive and blame it for slowing down innovation and the industry.

Why u just don't support both? Styles written in JavaScript AND styles written in css-modules? If i have a look at https://github.com/callemall/material-ui/blob/next/src/Button/Button.js for example, it would be quite easy to use class-names passed in by a prop (https://github.com/javivelasco/react-css-themr) instead of using:

const classes = this.context.styleManager.render(styleSheet);

Isn't it?

It doesn't look like the discussion about using JSS or CSS is finding an end (yet?). To me it looks like a fifty/fifty thing at the moment.

Regarding SASS, react-toolbox are currently migrating away from it in favor of a full postCSS solution, I personally think postCSS (with sassLike plugins) is a better pick, more powerful without build deps.

Styling in all JS, and in React in particular, is obviously still in a rapid state of evolution. So whatever you do, I'd try to avoid being opinionated - just fit well with with a broad set of current usage.

Consider just adding a *className prop wherever there's a *style prop. Period.

Full disclosure: I'm a happy Aphrodite user.

Adding a className will still require !important hacks because the inline styles (from style property) takes precedence.

@ligaz Of course, you're right. Aphrodite adds !important to everything by default, so perhaps my thinking about a "broad set of usage" is badly skewed.

@ligaz @estaub - next is already coded _without_ style and allows users of the components to override by providing className (and multiple class names to the various parts of complex components).

The styling paradigm setup on the next branch by the maintainers is using JSS. It is a pleasure to use and easy to override on an individual or a theme basis.

This horse is dead. Let's stop beating it. @oliviertassinari I suggest you close and lock this issue with a statement of direction on next.

Hi @rosskevin - can you point me at any examples at all of how this is working in next?

I'm currently looking at frameworks for a new project, I'd love to use Material UI but we'd need the changes that you've mentioned are in next. I've added the next branch to a test project and added a simple component and I'm seeing an inspector full of inline styles, so I'm guessing I'm doing something wrong?

Any further details would be really helpful!

Thanks

@giuseppepaul next is not published on npm because it is pre-alpha and is not yet complete. You can clone https://github.com/callemall/material-ui.git#next and run the docs/site to see that there are no more inline styles. It also has a reasonable amount of demos.

I am publishing my own private version of next (so I can control the updates) and am using this in a soon to be production application.

This horse is dead. Let's stop beating it. @oliviertassinari I suggest you close and lock this issue with a statement of direction on next.

That horse isn't fully dead. But definitely in a tight spot 🔫 .
I agree, let's close this issue.

A big thanks to @nathanmarks for his hard work on that story 👏 !
I have gathered more information on the road ahead with #5718.

Hello,
IconButton have a CSS3 transition property for ripple effect. In the complex interaction of the doc of Card@next, you have added a transition to transformation for add a transition when the icon reverses.
If I do the same on my app, one transition (ripple or reversion) overrides the other (an element cannot have two properties otherwise one overrides the other one).
However your chevron icon has successfully two transitions applied to it. Because in a someway you merge transitions provided by IconButton and the one defined in your code. How do you achieve that ?
Some other stuffs are obscure for me and I cannot find related doc. theme has a lot of methods/properties as breakpoints (not used here) transitions (used here). Is there already doc about theme property of what MuiThemeProvider.createDefaultContext() returns as it seems useful especially that it's used extensively inside your code.
this.context.styleManager.render(styleSheet) ? What ?
You also use jss-theme-reactor which I still don't understand the point compared to react-jss.

@NitroBAY This thread is over. Please ask you question on the right channel.if you notice a bug or want the documentation to be improved, open an issue. Otherwise you can use StackOverflow of gitter.im.

Was this page helpful?
0 / 5 - 0 ratings