jedwatson / classnames Goto Github PK
View Code? Open in Web Editor NEWA simple javascript utility for conditionally joining classNames together
License: MIT License
A simple javascript utility for conditionally joining classNames together
License: MIT License
when I upgraded React to version 15.0.1(newest version) I got this error: [email protected] - UNMET PEER DEPENDENCY [email protected].
Need some help !, thanks.
Hello @JedWatson,
Do you follow semver for classnames ?
Hello there,
I would like to suggest a small addition to the functionality of this library. It would be handy IMHO if there would be a way to add a prefix (such as "no-") instead of just leaving the class out of the generated class string.
so that next to this:
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true }, { bar: false }); // => 'foo'
the something like the following would also be possible:
classNamesPrefixed("no-")({ foo: true }, { bar: true }); // => 'foo bar'
classNamesPrefixed("no-")({ foo: true }, { bar: false }); // => 'foo no-bar'
Best regards,
Rico Moorman
Hi, thanks for this very useful library, it's gave me huge convenience manipulating DOM classes!
While using classnames, I found out it's somehow a bit inconvenient to remove class from current DOM class context, e.g
I am dealing with following html:
<p class="my-text invisible"></p>
and I want to remove invisible but keep my-text class:
var pDOM = document.querySelector('.my-text');
var classNames = require('classnames');
function showP {
var pDOMClass = classNames(pDOM.className, {invisible: false});
pDOM.className = pDOMClass;
}
showP();
currently it will still keep invisible
class b/c it's set in HTML, and pDOMClass is 'my-text invisible'.
Why I need this feature is b/c I don't want to specify my-text
inside script, but get reference from HTML.
So is it feasible to take later param with higher priority?
Hi @JedWatson,
I'm actually thinking that would be useful to have a option for specify a prefix/suffix of all the classes that are you passing into the classNames()
and have it as a global defined variable.
like:
classNames.prefix('foo-')
Have a little bit more of API in terms of options or settings for some cases can be useful.
What do you think guys?
PS: I this goes forward I would create the PR with some proposal.
HI,
First, thanks for your amazing package, we use it all over the place and it's been truly great.
We have recently discovered a slight limitation with regards to dynamic keys in objects passed to classNames
.
Say we have a React Button component which receives a theme
object.
function Button({ theme, disabled, children, ...otherProps }) {
const rootClass = classNames(theme.button, {
[theme.disabledButton]: disabled
});
return (
<button
className={rootClass}
disabled={disabled}
{...otherProps}
>
{children}
</button>
);
}
If the provided theme object doesn't contain a key of disabledButton
, [theme.disabledButton]
will be coerced into a string producing a key of "undefined"
.
This means that the DOM element will actually receive a class of "undefined"
.
The fix would be a simple one. On this line (https://github.com/JedWatson/classnames/blob/master/index.js#L28)
- if (hasOwn.call(arg, key) && arg[key]) {
+ if (hasOwn.call(arg, key) && key !== 'undefined' && arg[key]) {
There are ways around it obviously, but I was wondering if you would be interested in a fix at all? Or if you would consider that this is not the responsibility of the library and we should make sure we provide defined keys.
For information this is how we currently get around it:
const rootClass = classNames(theme.button, {
[theme.disabledButton]: disabled && theme.disabledButton
});
Let me know how you feel about this, and thanks again for your work.
My use case is something like classNames('foo', { foo: false, bar: true })
should render out class="bar"
instead of class="foo bar"
. Should this be supported by the library or is this out of scope? I'd be glad to submit a PR if this use case is something you guys plan to support.
Would you be open to bundling a .d.ts TypeScript definition for this package, so that it can seamlessly be used from TypeScript?
There are existing definitions https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/classnames that could be copied over, so it should be fairly trivial.
Hi!
I (probably, not only I) like to use rather popular classnames + css-modules
use case.
The most popular usage if it is not only concatenation but concatenation with truthfulness check.
Disadvantage: with css-modules
,real class names are usually stored in some object.
Usually it's looking the next way:
import styles from './styles.css'
const className = cx({
[styles.foo]: someLogic
})
And this looks weird.
I suggest some minor changes that will allow to "bind" the context.
As far as I understand that doesn't affect the speed too much. But should allow to make className calculations more comfortable to perform.
Also you can define this feature in a separate bind.j
s file and wrap into boundCreator.
And to use classnames in a certain way.
const styles = {
foo: '#foo',
bar: '#bar',
baz: '#baz'
}
var cx = require('classnames').bind(styles);
// or
var cx = require('classnames/bind')(styles);
const className = cx('bar', ['foo'], {baz: true})
// -> #bar #foo #baz
// Or es 6
import styles from './styles.css'
import classnames from 'classnames'
const cx = classnames.bind(styles)
const className = cx('bar', ['foo'], {baz: true})
// -> #bar #foo #baz
// es7
const className = styles::classnames('bar', ['foo'], {baz: true})
// -> #bar #foo #baz
Sorry, just filing an issue for myself. Really busy these days but will get to it.
I'm having this specific problem using classNames
with webpack
devtool
option set to eval
. It only happens on Chrome and when the console is not open. The issue is calling classNames
inside the classNames
function with the 'use strict'
statement inside the function (https://github.com/JedWatson/classnames/blob/master/index.js#L22), this will cause a ReferenceError
.
See:
Explanation:
I would be happy to submit a PR with a umd wrapper if you guys are ok with it :)
Thanks for the great lib!
Hey @JedWatson,
I am using webpack, once I compile production assets with
NODE_ENV=production webpack -p --config webpack.client.config.js
,
I see the library copyright in javascript
Is there a way to get rid of it?
Before writing a pull request I would like to ask for inputs on the following idea:
classNames({ 'foo-': { bar: true, baz: true } }); // => 'foo-bar foo-baz'
classNames({ 'foo-': ['bar', 'baz'] }); // => 'foo-bar foo-baz'
classNames({ 'foo_': { bar: true, baz: true } }); // => 'foo_bar foo_baz'
classNames({ 'foo_': ['bar', 'baz'] }); // => 'foo_bar foo_baz'
I'm trying to use classnames to manage the active class on a list of bootstrap tabs (see the code below). However, the generated markup is putting the active class on the anchor link child of the list item instead of the list item itself which causes the currently active tab to not display correctly. Is there something that I'm doing incorrectly?
const myFeedTabClasses = classNames({ active: this.state.selectedTab === 'my-feed' });
const discoveryFeedTabClasses = classNames({ active: this.state.selectedTab === 'discovery-feed' });
return (
<section id="feed">
<section id="content-region">
<PostCreationBox />
<ul className="nav nav-tabs" role="tablist">
<li role="presentation" className={myFeedTabClasses}>
<Link to={Config.RouteNames.MY_FEED} role="tab" onClick={this._onSelectMyFeed}>Feed</Link>
</li>
<li role="presentation" className={discoveryFeedTabClasses}>
<Link to={Config.RouteNames.DISCOVERY_FEED} role="tab" onClick={this._onSelectDiscoveryFeed}>
Discovery Feed
</Link>
</li>
</ul>
<RouteHandler user={this.props.user} />
</section>
</section>
);
hi,
thanks for wonderful add-on. question that I have is, can i use it with props? can i check conditionally what props value component has, and then add the class?
e.g:
var btnClass = classNames({
'btn btn-sm': true,
'btn-success': this.props.flag.success,
'btn-warning': this.props.flag.warning
});
return <button className={btnClass} >{this.props.label}</button>;
//-----------------
<Button label='click here' flag='success'/>
<Button label='click here' flag='warning'/>
Thanks for help
npm install classnames
should add this to package.json, right now it doesn't.
At this point, were someone to want to put it in package.json themselves, would they just add "classnames": "*"
?
There are two competing PRs to add deduping functionality for classNames
.
I'm happy to add support for it but not to impact the performance of the package, so what I propose we do is add one as ./dedupe.js
.
Anyone who then needs deduping can simply require('classnames/dedupe')
and get the alternate version. This has the added benefit of not increasing the download size, whether in browserify or standalone distributions.
@dcousens would appreciate your help assessing #20 vs. #21 in terms of which one we should merge.
From my assessment, #21 is missing some edge cases because it doesn't split strings, so the following test would fail:
asset.equal(classNames('a b', { a: false, b: true }), 'b')
#20 also uses a separate _parse
function which may be more efficient than the closure used in #21... needs some testing.
Hi, I'm trying to create a component that takes in some props similar to this:
<Component padding={{direction: 'all', size: '1'}} />
Any idea if this can be done with classnames
?
I tried writing it this way but it didn't work:
const classes = classnames({
'pa1': props.padding === {
direction: 'all',
size: '1',
}
})
Any help here would be very much appreciated. Thanks in advance.
Classnames almost works with React Native's StyleSheet module, using the bind variant. The one problem is that in React Native, the style attribute expects an array of keys instead of the string you'd pass to the className attribute of React.
I was able to get bind.js
to work with React Native by returning the array of classes instead of joining it.
Here's an example React Native component using Classnames (assuming classNames is returning an array):
import React, { Component } from 'react'
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
import classNames from 'classnames/bind'
const cx = classNames.bind(StyleSheet.create({
button: {
padding: 4,
backgroundColor: '#fff'
},
'button--dark': {
backgroundColor: '#000'
}
}))
const Button = ({ children, primary }) => {
const style = cx('button', {
'button--dark': primary
})
return (
<TouchableOpacity style={style}>
<Text>
{children}
</Text>
</TouchableOpacity>
)
}
I wanted to PR with an update to bind.js
that allows an array to be returned instead of a string, but I couldn't think of a good way to achieve this without duplicating the entire bind.js
file. It seems like a shame to duplicate so much for such a small change.
There's no (good) way to pass a config argument to classNames()
, as arguments are used exclusively for classnames and conditions. It's also not possible to set a flag on this
, because it's exclusively used for the styles object.
I had some other ideas about how to achieve this, but they seem impractical or just aren't possible for one reason or another:
A. Export a factory from bind.js
that accepts styles and config, i.e. const cx = classNames(styles, { returnArray: true })
. Impractical as it changes the existing API.
B. Move the majority of the code from bind.js
into another file that could be shared by bind.js
and a variant bind-array.js
. This would avoid duplication, but means Classnames would need to be built to UMD from source files.
C. Split the output string on ' '
, either in a function exported by Classnames, or in the consumer. Probably not ideal for performance, although I don't know for sure. If done in the consumer, it assumes that Classnames is joining on ' '
(and will break if this changes).
D. Have bind.js
recognise a config constant or symbol that could be passed in the styles object, or bound to this
. Feels like a hack.
Any thoughts on this? Am I missing something obvious? Would this functionality even be welcome in Classnames? 😊
Would be nice if it could expand arguments
array as well.
Readme clearly explains how to use an array ("if you have an array of these, use apply"). But I wonder if there's any reason not to also accept an array as a regular argument. Would you be open to a PR enabling that?
I´m new to React and can´t figure out how to use this lib. Is there a possiblity that you could add a full example to the README where state is manipulated to generate classes on a form with multiple inputs?
Thanks.
I'm not too fond of bower, but since lots of bower react users will come to check this library after classSet deprecation, I think it's valuable to provide it.
Hi. I'm tinkering with webpack DLLPlugin lately. I just wondered... Does classnames perform its magic at compile time or at run time?
I use the module in almost all my react classes, so I definitely want it "preloaded" or at least available at runtime, that's what I thought at least.
Now I wonder: should I bundle the classnames module into a vendors DLL (or any kind of webpack chunk that gets preloaded), or is it just wasted there since it performed its magic during the compilation step?
Sorry if this has already been answered elsewhere..
Hi, I use classnames module my project.
But there has a bug: Android WebView don't support ES6's Dynamic key.
render: function() {
var userChartText = this.props.userChartText;
var list = userChartText.map(function(item,index){
var textCss = cl({
'usercenter-chat-label':true,
['usercenter-chat-label__'+(index+1)]:true //error!!
});
return (
<li className={textCss} key={index}>{item}</li>
)
},this);
return (
<div className="usercenter-chat">
<canvas className="usercenter-chat-canvas" id="myChart" width="130" height="130"></canvas>
<ul>
{list}
</ul>
<a href="javascript:;" className="usercenter-chat-q" data-pe="tap:center.showMask">
<i className="icon-game icon-game-question"></i>
</a>
</div>
)
}
So I changed this module and add a few parameters:
render: function() {
var userChartText = this.props.userChartText;
var list = userChartText.map(function(item,index){
var textCss = cl({
'usercenter-chat-label':true,
'usercenter-chat-label__@1':true, //like a function,but it can work perfectly!!
'@1': index+1 //like pass a argument.
});
return (
<li className={textCss} key={index}>{item}</li>
)
},this);
return (
<div className="usercenter-chat">
<canvas className="usercenter-chat-canvas" id="myChart" width="130" height="130"></canvas>
<ul>
{list}
</ul>
<a href="javascript:;" className="usercenter-chat-q" data-pe="tap:center.showMask">
<i className="icon-game icon-game-question"></i>
</a>
</div>
)
}
Source Code:here
Is there a way to include a computed variable, not just a string? For example below, is there a way I can include typeName
, prefix
, and forIcon
if they pass the truth tests?
getClassNames() {
const typeName = `${this.props.type}-${this.props.name}`;
const prefix = this.props.prefix + '-';
const forIcon = ICON_LIST[this.props.for];
return classnames([
'muted-message',
this.props.classNames,
this.props.type,
{typeName: this.props.type},
{prefix: this.props.prefix},
{forIcon: this.props.for}
]);
}
Just like this.
.class1>.class2 {
}
both class1 and class2 would be add a hash suffix.
so the nest class selector not work.
Regards.
The latest release if you use AMD and commonjs/browserify on the same page.
Hi I'm using ReactJS, but when a class is added using {'some-class' : Boolean}
my view got scrolled to top. I wonder if you can help me with this.
Hi, firstly i'd like to thank you and the comunity for this amazing module, it certainly makes the life of anyone coding in React easier.
It seems i'm doing something wrong, yet i cant find what it is. You see, i'm coding in React with Typescript, therefore, i use
import * as ClassNames from "classnames"
to import your module into my code, but webpack seems unable to include it in the output bundle, forcing me to include it as a separate asset in my html. While this isn't terribly annoying, it would be wonderfull if classnames could be bunbled with the rest of my code.
I hope you can help me, either by telling what i'm doing wrong or by showing me how to hack around this.
Thanks in advanced!!
I'm using CSS modules, Is there a guaranteed order of application of CSS classes? In the following example, can I expect the resultant style to always have a green background since .bar
is last? I'm getting inconsistent results in my app. Is there a way to enforce order of application then?
// main.css
.foo { background: red; }
.bar { background: green; }
// main.js
import styles from './main.css';
const style = classNames(styles.foo, styles.bar);
classbtn = classnames({
foo: this.state.status
})
<button className={classbtn}>submit</button>
From the code above, we have the classbtn will not return anything if this.state.status is false
What if we want it to return class bar
if this.state.status is false
?
On a project I am currently working on, I encounter some situations where a class name is built up dynamically based some variable, for example: 'help help--' + props.position
, resulting in help help--left
, help help--top
, help help--right
. This library would make this code much more expressive if it supported a syntax such as the following:
var cls = classNames({
'help': true,
'help--${0}': [ props.position ]
}, { interpolate: true });
The character 0 inside the syntax notation would indicate that the 0th (first) element of the array should be used.
To improve performance, this behavior can be switched off by not setting the interpolate
option to true (no interpolation by default).
Is there an interest to have a feature like this in the library (if so, I am happy to implement it)? Any ideas for a better syntax?
I would really like the possibility to build a class name from a variable if the said variable is set. I encountered the issue when building classes for a standard Bootstrap alert box: in addition to the class alert
I also needed the string alert-<alert-type>
, but only if alert-type
is defined.
classnames('a', false)
produces 'a false'
in classSet, but classnames ignores false
. Passing null
crashes it. Passing undefined
gets it ignored. Doesn't matter what the desirable behaviour is; it breaks compatibility with classSet.className
so it'd be nice if this could be classNames
camelCased.undefined
rather than ''
.Please add UMD declaration.
There is nothing telling the developer where or what is duplicated. How is she supposed to fix it?
[HMR] ./~/classnames/index.js
There is another module with an equal name when case is ignored.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Rename module if multiple modules are expected or use equal casing if one module is expected.
client.js?3ac5:104 [HMR] ./~/classNames/index.js
There is another module with an equal name when case is ignored.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Rename module if multiple modules are expected or use equal casing if one module is expected.
* local#strings x 1,825,228 ops/sec ±0.14% (99 runs sampled)
* npm#strings x 1,741,256 ops/sec ±0.26% (102 runs sampled)
* local/dedupe#strings x 738,172 ops/sec ±0.70% (98 runs sampled)
* npm/dedupe#strings x 755,439 ops/sec ±0.34% (102 runs sampled)
> Fastest is local#strings
* local#object x 1,237,033 ops/sec ±0.34% (99 runs sampled)
* npm#object x 1,188,942 ops/sec ±0.21% (100 runs sampled)
* local/dedupe#object x 966,397 ops/sec ±0.17% (98 runs sampled)
* npm/dedupe#object x 965,234 ops/sec ±0.64% (98 runs sampled)
> Fastest is local#object
* local#strings, object x 1,186,118 ops/sec ±0.74% (100 runs sampled)
* npm#strings, object x 1,161,875 ops/sec ±0.32% (101 runs sampled)
* local/dedupe#strings, object x 623,911 ops/sec ±0.32% (101 runs sampled)
* npm/dedupe#strings, object x 608,739 ops/sec ±0.40% (99 runs sampled)
> Fastest is local#strings, object
* local#mix x 946,228 ops/sec ±0.32% (98 runs sampled)
* npm#mix x 891,805 ops/sec ±0.19% (97 runs sampled)
* local/dedupe#mix x 209,369 ops/sec ±0.17% (100 runs sampled)
* npm/dedupe#mix x 211,798 ops/sec ±0.20% (100 runs sampled)
> Fastest is local#mix
* local#arrays x 319,617 ops/sec ±0.23% (100 runs sampled)
* npm#arrays x 310,179 ops/sec ±0.12% (99 runs sampled)
* local/dedupe#arrays x 336,681 ops/sec ±0.28% (99 runs sampled)
* npm/dedupe#arrays x 326,192 ops/sec ±0.32% (99 runs sampled)
> Fastest is local/dedupe#arrays
Someone might say "wow, looks like performance boost", but the local version is the same 2.2.5 as in npm, no changes were made after git clone
&& npm install
.
My Webpack build logs the following warning:
WARNING in ./~/classNames/index.js
There is another module with an equal name when case is ignored.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Rename module if multiple modules are expected or use equal casing if one module is expected.
I checked the webpack repo and they have a related issue #382
I use ES2015 module syntax as follows:
import classNames from 'classnames';
I quickly checked your code and found two possible parts causing this warning:
classNames
vs. classnames
I use scss and classnames, but I find it doesn't work ,does classnames support scss?
Can you please share an example how to use it when we are not using node server.
Thanks
Hello.
I am building most of my frontend libs with rollupjs and single non-convertable library is this one. Is it possible to have a separate version with es2015 modules exports? I can create PR if you tell me your preference about handling and support.
Thanks.
Say I have grid styles - I do not want this to be packaged with every component - any thoughts on how to approach this
I have the following code
function renderSuggestion(suggestion, { query }) {
return (
<Link to={suggestion.url} target="_self">
<div>{suggestion.title}</div>
<div className={cx("suggestionSubtitle")}>{suggestion.subtitle}</div>
</Link>
);
}
function renderSectionTitle(section) {
return (
<div>
<span className={cx(getIconForSection(section.title) + ' font16')}></span>
<span className={cx("sectionIcon")}><strong> {section.title}</strong></span>
</div>
);
}
The first function the cx renders correctly with the prefix the second one, renders just what is in the quotes.
What am I doing wrong?
Would you consider adding an example of PropTypes
that work with this lib to the README?
This could be very useful for someone making low-level components that use classnames
, that can get passed anything compatible by a higher component.
An example might be:
import { PropTypes } from 'react'
import classNames from 'classnames'
export const classname = PropTypes.oneOfType([
PropTypes.object,
PropTypes.string,
PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.array,
PropTypes.bool,
PropTypes.object,
PropTypes.string
])
)
])
const Foo = ({ className }) => (
<div className={classNames(className)} />
)
Foo.propTypes = {
className: classname
}
I can PR for this if it seems like a good idea.
Is the following possible? I cannot seem to get it to work.
let inputClasses = classNames.bind(inputStyles);
let labelClasses = classNames.bind(labelStyles);
let inputClassList = inputClasses({
inputField: true,
preValidated: this.state.focused,
});
let validationMessageClassList = labelClasses({
errorLabel: true,
postValidated: !this.state.focused,
});
<TextInput className={inputClassList} />
<ErrorLabel className={validationMessageClassList} />
For some reason, the styles appear in React Dev Tools, but not in the DOM.
Look for postValidate
in the following screenshots. It only appears in RDT.
current format: class-a class-b
selector format: .class-a.class-b
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.