1

I'm wondering how to add additional class name to a custom React component, like a Button. So far I've tried with a traditional way of using class1 ${class2} and even classnames but it's not successful.

Here's my sample to my attempt: https://codesandbox.io/s/1zp7m2yv3

import React from "react";
import ReactDOM from "react-dom";
import classNames from "classnames";
import "./styles.css";

const ButtonTest = props => {
  // const className = `button is-testing is-gradient ${props.className ? props.className : ''}`;
  const className = classNames(
    "button is-testing is-gradient cv",
    props.className
  );
  console.log("a:", className);

  if (props.href) {
    return (
      <a href={props.href} className={className} {...props}>
        {props.children}
      </a>
    );
  }

  return (
    <button className={className} {...props}>
      {props.children}
    </button>
  );
};

function App() {
  return (
    <div className="App">
      <ButtonTest href="https://google.vn">BUTTON LINK</ButtonTest>
      <ButtonTest className="aaa is-block">DEFAULT</ButtonTest>
      <ButtonTest href="https://google.vn" className="is-block dfdfdf">
        BUTTON LINk - FULL
      </ButtonTest>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Thanks, D

2
  • Can you please describe your issue indetail? Commented Jan 26, 2019 at 10:35
  • the issue is when I try to add more classes, it seems like the defined classes button is-testing is-gradient cv is replaced by newer ones, the expected result in my sample is all the Button component should have a border around, because of the .is-testing in CSS Commented Jan 26, 2019 at 10:39

1 Answer 1

3

That happens because you are spreading the props after giving the className attribute to your components.

So <ButtonTest className="aaa is-block">DEFAULT</ButtonTest> will try to render

<button className={className} {...props}> 

which expands to

<button className={className} className={"aaa is-block"}>

and the last same-named attribute is what prevails.

You can invert the order and use

<button {...props} className={className} >

so that the spread props will be overridden by any custom props you pass.

See https://codesandbox.io/s/oqvy6qp56z


Or you could extract the props you want to directly use so that the props only holds the rest

Like

const ButtonTest = ({className:passedClasses, ...props}) => {
  const className = classNames(
    "button is-testing is-gradient cv",
    passedClasses
  );
  console.log("a:", className);

  if (props.href) {
    return (
      <a href={props.href} className={className} {...props}>
        {props.children}
      </a>
    );
  }

  return (
    <button className={className} {...props}>
      {props.children}
    </button>
  );
};

See https://codesandbox.io/s/l7ro16wqz9

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your quick and clear explanation, shame on me for didn't notice the order I put my the ...props in the first place. The second suggestion is something new to me, and will give it a try. Big thanks to you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.