How Do I Conditionally Add Attributes to React Components?
Is There a Way to Only Add Attributes to a React Component If a Certain Condition Is Met? I'm Supposed to Add Required and readOnly Attributes to Form Elements...
Is there a way to only add attributes to a React component if a certain condition is met?
I'm supposed to add required and readOnly attributes to form elements based on an Ajax call after render, but I can't see how to solve this since readOnly="false" is not the same as omitting the attribute completely.
The example below should explain what I want, but it doesn't work.
(Parse Error: Unexpected identifier)
function MyInput({isRequired}) {
return <input classname="foo" {isRequired ? "required" : ""} />
}
21 Answers
Apparently, for certain attributes, React is intelligent enough to omit the attribute if the value you pass to it is not truthy. For example:
const InputComponent = function() {
const required = true;
const disabled = false;
return (
<input type="text" disabled={disabled} required={required} />
);
}
will result in:
<input type="text" required>
Update: if anyone is curious as to how/why this happens, you can find details in ReactDOM's source code, specifically at lines 30 and 167 of the DOMProperty.js file.
juandemarco's answer is usually correct, but here is another option.
Build an object how you like:
var inputProps = {
value: 'foo',
onChange: this.handleChange
};
if (condition) {
inputProps.disabled = true;
}
Render with spread, optionally passing other props also.
<input
value="this is overridden by inputProps"
{...inputProps}
onChange={overridesInputProps}
/>
Here is an example of using Bootstrap's Button via React-Bootstrap (version 0.32.4):
var condition = true;
return (
<Button {...(condition ? {bsStyle: 'success'} : {})} />
);
Depending on the condition, either {bsStyle: 'success'} or {} will be returned. The spread operator will then spread the properties of the returned object to Button component. In the falsy case, since no properties exist on the returned object, nothing will be passed to the component.
An alternative way based on Andy Polhill's comment:
var condition = true;
return (
<Button bsStyle={condition ? 'success' : undefined} />
);
The only small difference is that in the second example the inner component <Button/>'s props object will have a key bsStyle with a value of undefined.
Here is an alternative.
var condition = true;
var props = {
value: 'foo',
...(condition && { disabled: true })
};
var component = <div {...props} />;
Or its inline version
var condition = true;
var component = (
<div value="foo" {...(condition && { disabled: true })} />
);
Here's a way I do it.
With a conditional:
<Label
{...{
text: label,
type,
...(tooltip && { tooltip }),
isRequired: required
}}
/>
I still prefer using the regular way of passing props down, because it is more readable (in my opinion) in the case of not have any conditionals.
Without a conditional:
<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Let’s say we want to add a custom property (using aria-* or data-*) if a condition is true:
{...this.props.isTrue && {'aria-name' : 'something here'}}
Let’s say we want to add a style property if a condition is true:
{...this.props.isTrue && {style : {color: 'red'}}}
You can use the same shortcut, which is used to add/remove (parts of) components ({isVisible && <SomeComponent />}).
class MyComponent extends React.Component {
render() {
return (
<div someAttribute={someCondition && someValue} />
);
}
}
If you use ECMAScript 6, you can simply write like this.
// First, create a wrap object.
const wrap = {
[variableName]: true
}
// Then, use it
<SomeComponent {...{wrap}} />
This should work, since your state will change after the Ajax call, and the parent component will re-render.
render : function () {
var item;
if (this.state.isRequired) {
item = <MyOwnInput attribute={'whatever'} />
} else {
item = <MyOwnInput />
}
return (
<div>
{item}
</div>
);
}
Using undefined works for most properties:
const name = "someName";
return (
<input name={name ? name : undefined} />
);
For example using property styles for custom container
const DriverSelector = props => {
const Container = props.container;
const otherProps = {
...( props.containerStyles && { style: props.containerStyles } )
};
return (
<Container {...otherProps} >
- For some boolean attributes listed by React [1]:
<input disabled={disabled} />
// renders either `<input>` or `<input disabled>`
- For other attributes:
<div aria-selected= {selected ? "" : undefined} />
// renders either `<div aria-selected></div>` or `<div></div>`
[1] The list of boolean attributes:
In React you can conditionally render Components, but also their attributes, like props, className, id, and more.
In React it's very good practice to use the ternary operator which can help you conditionally render Components.
An example also shows how to conditionally render Component and its style attribute.
Here is a simple example:
class App extends React.Component {
state = {
isTrue: true
};
render() {
return (
<div>
{this.state.isTrue ? (
<button style={{ color: this.state.isTrue ? "red" : "blue" }}>
I am rendered if TRUE
</button>
) : (
<button>I am rendered if FALSE</button>
)}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src=""></script>
<script src=""></script>
<div id="root"></div>
From my point of view the best way to manage multiple conditional props is the props object approach from @brigand. But it can be improved in order to avoid adding one if block for each conditional prop.
The ifVal helper
rename it as you like (iv, condVal, cv, _, ...)
You can define a helper function to return a value, or another, if a condition is met:
// components-helpers.js
export const ifVal = (cond, trueValue=true, falseValue=null) => {
return cond ? trueValue : falseValue
}
If cond is true (or truthy), the trueValue is returned - or true.
If cond is false (or falsy), the falseValue is returned - or null.
These defaults (true and null) are, usually the right values to allow a prop to be passed or not to a React component. You can think to this function as an "improved React ternary operator". Please improve it if you need more control over the returned values.
Let's use it with many props.