Home > Back-end >  How to make css dynamic for React reusable component?
How to make css dynamic for React reusable component?

Time:01-25

I am developing a React application with SCSS (I am a beginner with SCSS). I am trying to develop reusable components (like with bootstrap, and...).

I begin with "Card", and I want this component to be reusable as possible, as I can reuse it in the same app and in other apps because it will be added to "commun_lib, which is a global repository in GitLab for common use in hole company".

This is what I did:

Card.jsx

import React from "react";
import "./Card.scss";

export function cardStyle(cardWidth, cardHeight) {
  var bodyStyles = document.body.style;
  bodyStyles.setProperty("--card-width", cardWidth "px");
  bodyStyles.setProperty("--card-height", cardHeight "px");
}
export default function Card({ title, content }) {
  return (
    <div className="APP_card">
      {title ? (
        <div className="APP_cardHeader">
          <span className="APP_cardTitle">{title}</span>
        </div>
      ) : (
        <></>
      )}
      <div className="APP_cardContainer">{content}</div>
    </div>
  );
}

Card.scss

//card
$card-bg: #fff;
$card-width: var(--card-width); //280px
$card-height: var(--card-height); //508px
$card-box-shadow: 0px 3px 16px #0a4b6d14;

//card-header
$card-header-height: var(--card-header-height); //33px;
$card-header-bg: var(--card-header-bg);
$card-header-padding: 5px;

//card-title
$card-title-color: #fff;

//border-radius
$border-top-left-radius: 12px;
$border-top-right-radius: 12px;
$border-bottom-right-radius: 12px;
$border-bottom-left-radius: 12px;

@mixin border-radius($border-top-left-radius, $border-top-right-radius, $border-bottom-right-radius, $border-bottom-left-radius) {
    border-radius: $border-top-left-radius $border-top-right-radius $border-bottom-right-radius $border-bottom-left-radius;
}

@mixin border($border-color, $border-type, $border-width) {
    border: $border-width $border-type $border-color;
}

.APP_card {
    @include border-radius($border-top-left-radius, $border-top-right-radius, $border-bottom-right-radius, $border-bottom-left-radius );
    @include border(1px, solid, #a5c9ff);
    width: $card-width;
    height: $card-height;
    background-color: $card-bg;
}

.APP_cardHeader {
    @include border-radius($border-top-left-radius, $border-top-right-radius, 0, 0);
    height: $card-header-height;
    box-sizing: content-box;
    padding: $card-header-padding;
    background-color: $card-header-bg;
    display: flex;
    align-items: center;
    justify-content: center;
}

.APP_cardTitle {
    color: $card-title-color;
    line-height: 16px;
    font-size: 13px;
    margin-left: 10px;
}

.APP_cardContainer {
    padding: 6px 10px 6px 10px;
    display: flex;
    flex-direction: column;
    box-sizing: content-box;
    justify-content: center;
}

ActivityCard.jsx

import React, { useEffect, useState } from "react";
import Card, { cardStyle } from "../../../../shared/components/card/Card";

export default function ActivityCard({ title, indexOfPeriod }) {
....
cardStyle(260, 508);
var cardTitle = (...);
var cardContent = (...);
return <Card title={cardTitle} content={cardContent}></Card>;
}

But for every cardStyle() call, I should add all CSS properties in order to pass 0 or none for attributes that I don't want to change.

I really do not know if this method can be improved or is there are others methods that are better.

CodePudding user response:

What you are doing in that cardStyle would change the width and height of all your cards. You would wanna remove it, and pass cardWidth and cardHeight to the component directly, with default values to be used when they are not passed.

import React from "react";
import "./Card.scss";

export default function Card({ title, content, cardWidth = 280, cardHeight = 508 }) {
  return (
    <div className="APP_card" style={{ width: cardWidth, height: cardHeight }}>
      {title ? (
        <div className="APP_cardHeader">
          <span className="APP_cardTitle">{title}</span>
        </div>
      ) : (
        <></>
      )}
      <div className="APP_cardContainer">{content}</div>
    </div>
  );
}

This way, you have a common style applied to all Card through SCSS, and custom inline ones scoped to each Card.

  • Related