Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing in class names to react components

People also ask

Can we give className to a component in React?

To add the className prop to a component with React and TypeScript, we can add the React. HTMLAttributes type into our prop type. to set the prop type of MyComponent to MyProps & React.

Can you add a className to a component?

To do this, first we need to add a prop name to the <Button> component. Now, inside an App component we can pass a classname to the Button component using cname prop. Sometimes, there is a default classname in Button component and we need to pass extra classname from an App component.

Is it possible to set a className on custom React components?

You can, but you should propagate the prop to the inner component.


In React, when you want to pass an interpreted expression, you have to open a pair of curly braces. Try:

render () {
  return (
    <button className={`pill ${ this.props.styleName }`}>
      {this.props.children}
    </button>
  );
}

Using the classnames npm package

import classnames from 'classnames';

render() {
  return (
    <button className={classnames('pill', this.props.styleName)}>
      {this.props.children}
    </button>
  );
}

Just for the reference, for stateless components:

// ParentComponent.js
import React from 'react';
import { ChildComponent } from '../child/ChildComponent';

export const ParentComponent = () =>
  <div className="parent-component">
    <ChildComponent className="parent-component__child">
      ...
    </ChildComponent>
  </div>

// ChildComponent.js
import React from 'react';

export const ChildComponent = ({ className, children }) =>
  <div className={`some-css-className ${className}`}>
    {children}
  </div>

Will render:

<div class="parent-component">
  <div class="some-css-className parent-component__child">
    ...
  </div>
</div>

pill ${this.props.styleName} will get "pill undefined" when you don't set the props

I prefer

className={ "pill " + ( this.props.styleName || "") }

or

className={ "pill " + ( this.props.styleName ? this.props.styleName : "") }

For anyone interested, I ran into this same issue when using css modules and react css modules.

Most components have an associated css module style, and in this example my Button has its own css file, as does the Promo parent component. But I want to pass some additional styles to Button from Promo

So the styleable Button looks like this:

Button.js

import React, { Component } from 'react'
import CSSModules from 'react-css-modules'
import styles from './Button.css'

class Button extends Component {

  render() {

    let button = null,
        className = ''

    if(this.props.className !== undefined){
        className = this.props.className
    }

    button = (
      <button className={className} styleName='button'>
        {this.props.children}
      </button>
    )

    return (
        button
    );
  }
};

export default CSSModules(Button, styles, {allowMultiple: true} )

In the above Button component the Button.css styles handle the common button styles. In this example just a .button class

Then in my component where I want to use the Button, and I also want to modify things like the position of the button, I can set extra styles in Promo.css and pass through as the className prop. In this example again called .button class. I could have called it anything e.g. promoButton.

Of course with css modules this class will be .Promo__button___2MVMD whereas the button one will be something like .Button__button___3972N

Promo.js

import React, { Component } from 'react';
import CSSModules from 'react-css-modules';
import styles from './Promo.css';

import Button from './Button/Button'

class Promo extends Component {

  render() {

    return (
        <div styleName='promo' >
          <h1>Testing the button</h1>
          <Button className={styles.button} >
            <span>Hello button</span>
          </Button>
        </div>
      </Block>
    );
  }
};

export default CSSModules(Promo, styles, {allowMultiple: true} );

As other have stated, use an interpreted expression with curly braces.

But do not forget to set a default.
Others has suggested using a OR statement to set a empty string if undefined.

But it would be even better to declare your Props.

Full example:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Pill extends Component {

  render() {

    return (
      <button className={`pill ${ this.props.className }`}>{this.props.children}</button>
    );
  }

}

Pill.propTypes = {
  className: PropTypes.string,
};

Pill.defaultProps = {
  className: '',
};

You can achieve this by "interpolating" the className passed from the parent component to the child component using this.props.className. Example below:

export default class ParentComponent extends React.Component {
  render(){
    return <ChildComponent className="your-modifier-class" />
  }
}

export default class ChildComponent extends React.Component {
  render(){
    return <div className={"original-class " + this.props.className}></div>
  }
}

In Typescript you need to set types of HTMLAttributes and React.FunctionComponent.

In most cases you will need will be extending it to another interface or type.

const List: React.FunctionComponent<ListProps &
  React.HTMLAttributes<HTMLDivElement>> = (
  props: ListProps & React.HTMLAttributes<HTMLDivElement>
) => {
  return (
    <div className={props.className}>
      <img className="mr-3" src={props.icon} alt="" />
      {props.context}
    </div>
  );
};

interface ListProps {
  context: string;
  icon: string;
}