27

I'm trying to clarify some confusion I have about boolean props in React.

Suppose a have MyComponent with several boolean props prop1, prop2...

First: it seems that boolean props are like just others: you can define default values, either in defaultProps or in destructuring params:

const MyComponent = ({ prop1, prop2 }) => (
   ...
);

MyComponent.defaultProps = {
  prop1: false,
  prop2: true,
}

Or (equivalently... I think)

const MyComponent = ({ prop1 = false, prop2 = true }) => (
 ...
) 

What's not clear is how to pass values. The natural "React style", again, seems to be

  <MyComponent prop1={ BOOLEAN_EXPRESION1 } prop2={ BOOLEAN_EXPRESION2 } />

... including the static literals (false/true).

However, it's also stated that the correct (recommended?) way to pass boolean properties is presence/absence of the attribute, as in HTML5.

So that, instead of <MyComponent prop1={true} prop2={false} />, one should write <MyComponent prop1 />.


My questions are:

  1. What is the correct way of passing boolean props? Are both acceptable?

  2. In case HTML5 style is the recommended (or correct) way, how would one deal with dynamic values?

  3. In case HTML5 style is acceptable, what about default values? In the example above (where prop2 is true by default), if I write <MyComponent />, what value would prop2 get?


Edit: To the accepted answer, I'd like to add my own tip: to play along nicely with the HTML5 style (and to prevent surprises), design your boolean props so that they are by default false. Put in other way: a boolean prop that defaults to true should be considered an antipattern.

Edit 2: It should be noted that sometimes the default of a boolean prop is undefined and that's (by design) treated differently than false, (eg: in Material UI's Checkbox the prop checked is true|false if the component is controlled, undefined if it's uncontrolled). Hence here the HTML5 convention cannot be used.

leonbloy
  • 73,180
  • 20
  • 142
  • 190
  • See how react documentation handles [boolean props](https://reactjs.org/docs/forms.html#handling-multiple-inputs) for check boxes. I would not recommend html5 style because your default value only works if default is false. JSX is not html5 – HMR Mar 23 '20 at 15:49
  • @HMR That was my impression, but it does not seem to be discouraged in any doc, nor in eslinter, and the linked answer has 42 upvotes... – leonbloy Mar 23 '20 at 15:59
  • If SO upvotes is an "authority" then [the chosen answer](https://stackoverflow.com/a/39326442/1641941) has 99 upvotes. I'd stick with react documentation, have not seen a html5 example of setting boolean prop in React documentation. – HMR Mar 23 '20 at 16:13
  • 2
    Here is the point to remember, OP: JSX is not html5 – D. Richard Mar 23 '20 at 16:47
  • @leonbloy, because both ways are acceptable in the case of passing `true`, I personally turn on the ESLint rule jsx-boolean-value because of the style guide I use uses it. My preferred guide emphasizes on readability such as avoiding classic for loops in favor of forEach. I do think the HTML5 style of omitting the explicit true is more readable. Because it's only a matter of styling, it should be up to the repo maintainer to decide a consistent styling. – kmui2 Mar 23 '20 at 17:22
  • @kmui2 "the HTML5 style of omitting the explicit true is more readable" But it's also confusing because `` (no prop2) does not mean prop2=false but "default" (which in this case is true). Furthermore, it's impossible to pass "false" in this case, unless you write `` ... which eslint prohibits! – leonbloy Mar 25 '20 at 13:40
  • @D.Richard : "JSX is not html5" That sounds sensible to me. Sadly, that is not clearly stated in React official docs ... and eslint seems to disagree. – leonbloy Mar 25 '20 at 13:42
  • Eslint is just a tool that can be configured in a way that’ll disagree with anything you write. Also, it’s not mentioned in the docs because React has exactly 0 things to do with Html5 – D. Richard Mar 25 '20 at 13:50
  • "React has exactly 0 things to do with Html5" However, it seems to accept `` as equivalent to ``, no? – leonbloy Mar 25 '20 at 13:54
  • 1
    @leonbloy, ok let's just think this differently and disregard rules established by HTML5 and focusing only on JSX. JSX has **exactly two ways of passing true**, `` and `` and **exactly one way of passing false** ``. I do agree this is an oddity distinguishing between HTML5 and JSX, but **JSX is a syntax extension to JavaScript and not HTML** so it does not need to conform to all rules of HTML. – kmui2 Mar 25 '20 at 16:42
  • 1
    FYI, all rules and behavior of JSX is listed in the React docs, and it includes how defaulting to true works (https://reactjs.org/docs/jsx-in-depth.html#props-default-to-true). These docs do not inherit anything from HTML and shouldn't be compared with HTML specs either. – kmui2 Mar 25 '20 at 16:51
  • @kmui2 You might considering adding these last comments into your answer. – leonbloy Mar 25 '20 at 17:03
  • @leonbloy I updated my answer to include my comments. – kmui2 Mar 25 '20 at 17:24

3 Answers3

44

Forenote:

Let's just think this differently and disregard rules established by HTML5 and focusing only on JSX. JSX has exactly two ways of passing true, <MyComponent prop /> and <MyComponent prop={true} /> and exactly one way of passing false <MyComponent prop={false} />. I do agree this is an oddity distinguishing between HTML5 and JSX, but JSX is a syntax extension to JavaScript and not HTML so it does not need to conform to any of the rules of HTML.

From the JSX docs:

This funny tag syntax is neither a string nor HTML.

FYI, all rules and behavior of JSX is listed in React's JSX docs, and it includes how defaulting a prop to true works. Important note: these docs do not inherit anything from HTML and shouldn't be compared with HTML specs either.


Answers:

  1. What is the correct way of passing boolean props?

Passing an explicit true in JSX:

There are exactly two ways to pass an explicit true: passing true and defaulting a prop to true:

<MyComponent prop={true} />
<MyComponent prop />

Note: As stated in the docs, JSX's behavior of defaulting a prop to true is just an added feature that matches with HTML5's boolean attributes behavior.

Passing an explicit false in JSX:

There is exactly one way to pass an explicit false: passing false

<MyComponent prop={false} />

Note: This is where JSX's behavior differ from HTML5's boolean attributes behavior. There is not such thing as defaulting to false in JSX; it is only applicable for passing an explicit true. In contrast to HTML5, if you do not pass anything, you're really passing undefined, and your defined default values will be used instead. This is contrary to the HTML5 specs which would say it's false. Refer to the CodeSandbox link in the answer to #3 for this behavior.

Passing a boolean variable/expression in JSX:

Pass the variable or an expression to the prop:

// via variable
const foo = true;
<MyComponent prop={foo} />
const bar = false;
<MyComponent prop={bar} />

// via expression
<MyComponent prop={Math.random() > 0.5} />

Are both acceptable?

Referring to the way of passing an explicit true vs defaulting a prop to true, they are both acceptable in terms of compiling JSX. However, if you need consistency in a codebase for adhering to a certain style, add the ESLint rule jsx-boolean-value. I personally use the Airbnb JavaScript style which turns that rule on. The guide emphasizes on readability, and so it decided for omitting the explicit true.

  1. In case HTML5 style is the recommended (or correct) way , how would one deal with dynamic values?

Do not use HTML5 style (defaulting props to true) for dynamic values (variables/expressions); use the React way of passing props (explicitly assigning prop values). See above for how to pass those.

  1. Furthermore, in case HTML5 style is acceptable, what about the default values? In the example above (where prop1,prop2 are resp. false/true by default) what would give?

Here are the final values for prop1 and prop2 passed respectively:

MyComponent.defaultProps = {
  prop1: false,
  prop2: true,
}

<MyComponent prop1 />
// prop1 == true
// prop2 == true // defaulted to true

<MyComponent prop1={true} prop2={false} />
<MyComponent prop1 prop2={false} />
// prop1 == true
// prop2 == false

Here is the CodeSandbox link: https://codesandbox.io/s/elated-davinci-izut1?fontsize=14&hidenavigation=1&theme=dark

Note: Not adding an attribute and then not passing a value (such as prop2 in the first example) is the same as passing undefined unlike passing an explicit false for the second example. Therefore, prop2 got defaulted to true.

kmui2
  • 2,227
  • 18
  • 19
  • THanks. This still does not answer my question 3. – leonbloy Mar 23 '20 at 16:33
  • Oh, forgot to mention `prop2`. Sorry – kmui2 Mar 23 '20 at 16:42
  • @leonbloy, I forgot to mention that not defining an attribute and then not defining a value as in `prop2` in the first example is the same as passing undefined unlike false in your second example. Answer has been updated :) – kmui2 Mar 23 '20 at 17:43
1

Let me tell you about passing boolean values

HTML5 Style

<MyComponent
  prop2  // equivalent prop2={true}, works only for static true values
  prop1={false} // You can't do something like that for false though
/>

// example
<Select
  multiSelect // You won't be changing this value throughout the whole life cycle
/>

// They will however transpiled to 
React.createElement(MyComponent, {prop1: false, props2: true}, null)
// So passing true isn't necessarily a must

Default Props

This method isn't any different for boolean than other types

<MyComponent
  title={title} // typeof title = string | undefined | null
  bold={bold} // typeof bold = boolean | undefined | null
/>

// In case title being undefined or null,
// React will take the defaultProps

defaultProps are equivalent to

static defaultProps = {
  title: 'Hello World',
  bold: true
}

props = {
  title: props.title ?? 'Hello World',
  bold: props.bold ?? true
}


// Or in function, it's much simpler and familiar
// Same as old C, if the props are undefined or null,
// default values will be taken, this is plain 'ol JS
const MyComponent = ({title = 'Hello World', bold = true}) => {
  // boop
}


So to summarize and answer your question

  1. What is the correct way of passing boolean props? Are both acceptable?

Yes, both are acceptable. React is un-opinionated, It depends upon which style you're following, AirBnB recommends you to use HTML5 style for passing static true values, while old TypeScript screams at you to change it to props2={true}.

  1. In case, HTML5 style is the recommended (or correct) way, how would one deal with dynamic values?

HTML5 is applicable only for static true values. There's simply no way for you to use dynamic boolean values in HTML5 style.

  1. Furthermore, in case HTML5 style is acceptable, what about the default values? In the example above (where prop2 is true by default), if I write <MyComponent />, what would happen?

<MyComponent /> will be transpiled to React.createElement(MyComponent, {}, null), meaning prop1 and prop2 will be undefined. Given that the default values for prop1 is false while prop2 is true. Their respective default values will be taken.

Pushkin
  • 3,336
  • 1
  • 17
  • 30
-2

Depends on use case. Ever heard of separation of concerns? The same principle apply here. Handle it where it makes sense to handle. You can use variables in a component instead of defaultProps (the React way). If its a switch pass it down from parent.

D. Richard
  • 460
  • 3
  • 12