Skip to main content
  1. « Go back to Articles

Conditionally wrapping components in React

Image of the Wrap component

Sometimes, we want to wrap a React component in another component if a certain condition is true, and not if the condition is false. One such situation might be when a text is a clickable link if an URL is present, or else just plain text.

One way to implement this requirement could look like that:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import { type FunctionComponent } from 'react'

type LinkProps = {
  label: string
  url?: string
}

export const Link: FunctionComponent<LinkProps> = ({ label, url }) => {
  if (url) {
    return (
      <a href={url} className="link-classname">
        <span className="text-classname">{label}</span>
      </a>
    )
  }

  return <span className="text-classname">{label}</span>
}

In this example, we only needed to duplicate the <span className="text-classname" /> component, but in more complex situations, the amount of code that would be duplicated can be forbiddingly huge. We want a more generic solution for this issue, some kind of Wrap component that would allow rewriting the code from above as follows:

1
2
3
4
5
6
7
8
export const Link: FunctionComponent<LinkProps> = ({ label, url }) => {
  const hasUrl = Boolean(url)
  return (
    <Wrap when={hasUrl} wrapper={<a href={url} className="link-classname" />}>
      <span className="text-classname">{label}</span>
    </Wrap>
  )
}

So let’s do it! Here is how I implemented the Wrap component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {
  cloneElement,
  isValidElement,
  type FunctionComponent,
  type PropsWithChildren,
  type ReactNode,
} from 'react'

type WrapProps = PropsWithChildren<{
  when: boolean
  wrapper: ReactNode
}>

export const Wrap: FunctionComponent<WrapProps> = ({
  when,
  wrapper,
  children,
}) => {
  if (when && isValidElement(wrapper)) {
    return cloneElement(wrapper, wrapper.props, children)
  }

  return <>{children}</>
}

The lesser-known isValidElement and cloneElement functions from the React API have been declared as Legacy since the release of React 18, which means they are not recommended for use in newly written code. However, as of today, they are not marked for removal in a future major version of React.

Dr. Ole Hüter
Author
Dr. Ole Hüter
Freelance Full Stack Web Developer