1

I am trying to build a React Component Library, the Button component takes the following props :

<Button
  kind='primary' //secondary, ghost
  size='large' //small, large
  success
  shape='' //pill
  onClick={() => console.log("**clicked**")}
  >
  Button Click
</Button>

Based on what has been passed to props, I want to render a certain styles, like :

import { Colors } from "../Utils/Colors";
export default function Button({
  children,
  className,
  kind,
  size,
  shape,
  success,
  warning,
  error,
  ...props
}) {
  const btnStyle = {
    boxSizing: "border-box",
    display: "inline-block",
    border: "1px solid black",
    cursor: "pointer",
    borderRadius: shape == "pill" ? "100px" : "0px",
  };

  if (success || "") {
    Object.assign(btnStyle, {
      backgroundColor: Colors.success,
      color: "white",
      border: "1px solid" + Colors.sucess,
    });
  }

  if (warning) {
    Object.assign(btnStyle, {
      backgroundColor: Colors.warning,
      color: "white",
    });
  }
  if (error) {
    Object.assign(btnStyle, { backgroundColor: Colors.error, color: "white" });
  }

  if (kind == "primary") {
    Object.assign(btnStyle, {});
  }
  if (kind == "secondary") {
    Object.assign(btnStyle, {
      backgroundColor: "white",
    });
  }
  if (kind == "ghost") {
    Object.assign(btnStyle, { background: "none", border: "none" });
  }
 
  if (size == "mini") {
    Object.assign(btnStyle, { fontSize: "10px", padding: "4px 10px" });
  }

  if (size == "small") {
    Object.assign(btnStyle, { fontSize: "12px", padding: "6px 20px" });
  }

  if (size == "" || size == "medium") {
    Object.assign(btnStyle, { fontSize: "14px", padding: "8px 24px" });
  }

  if (size == "large") {
    Object.assign(btnStyle, { fontSize: "18px", padding: "10px 34px" });
  }

  if (kind === "default") {
    Object.assign(btnStyle, { color: "pink" });
  }

  return (
    <div>
      <button style={btnStyle} className={`btn ${className}`} {...props}>
        {children}
      </button>
    </div>
  );
}

As we can see, I am pushing a new Object style to btnStyle based on the props, which is certainly not a good way to do this. How can I optimize this?

What I have tried :

1 ) I have tried looking at popular open-source Design System like Base Web, Adobe Spectrum, but couldn't get far as the codebase is very structured.

2 ) I tried storing the styles in an array and pushing along the if-else condition, which is again the same thing.

3 ) Looked at other answers here on SO, found a few ones which only deals with appending CSS styles and variables, not really a component library sort of pattern.

3 ) I tried doing conditional styling in the btnStyle itself like :

borderRadius : ${ type == "pill" ? "10px" : "0px" }

But the above works in a very limited manner and only for two condition which is a problem in the kind prop.

Any helpful suggestion in the right direction will do wonders.

Thank You for reading this far.

1 Answer 1

2

Example:

  • Create a button.module.css file
  • import style from './button.module.css' in Button component

In button.module.css file you have below classes,

.primary,
.success,
.danger,
.warning {
  color: #fff;
}
.primary {
  background-color: blue;
  border-color: darkblue;
}
.primary:hover {
  background-color: darkblue;
}
.success {
  background-color: green;
  border-color: darkgreen;
}
.success:hover {
  background-color: darkgreen;
}
.danger {
  background-color: red;
  border-color: darkred;
}
.danger:hover {
  background-color: darkred;
}
.warning {
  background-color: orange;
  border-color: darkorange;
}
.warning:hover {
  background-color: darkorange;
}

I have four KIND of CSS buttons. Primary, Success, Danger and Warning. Now, you can add your classes like this ${style[kind]},

  return (
    <div>
      <button style={btnStyle} className={`${style[kind]}`} {...props}>
        {children}
      </button>
    </div>
  );

and then add Button.propTypes

Button.propTypes = {
    kind: PropTypes.oneOf([
        'primary',
        'success',
        'danger',
        'warning'
    ])
}
Sign up to request clarification or add additional context in comments.

Comments

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.