React JSX conditional rendering of column layout

Viewed 275

I want to have a dynamic rendering of JSX as below;

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon ?
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>
        : null
    }
</ColumnLayout>

Thus, I want that only if "showSubTextAndIcon" is true, then render the subtext and Icon. Now the above does not work and I get a syntax error saying;

Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>

This works if I add a wrapping ColumnLayout. However, that messes my layout when showSubTextAndIcon is true.

{showSubTextAndIcon ?
        <ColumnLayout container spacing={1}>
            <ColumnLayout item xs={2}>                    
                <span>{subText}</span>
            </ColumnLayout>
            <ColumnLayout item xs={1}>
                <Icon  />
            </ColumnLayout>
        </ColumnLayout>
        : null
    }

Note: ColumnLayout is derived from material ui library.

4 Answers

All you need is Fragment, as React is expecting an array or an element as a return:

import React, { Fragment } from 'react';

and just wrap it.


{showSubTextAndIcon &&
       <Fragment>
          <ColumnLayout item xs={2}>                    
              <span>{subText}</span>
          </ColumnLayout>
          <ColumnLayout item xs={1}>
              <Icon  />
          </ColumnLayout>
        </Fragment>
    }

If you want a single condition, you need to wrap your elements, as the error suggests and as you have discovered already. If it breaks your layout, you can either change your CSS, either try with a simple <div> instead of nesting ColumnLayout elements.

Another solution would be adding the same condition to each of the elements you want to show under that condition, like:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon &&
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>}
    {showSubTextAndIcon &&
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>}
</ColumnLayout>

An alternative way of doing it is to wrap components in an array and give them keys:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon && [
        <ColumnLayout item xs={2} key={1}>                    
            <span>{subText}</span>
        </ColumnLayout>,
        <ColumnLayout item xs={1} key={2}>
            <Icon  />
        </ColumnLayout>
    ]}
</ColumnLayout>

You need to enclose it in a fragment as react expects only one element as return:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon ?
       <>
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>
       </>
        :" "
    }
</ColumnLayout>
Related