5

All:

I wonder if I made a signin/signup toggle tab component, how can I dynamically add a selected class to according component(like ngclass)?

render(){
return (
            <div>
                <span className="tab" className={{"selected": this.state.signin}}>Sign In</span>
                <span className="tab" className={{"selected": !this.state.signin}}>Sign Up</span>
            </div>
    )
}
6
  • You are on the right track. Remember that class names have to be strings, so className={this.state.signin ? 'selected' : ''} would be more appropriate. Commented May 2, 2017 at 22:45
  • 1
    It also just came to my mind that you can do precisely this using classnames lib. Give it a try, it allows you to manipulate plain-objects with boolean values in order to apply classes. Commented May 2, 2017 at 22:47
  • @RishatMuhametshin in that way, I can not keep "tab" class, how can I merge them? Commented May 2, 2017 at 22:52
  • 2
    I would recommend you use the library classnames it is a very nice and useful tool. usage import cx from 'classnames'; ....<span className={cx('tab', {selected: this.state.signin})}>Sign In</span> Commented May 2, 2017 at 23:52
  • @JohnRuddell Thanks, I chose that way at last. Commented May 3, 2017 at 0:00

3 Answers 3

4

I would recommend you use the library classnames it is a very nice and useful tool.

usage

import cx from 'classnames';
...
<span className={cx('tab', {selected: this.state.signin})}>Sign In</span>

when invoking the function you can pass default values and an object to conditionally add classes in any order.

syntax: cx(default, {conditional: boolean, conditional: boolean});
syntax: cx({conditional: boolean, conditional: boolean}, default);
syntax: cx(something, {conditional: boolean}, 'something', 'something');

I prefer to use it consistently in the order of default string, conditionals. just for the sake of readability for me and others that come by, its easy when you expect it to be the same.

you can pass it a lot of different things and it handles it. From the NPM docs

classNames('foo', 'bar'); // => 'foo bar' 
classNames('foo', { bar: true }); // => 'foo bar' 
classNames({ 'foo-bar': true }); // => 'foo-bar' 
classNames({ 'foo-bar': false }); // => '' 
classNames({ foo: true }, { bar: true }); // => 'foo bar' 
classNames({ foo: true, bar: true }); // => 'foo bar' 

// lots of arguments of various types 
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux' 

// other falsy values are just ignored 
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1' 
Sign up to request clarification or add additional context in comments.

6 Comments

IMHO That's a lazy solution. dynamic classes is just an easy code write, you shouldn't need to import more libs.
@Despertaweb It depends on how complicated the classnames you need... now does that mean you have to? no, if it doesn't suite your needs then it doesn't make sense to use it. There was already an answer (this is also 5 years ago...) with a solution to the OP's question. It felt more appropriate to provide an alternative solution to give this question different types of answers so it can be viewed more holistically. As another data point, this package and others like it are more or less an industry standard today. classnames has ~8.5mil weekly downloads. clsx is at ~5.6mil weekly downloads
I see your point @John Ruddel, but as long as you could us "external" functions or even computed.... But of course is up to you hehe
Well at some point it doesn't make sense to re-invent the wheel. There are some places where writing everything from scratch makes sense, and other places where it doesn't. If someone wants to look at the source code from classnames even, to get inspiration and then write their own class name generator... have at it. But downvoting an old answer for the sake of writing it yourself isn't always the right approach either. Why not write your own router vs using a package? We should embrace open-source and help add to the community. Thats what this answer attempts to do :)
I see your point, but comparing writting a router vs a computed property AKA ClassName.... not same complexity, right?
|
4

You can use template literals ``

In your case it will look like that:

<span className={`tab ${this.state.signin ? "selected" : ""}`}>Sign In</span>

2 Comments

thing I dont like about this is your class now looks like "tab selected" or when not selected "tab " notice the extra space. you can trim it but thats annoying to do every time you have a conditional class.
DOM parser doesn't care if you have trailing spaces in the class attribute or not. You generally shouldn't worry about this at all.
0

Though John's answer does the Job. That library lacks function support for determining the value.

You can use this npm package. It handles everything and has options for static and dynamic classes based on a variable or a function.

// Support for string arguments
getClassNames('class1', 'class2');

// support for Object
getClassNames({class1: true, class2 : false});

// support for all type of data
getClassNames('class1', 'class2', ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames({class1: true, class2 : false})} />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.