DEV Community

Cover image for Understanding the "Element" React Component: A Flexible Approach to Conditional Rendering
Serif COLAKEL
Serif COLAKEL

Posted on

Understanding the "Element" React Component: A Flexible Approach to Conditional Rendering

When working with React, developers often encounter scenarios where they need to conditionally render elements based on certain conditions. The provided Element component aims to simplify this process by introducing a flexible and intuitive approach to conditional rendering.

The Problem

When working with React, developers often encounter scenarios where they need to conditionally render elements based on certain conditions. For example, a developer may want to render a button only if a user is logged in. Or, a developer may want to render a form only if a user is logged out.

In these scenarios, developers often use conditional rendering strategies such as the && operator or the ternary operator. While these strategies are effective, they can be difficult to read and maintain. For example, the following code snippet uses the && operator to conditionally render a button:

import React from 'react';

export default function Usage() {
  const isLoggedIn = true;

  return (
    <div>
      {/* ✅ Button will be rendered if isLoggedIn is true */}
      {isLoggedIn && <button>Logout</button>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

While this approach is effective, it can be difficult to read and maintain. For example, the following code snippet uses the ternary operator to conditionally render a form:

import React from 'react';

export default function Usage() {
  const isLoggedIn = true;

  return (
    <div>
      {/* ✅ Form will be rendered if isLoggedIn is true */}
      {isLoggedIn ? (
        <form>
          <input type="text" />
          <input type="password" />
          <button>Login</button>
        </form>
      ) : null}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The Element component aims to simplify this process by introducing a flexible and intuitive approach to conditional rendering. It leverages TypeScript to provide a type-safe interface and improve code clarity.

Overview - Element Component

The Element component is a React component that allows developers to conditionally render elements based on specific conditions. It leverages TypeScript to provide a type-safe interface and improve code clarity.

import React, { ComponentProps } from 'react';

type ElementBaseProps<T extends keyof HTMLElementTagNameMap> =
  | {
      as: T;
      /**
       * If `true`, the element will be rendered. If `false`, the element will not be rendered.
       */
      rcIf?: boolean;
      /**
       * If has `rcIf` you can't use `rcElse`.
       */
      rcElse?: never;
    }
  | {
      as: T;
      /**
       * If has `rcElse` you can't use `rcIf`.
       */
      rcIf?: never;
      /**
       * If `true`, the element will not be rendered. If `false`, the element will be rendered.
       */
      rcElse?: boolean;
    };

type ElementProps<T extends keyof HTMLElementTagNameMap> = ElementBaseProps<T> &
  ComponentProps<T>;

export function Element<T extends keyof HTMLElementTagNameMap>({
  as,
  children,
  rcIf = true,
  rcElse = false,
  ...props
}: ElementProps<T>) {
  if (rcIf === false || rcElse === true) {
    return null;
  }

  return React.createElement(as, props as ComponentProps<T>, children);
}

export default Element;
Enter fullscreen mode Exit fullscreen mode

Element Props

The Element component accepts the following props:

  • as: The HTML tag name of the element to be rendered.

  • rcIf: If true, the element will be rendered. If false, the element will not be rendered. If rcElse is provided, rcIf cannot be used, and vice versa.

  • rcElse: If true, the element will not be rendered. If false, the element will be rendered. If rcIf is provided, rcElse cannot be used, and vice versa.

  • children: The children of the element. This can be a string, a React element, or an Array of React elements.

Element Usage

The Element component can be used to conditionally render elements based on specific conditions. It can be used in the following ways:

import React from 'react';
import Element from './Element';

export default function Usage() {
  return (
    <Element as="main">
      {/* ✅ Element Component as a with all props */}
      <Element as="a" href="https://www.google.com" target="_blank">
        Google
      </Element>
      {/* ✅ Element Component as h1 with all props */}
      <Element rcIf as="h1">
        Hello, World!
      </Element>
      {/* ✅ Element Component as section with all props */}
      <Element as="section" rcIf={false}>
        Hello, World!
      </Element>
      {/* ✅ Element Component as span with all props */}
      <Element rcElse as="span">
        Hello, World!
      </Element>
      {/* ❌ You can't use rcIf and rcElse together */}
      <Element rcIf as="h4" rcElse={false}>
        Hello, World!
      </Element>
      {/* ✅ Element Component as Input */}
      <Element as="input" type="color" />
      <Element as="input" type="date" />
      <Element as="input" type="datetime-local" />
      <Element as="input" type="email" />
      <Element as="input" type="file" />
      <Element as="input" type="month" />
      <Element as="input" type="number" />
      <Element as="input" type="password" />
      <Element as="input" type="radio" />
      <Element as="input" type="range" />
      <Element as="input" type="search" />
      <Element as="input" type="tel" />
      <Element as="input" type="text" />

      {/* ✅ Element Component as div with inline style */}
      <Element
        as="div"
        style={{
          display: 'flex',
          flexDirection: 'column',
          gap: '10px',
          height: '30vh',
          overflowY: 'auto',
        }}
      >
        {todos.map((todo) => {
          return (
            <Element as="div" key={todo.id}>
              <Element as="input" checked={todo.completed} type="checkbox" />
              <Element as="h2">{todo.title}</Element>
              <Element as="p">
                {todo.completed ? 'Completed' : 'Not completed'}
              </Element>
            </Element>
          );
        })}
      </Element>
    </Element>
  );
}
Enter fullscreen mode Exit fullscreen mode

Features

  • Type Safety: The Element component is built with TypeScript, which allows it to provide a type-safe interface. This helps reduce the risk of unexpected bugs and improves code clarity.

  • Ease of Use: The Element component is easy to use. It provides a straightforward API that allows developers to conditionally render elements based on specific conditions.

  • Flexibility: The Element component is flexible. It can be used to render elements based on a single condition or multiple conditions.

  • Exclusive Usage: If rcIf is provided, rcElse cannot be used, and vice versa. This ensures that only one conditional rendering strategy is employed for each instance of the Element component.

Drawing Inspiration from Angular and Vue

The conditional rendering approach implemented in the Element component draws inspiration from similar concepts in Angular and Vue. Angular developers are familiar with the *ngIf directive, while Vue developers often use the v-if and v-else directives. The Element component adopts a similar philosophy, providing a concise and readable way to conditionally render elements in React.

Conclusion

The Element component is a React component that allows developers to conditionally render elements based on specific conditions. It leverages TypeScript to provide a type-safe interface and improve code clarity.

Feel free to incorporate the Element component into your React projects to simplify conditional rendering and improve the overall maintainability of your codebase.

Thanks for reading! Happy coding!

Top comments (10)

Collapse
 
eitanavgil profile image
Eitan • Edited

I am not arguing about this technique, but it makes your code unreadable. Having a generic Element with 'as' type makes the code less intuitive and cumbersome. You are trying to solve a problem that is not that of an issue, and on the way you are making the code less readable to other developers. React developers should know to read JSX with conditional rendering. If you wish to make it cleaner, add a boolean const above the JSX (e.g. const showForm...) and don't add long or complex logic to the JSX.

Collapse
 
kornelijepetak profile image
Kornelije Petak

I disagree about react devs should know how to read conditional rendering. It very quickly becomes unreadable and is a norm on the internet only because self taught developers who couldn't care less about readability proliferated in recent years.

Lifting conditional renders outside of jsx and putting only properly named variables into jsx the only readable way. It keeps jsx as simple as possible (and semantically as close to markup as possible).

Collapse
 
serifcolakel profile image
Serif COLAKEL

I understand but i like see other frameworks approach in react, thank you for feedback :)

Collapse
 
nt222 profile image
NT222 • Edited

There are discussions about this topic. Your solution is unreadable and having hidden problems. It does not work for this code:

<Element as="section" rcIf={obj}>
        { obj.title}
</Element>
Enter fullscreen mode Exit fullscreen mode

This is best package for [React control statements components] now: npmjs.com/package/reloc

Collapse
 
serifcolakel profile image
Serif COLAKEL

Thank you for your feedback :)

Collapse
 
floony7_87 profile image
Fred Lunjevich

Yeah, not convinced this a solution to anything really. I've written some nasty conditionals but in refactoring I just lifted it out of the jsx. Most cases, however, it isn't really an issue.

Collapse
 
iamfoxx profile image
jerry Almeida

Good idea, but....

Collapse
 
serifcolakel profile image
Serif COLAKEL • Edited

Thank you for your feedback, but??

Collapse
 
multani9900 profile image
Multani

I'm not quarreling over this method, but rather it makes your code garbled. Having a conventional Component with 'as' type makes the code less instinctive and unwieldy. You are attempting to take care of an issue that isn't that of an issue, and on the manner in which you are making the code less meaningful to different designers. Respond designers ought to be aware to peruse JSX with restrictive delivering.

There are conversations about this point. Your answer is confused and having stowed away issues.

Collapse
 
eitanavgil profile image
Eitan

Gee... This is the 1st comment with GPT interpretation. We got to a point that even comments are GPT generated just for the sake of commenting something?
Multani, a wise man once said "if you don't have anything to say, just be quiet".