Workaround to add className to Fragment in React
Asked Answered
T

4

30

I am trying to create a stateless component in React with the sole purpose of acting as a reusable wrapper. I am also using CSS Modules because I want to have fully modular CSS.

The thing is I don't want to add unnecessary elements (and even more so <div>s), but instead I want to use React's Fragments.

Now, the problem I have is Fragment (at least for now) do not accept classNames. So if I try this:

// In Wrapper.js:

import React, { Fragment } from 'react'
import styles from './Wrapper.css'

const wrapper = (props) => (
    <Fragment className={styles.wrapper}>
        {props.children}
    </Fragment>
)

export default wrapper

In (for example) Navbar.js:

import React from 'react'
import styles from './Navbar.css'
import Wrapper from '../../Layout/Wrapper'

const navBar = (props) => (
    <nav className={styles.navBar}>
        <Wrapper>
            This is the site's main navigation bar.
        </Wrapper>
    </nav>
)

export default navBar

Now I can of course, use a div instead of the Fragment, but is there any other workaround to avoid using unnecessary markup, of which I am totally unaware of?

Theft answered 2/3, 2018 at 13:6 Comment(2)
Why not use a <div> instead of a fragment? I haven't used fragments yet but it is my understanding that they are just for wrapping a group of components in JSX but doesn't actually render a wrapping element in the dom. Where as a div will actually wrap the elements in a div. Correct me if I'm wrong though...Fore
If you want a className, this className will have to apply to an element, no ? And Fragments do not render any element, so you can't use a className with it.Nubilous
N
64

Fragments let you group a list of children without adding extra nodes to the DOM. - https://reactjs.org/docs/fragments.html

What Fragments tries to solve it's the unnecessary dom elements but this doesn't mean that Fragments will replace div entirely. If you need to add a className there, it's clear that either you add a dom element in this case another div or add the className to its parent.

Noumenon answered 2/3, 2018 at 13:29 Comment(0)
H
17

Using Fragment means not adding an extra node to DOM.

If you want to assign a className to a node then you'll have to use div.

Herbherbaceous answered 2/3, 2018 at 13:45 Comment(0)
F
5
  1. Create a css file and import it inside your App.js
  2. Create a higher order component withClass.js like below

    import React from  'react';
    
    const withClass = (WrappedComponent, className) => {
        return props => (
            <div className={className}>
                <WrappedComponent {...props} />
            </div>
        );
    };
    
    export default withClass;
  1. Import your hoc too.
  2. In your App.js write something like below

    <React.Fragment>
        <p>Some JSX code here</p>
    <React.Fragment>
    
    export default withClass(App, classes.App);

I created .App class inside my css file and imported it so that i can use it later with classes.App. This way you can apply any css class that you create inside your css.You can use the same wrapperComponent to wrap every component you have, by simply importing it and changing export in your component. You just have to make classname of your choice and use it in export statement of your component. When you write props with spread operator(...). All the props from your component will be passed to this wrapperComponent.

Fino answered 24/12, 2019 at 13:16 Comment(0)
L
0

So the only thing the Wrapper / Fragment does is acting as a CSS wrapper over the children of nav?

I am not very experienced with css-modules, but if I wanted to avoid an extra DOM node just for the className I'd use something like this to get both classNames applied to <nav>:

import React from 'react'
import navStyles from './Navbar.css'
import wrapperStyles from './Wrapper.css'

const navBar = (props) => (
    <nav className={`${navStyles.navBar} ${wrapperStyles.wrapper}`}>
       This is the site's main navigation bar.
    </nav>
)

export default navBar
Levison answered 2/3, 2018 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.