facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
227.35k stars 46.37k forks source link

Support !important for styles? #1881

Closed syranide closed 4 years ago

syranide commented 10 years ago

We currently don't support !important as it has to be set using style.setProperty(name, value, priority). This should be trivially easy to implement if it's something want to support, although I'm not sure about the performance implications (EDIT: #1886), although I can't imagine it would be measurable as we would be doing the string test ourselves and those are cheap.

http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration

OK... apparently IE8 doesn't support this at all, it might still be worth implementing, for the future and for those who don't care about IE8. After further experimentation, apparently it is! style.setAttribute(name, value) (priority is part of the value). But apparently that was wrong as well, the only way to set it seems to be with cssText, an acceptable work-around may be to just use cssText when we detect an !important style, which should be seldom enough that performance is a non-issue.

An important consideration is that we already support this for the initial render, but subsequent updates will fail as !important isn't recognized for properties.

AdamKyle commented 10 years ago

!important is horribly abused in css, and if people write their css properly their is never a need for !important. That said I don't think it should be included, because then people can use "bad practices" in their apps and styles. Personally inline styling with react is bad enough.

vjeux commented 10 years ago

On a random note, I thought that inline styles override !important but I was wrong ( http://jsfiddle.net/do0hpcvm/ ).

zpao commented 10 years ago

@vjeux I'm going to leave this to you. I think we should probably just maintain status quo here and not support !important, but there may be valid uses somewhere.

syranide commented 10 years ago

@zpao We do support it though, we just don't support updating a style that has it.

zpao commented 10 years ago

That's not support, but I see what you mean (that's like saying we "support" hyphenated styles)

nelix commented 9 years ago

Any word on the progress of this? I'm using react in a widget and a browser extension that work on third party sites and not being able to update !important styles is an issue for me

waldreiter commented 9 years ago

@nelix Maybe you can use something like this as a workaround:

var sheet = document.createElement('style');
document.body.appendChild(sheet);
sheet.innerHTML = 'html {font-size: 1em !important;}';
syranide commented 9 years ago

@cody It would probably be easier to just manually manage the style property of the node itself ;)

ccnokes commented 9 years ago

+1 to Nelix's comment. For example, in Bootstrap CSS there are a number of utility classes that all use !important (hidden, pull-right, etc) that I wouldn't be able to override without !important inline styles. (I totally agree that !important is abused--and probably Bootstrap too, for that matter--but I think React should still be able to work with them.)

thomassuckow commented 9 years ago

We use !important to set a dynamic background color on an element and have it still show up when printing. Without !important the background is not printed.

EDIT: Since I only needed ie9+, I used setProperty in componentDidMount & componentDidUpdate

quantizor commented 9 years ago

IMO, it should be supported. It's not React's place to be dogmatic about how people author their styles.

zpao commented 9 years ago

I had a longer post here and then lost it, oh well…

The summary is that it would be expensive to check every value for !important, so supporting this isn't awesome. Even if we do get a good option, it's unlikely we'd do this while we support IE8 because I don't want to go down that cssText path. This isn't really at all about dogma, I would say that it's more about perf. And the fact that we're faced with a number of limitations when working with styles in CSS.

What we could perhaps do is change the data structure for style.

style = {
  color: 'red',
  backgroundColor: {
    value: 'blue',
    important: 'true'
  }
}

It would be backwards compatible (if the value isn't an object, we do the exact same thing). And it would allow us to start using the setProperty API with important. Downside is obviously more objects. But we don't have to do any string parsing.

quantizor commented 9 years ago

@zpao That seems reasonable. Perf is obviously a very important factor to consider and I appreciate the creative thinking... your solution would at least allow a developer to support the need, even if it's a little more effort.

Charca commented 8 years ago

I'm facing the same issue as @nelix. It is quite an edge case, but it would be nice to have support for this.

nelix commented 8 years ago

@zpao that api suites me fine, I will be really happy to rip out dynamically generated css + manual style manipulation I have from my chrome extension's IFrame armor.

mwschall commented 8 years ago

Ran into this today, trying to dynamically set the background color of a Semantic UI Icon. They have those colors set as !important, presumably for legitimate reasons. Fortunately I could work around it like @thomassuckow did. Would be nice to avoid the extra step though.

6ewis commented 8 years ago

what's the status on this?

zpao commented 8 years ago

No change. As we invest more in JS styles I think we'll end up with some changes to how styles work. In the mean time I don't think we'll make any changes without a fuller picture of how that will play out.

japgolly commented 8 years ago

This makes it pretty hard for React to play nice with Semantic UI (which frustratingly uses !important nearly everywhere).

harmony7 commented 8 years ago

For the record, since 15.x it no longer works even on initial render (since moving away from innerHTML). All rules with "!important" are now being thrown out.

syranide commented 8 years ago

For the record, since 15.x it no longer works even on initial render (since moving away from innerHTML). All rules with "!important" are now being thrown out.

For non-IE8 (which we actually don't actively care about anymore) this can technically be solved. EDIT: If that is something we want to look into.

yanickrochon commented 8 years ago

Over two years ago, and this is still debated? To me restricting it's use because of some subjective argument is just regressive. If it's mainly to prevent people to abuse it, well, it is quite idiotic as it's use is... important on many use cases. If it is part of the specification, then why not supporting it in React?

However, for balance, an "!important" declaration (the delimiter token "!" and keyword "important" follow the declaration) takes precedence over a normal declaration. Both author and user style sheets may contain "!important" declarations, and user "!important" rules override author "!important" rules. This CSS feature improves accessibility of documents by giving users with special requirements (large fonts, color combinations, etc.) control over presentation.

toddself commented 7 years ago

I literally just lost an hour debugging this. Given the amount of assistance react provides users when they do something unexpected (suggesting camel-case when using hyphenated class names, etc), i would have expected something in the console in this.

It would be awesome to be non-dogmatic and support people doing something unnecessary or at least warning about it.

Venryx commented 7 years ago

I'm having this issue as well.

The reason I need the " !important" override on an inline style is that my project is in a transition state, and still has CSS being applied using classes--one of which is using a css " !important" tag. (originally to override some JQueryUI css, I believe)

Having support for the tag would prevent me from having to use another css class (I'm trying to transition away from css classes), or modifying the old css class to no longer have the !important tag--which is a pain since it's used globally and would break other areas of the UI. (which are still using the old, JQuery rendering)

brigand commented 7 years ago

For the moment, I wrote a library that should address this use case: brigand/react-with-important-style.

It uses this.element.style.setProperty to set the style with the important modifier.

arackaf commented 7 years ago

I said to myself, while searching for this, "it's not even a question if React supports this; of course they do." Turns out that's not the case.

My use case is like others: I'm trying to get my component to play along nicely with some third party stuff.

I really hope this gets added.

domino14 commented 7 years ago

Plz add

tvankruijsbergen-aa commented 7 years ago

Agreed this should be fixed. In the meantime, I hacked it through the ref callback:

<div ref={(node) => {
    if (node) {
        node.style.setProperty("float", "right", "important");
    }
}}>

</div>
s-devaney commented 7 years ago

Can't believe this isn't supported.

Tectract commented 7 years ago

I also just lost time debugging this. Please support !important. It's part of the css protocol, you should support the entire protocol not just the pieces you like.

it would be expensive to check every value for !important

it would be cheap to check every value for ending in space, then only those that do for ending in !important. It would also be a lead-in to supporting more advanced css directives.

pmirandaarias commented 7 years ago

Bad practice? sure, if you have coded from zero to all the entire page, what about to join a project with Symfony, UiKit, jQuery, etc, etc... that uses ReactJS too. What, I'll have to say to all the team "hey! bad practices, delete all the !important from the css please"

sergiotapia commented 7 years ago

I'm really surprised this has been overlooked for so long. Support for !important is absolutely needed for CSS. There are so many use cases for it.

dagatsoin commented 7 years ago

I am ok for best practice guideline.

But the majority of developper works on budget which leads to quick and dirty or in best case using bootstrap, foundation, uikit and co. which are still leader in the vanilla HTML/CSS integration habits. And they do use !important. It is not dirty, it is the css way for providing control on override in inheritance.

Also there is a lot of great projects which are driven by @vjeux famous presentation. And there are powerful: jss, glamor, styled-component, etc. Is still React responsibility to check CSS ?

ablankenship10 commented 7 years ago

Just to add, I'm writing a 3rd party widget to be injected using React and I have to use the CSS library cleanslate which gives me my own DOM with completely reset CSS. This also means I HAVE to use !important on all of my styles. This is necessary for anyone making a widget because you can't trust the styles of the rest of the page. So despite "good practice" this is necessary.

Tectract commented 7 years ago

React css support seems a little behind the times on css support actually. It should properly support not only all features of the css standard, but also css 'modules'. There are some key issues with css that cannot be easily addressed by any means other than modules, namely global namespaces and code isolation. See here:

https://glenmaddern.com/articles/css-modules

On tool I used in some of my React-on-Rails projects is Rebass, which is a css module, for example:

https://github.com/jxnblk/rebass

but it seems to have only limited support. Works for a decent modal popup though...

brigand commented 7 years ago

@Tectract css modules are far outside the scope of React core. Also inline styles are as isolated as css modules.

bootrino commented 6 years ago

You can do anything you want with css in react if you use backticks in a style tag.

For example this is how to do important:

  render() {

    return (
        <div>
          <style>
            {`
              #colorBlackImportant {
                color: black  !important;
                font-size: 50px !important;
                }
            `}
          </style>
          <input
            type="text"
            className="form-control no-border-left"
            id="colorBlackImportant"
            name="navField"
            value={this.props.value}
            label="url"
            onChange={this.props.onChange}
            onKeyPress={(e) => {if(e.key === 'Enter') {this.props.onEnter()}}}
          />
        </div>
    )
  }

This also lets you do all that weird stuff like :hover and :focus

        <div style={{"padding": "6px"}}>
          <style>
            {`
                          .countConnections,
                          .countConnections:focus,
                          .countConnections.focus {
                            background-color: #f4a911;
                            color: white;
                            text-decoration: none;
                            }
                          .countConnections:hover,
                          .countConnections.hover {
                            color: #808080;
                            background-color: white;
                            }
                        `}
          </style>
          <a
            className="btn btn-md btn-block countConnections"
            type="primary"
            href={connectionsButtonURL}>
            {numberOfConnections} connection{(numberOfConnections === 1) ? null : 's'}
          </a>
        </div>

I know you've been missing the blink tag since they got rid of it. It's back in React:

              <style>
                {`
                  @keyframes blink {
                    from { opacity: 0.0; }
                    50% { opacity: 1.0; }
                    to { opacity: 0.0; }
                  }

                  blink{
                    animation: blink 20s infinite;
                    color: #FFD938;
                  }
              `}
              </style>
              <h3>
                Connection invitations received from {directionString}&nbsp;
                {(!!this.props.countInvitations) ?
                  <blink>
                    <i className='fa fa-bell' style={{'fontSize': '24px'}}/>
                    &nbsp;{this.props.countInvitations}
                  </blink> : null}

              </h3>
singular1ty94 commented 6 years ago

@bootrino's solution is still the best to date, coupled with React's fragment syntax you can embed styles side-along tags you need edited, and cobble together some kind of solution - particularly useful if you're fighting Semantic-UI which uses !important everywhere:

{myObjects.map((object, key) => {
    return (
        <Fragment key={key}>
            <style>
            {`
                #${object.uniq_id}_label {
                    background-color: ${colors[key]} !important;
                }
            `}
            </style>
            <Label
                size="large"
                color="teal"
                id={`${object.uniq_id}_label`}
            >
                {object.children}
            </Label>
        </Fragment>
    );
})}
TimoSolo commented 6 years ago

@singular1ty94 - Also trying to override SemanticUI - it may be semantic, but it's not great css :(

I ended up wrapping a div with the styles inside the offending element:

<Grid.Column>
          <div  style={{paddingTop:'4em'}}>
                ...
          </div>
</Grid.Column>
singular1ty94 commented 6 years ago

@TimoSolo An alternative solution to that method, which I've used lately, is to use styled-components to wrap Semantic UI's elements and then apply custom styling, eg:

import styled from 'styled-components';
import { Input } from 'react-semantic-ui';

export const StyledInput = styled(Input)`
    font-size: 12pt !important;
    ...
`

This way your JSX still looks relatively neat but you get the opportunity to apply actual CSS classes onto the Semantic elements rather than using additional elements or embedded CSS like my original solution.

necolas commented 6 years ago

I've bumped into this problem too. React Native for Web currently relies on !important for certain flex styles due to inconsistencies in how browsers expand the flex shorthand. Applying !important is fine when transforming styles to CSS via StyleSheet.create, but breaks when using inline styles due to this limitation in React DOM.

I'll make a PR to add a style warning when values include !important. And will look into ways to potentially support !important after that.

corysimmons commented 6 years ago

Why doesn't <pre style={{ fontFamily: 'monospace !important' }}> work? 😩

yagudaev commented 6 years ago

I tend to agree that using !important is a sin. If we do not want to support this we should at least give a warning to the user

Tectract commented 6 years ago

I like using !important. It makes me feel like my code is important, lol.

kelseyleftwich commented 6 years ago

I'm trying to use !important so background colors will print when using Chrome. Maybe there is a better way but I haven't found it. ¯_(ツ)_/¯

brigand commented 6 years ago

If you don't want to load in a full css-in-js solution for this, here's a minimal implementation: codesandbox, gist.

The <style>put css here</style> technique breaks with certain input. Also, this would be a touch simpler if we just modified the wrapped element's .style DOM property (using the same set of APIs), but I'd rather target it with CSS, and allow it to do its own inline-style overrides of !important properties

JoeDuncko commented 6 years ago

Like others, I just ran into this while trying to build a react-powered widget to be used on third party sites. I, too, just spent a couple hours super confused because at one point styles would work, then as soon as I threw !important in there they disappeared. Very frustrating.

steodor commented 5 years ago

Having lost quite some time on this myself today, i'd like to reiterate what @probablyup said back in 2015: "It's not React's place to be dogmatic about how people author their styles." - it's simple specs, i don't see one valid reason for not fully supporting it.

ccurtin commented 5 years ago

Sometimes !important must be used for overrides of 3rd party software.

ckhicks commented 5 years ago

This is super frustrating - while I agree with the theory of not using !important in your styles, it's not React's job to block something outright. Unless you can guarantee that every. single. vendor. lib. will stop using it as well, we need a way to override something if the situation demands it.

Put another way: Yeah, we shouldn't find ourselves sliding down the hill if we park correctly, but sometimes you just need perform a quick stop. You've removed the emergency brake.