56

How does one pass a prop without value to a react component?

<SomeComponent disableHeight> {/* here */}
    {({width}) => (
        <AnotherComponent
            autoHeight {/* and here */}
            width={width}
            height={300}
            {...otherProps}
        />
    )}
</SomeComponent>

Note - there is no default prop values specified for those props.

I can't seem to find any references on that, but by observing values for those properties they get assigned to true by default.

Chris
  • 57,622
  • 19
  • 111
  • 137
code-jaff
  • 9,230
  • 4
  • 35
  • 56

3 Answers3

98

What you are passing is interpreted by the compiler as a boolean attribute. This is also true for when writing pure HTML; attributes without values are interpreted as a boolean true. Since JSX is a syntactic-sugar for writing HTML, it makes sense that it has the same behavior.

The official React documentation has the following:

Boolean Attributes

This often comes up when using HTML form elements, with attributes like disabled, required, checked and readOnly. Omitting the value of an attribute causes JSX to treat it as true. To pass false an attribute expression must be used.

// These two are equivalent in JSX for disabling a button

<input type="button" disabled />;
<input type="button" disabled={true} />;

// And these two are equivalent in JSX for not disabling a button

<input type="button" />;
<input type="button" disabled={false} />;

Example

JSX:

<div>
  <Component autoHeight />
  <AnotherComponent autoHeight={null} />
</div>

JS:

React.createElement(
  "div",
  null,
  React.createElement(Component, { autoHeight: true }),
  React.createElement(AnotherComponent, { autoHeight: null })
);

Check the babel demo of this, here.


Solution

As ctrlplusb stated, if you want to pass an "empty prop" you can simply give it the value of null or even undefined.

So you could do:

<SomeComponent disableHeight={null}>
    {({width}) => (
        <AnotherComponent
            autoHeight={null}
            width={width}
            height={300}
            {...otherProps}
        />
    )}
</SomeComponent>

Though I will note that passing it as undefined is probably entirely unnecessary because reading this.props.autoHeight from AnotherComponent will always give you undefined, regardless if you explicitly passed it as autoHeight={undefined} or not at all. Passing null is probably better in such cases since you are explicitly passing the prop by stating that it has the value of... "no value" (i.e null).

Chris
  • 57,622
  • 19
  • 111
  • 137
  • 1
    I completely missed that part of the document as I thought it's only for boolean attribs like `disabled`, `required`, etc... Thanks for the clarification. – code-jaff Jun 15 '16 at 07:55
  • 1
    Please take care not to mix up HTML attributes and the properties of DOM's `HTMLElement` interface. React DOM works with directly with the element _property_, which indeed is a boolean, set as `true`/`false`. But a so-called HTML "boolean attribute" cannot have a value of true. It can be missing to indicate _false_, or to indicate _true_, it can be present with either no value, an empty value, or "a value that is an ASCII case-insensitive match for the attribute's canonical name, with no leading or trailing whitespace." JSX has its own third set of rules, which have been quoted correctly. – AndrewF Aug 08 '18 at 03:09
  • @AndrewF I think the point that this post tries to emphasize is that JSX tries to mimic HTML as much as possible. This is an answer to a fairly novice question and there is no need to over-complicate this with such a thorough explanation. HTML is not a programming language, so booleans and other types don't make sense there anyway. Your comment is appreciated but any experienced developers out there can probably read between the lines without issue. – Chris Aug 16 '18 at 11:26
  • 1
    JSX mimics HTML markup in some ways, the HTML DOM interfaces in other ways. I don't believe developers easily "read between lines" on this subject. The relationship between markup and the DOM API is a common source of confusion. Misconception: "booleans and other types don't make sense there". DOM API uses strong typing (which does manifest in JS), and the HTML spec itself defines "boolean attribute" along with how it maps to the (strictly boolean) DOM interface properties. The nuance around typing & flow of HTML/DOM data is important for many, certainly enough to warrant an addendum comment. – AndrewF Aug 17 '18 at 23:20
  • @AndrewF, Right, but I am making no reference to the DOM api at all. The only comparison done here is between JSX props and Element attributes, nothing else. I feel like this is going off context... – Chris Aug 17 '18 at 23:33
  • If you don't define a prop its value should be "undefined" not "null" right? – Rob Evans Jan 24 '19 at 11:34
  • 1
    @RobEvans, oops. Yes, you are 120% correct. I'll fix it right away! Thanks. – Chris Jan 24 '19 at 15:07
12

Yeah JSX sees properties without a = as being a boolean true.

One option is to simply set null values:

<Foo name="Bob" surname={null} />

You could also dynamically build a property bag via an object and only add the properties if required. For example:

render() {
  const propBag = {
    width: width,
    height: 300
  };
  if (someCondition) {
    propBag.something = 'bob';
  }

  return (
    <FooComponent {...propBag} {..otherProps} />
  );
}
ctrlplusb
  • 12,847
  • 6
  • 55
  • 57
4

TL;DR: Set empty string:

<Amp.AmpAccordion animate="">

Explanation

A copy+paste from the link above:

Any attribute with an empty string will render into the DOM without a value.

W3C relevant documentation: https://www.w3.org/TR/html5/syntax.html#elements-attributes

Empty attribute syntax
Just the attribute name. The value is implicitly the empty string.

In the following example, the disabled attribute is given with the empty attribute syntax:

<input disabled>

If an attribute using the empty attribute syntax is to be followed by another attribute, then there must be a space character separating the two.

ghashi
  • 1,497
  • 1
  • 13
  • 17