<div id='root' ></div>
*,
*::before,
*::after {
  box-sizing: border-box;
}

pre {
  width: 100%;
  white-space: pre-wrap;
}

body {
  font-family: Arial, sans-serif;
  background-color: #1a1d1d;
  padding: 20px;
  font-size: 0.875rem;
}
.controls-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 80%;
  margin: 0 auto;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  background-color: #f9f9f9;
}

.controls-container label {
  display: flex;
  flex-direction: column;
  font-size: 16px;
  color: #333;
}

.controls-container input {
  margin-top: 5px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.controls-container input:focus {
  border-color: #007bff;
  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
  outline: none;
}

.themed {
  padding: 8px;
  text-align: center;
  overflow: hidden;
}

.container {
  background-color: #fff;
  padding: 20px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  max-width: 30rem;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

h1 {
  font-size: 1rem;
}

@media screen and (max-width: 600px) {
  body {
    padding: 5px;
  }
  .container {
    width: 100%;
  }
}
import React, {
  useState,
  useRef,
  useEffect,
  useReducer
} from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const initialState = {
  theme: {
    background: {
      color: "#ddd"
    },
    textColor: "#000000",
    size: "100",
    borderStyle: {
      width: "1",
      color: "#000000",
      style: "solid",
      radius: "5"
    },
    boxShadow: "0px 0px 0px 0px rgba(0,0,0,0.75)"
  }
};

function styleReducer(state, action) {
  switch (action.type) {
    case "CHANGE_BACKGROUND_COLOR":
      return {
        ...state,
        theme: {
          ...state.theme,
          background: { ...state.theme.background, color: action.value }
        }
      };
    case "CHANGE_TEXT_COLOR":
      return {
        ...state,
        theme: { ...state.theme, textColor: action.value }
      };
    case "CHANGE_BORDER_COLOR":
      return {
        ...state,
        theme: {
          ...state.theme,
          borderStyle: { ...state.theme.borderStyle, color: action.value }
        }
      };
    case "CHANGE_BORDER_RADIUS":
      return {
        ...state,
        theme: {
          ...state.theme,
          borderStyle: { ...state.theme.borderStyle, radius: action.value }
        }
      };
    case "CHANGE_SIZE":
      return {
        ...state,
        theme: {
          ...state.theme,
          size: action.value
        }
      };
    case "CHANGE_BOX_SHADOW":
      return {
        ...state,
        theme: {
          ...state.theme,
          boxShadow: `0px 0px ${action.value}px rgba(0,0,0,0.75)`
        }
      };
    case "CHANGE_BORDER_WIDTH":
      return {
        ...state,
        theme: {
          ...state.theme,
          borderStyle: { ...state.theme.borderStyle, width: action.value }
        }
      };
    default:
      return state;
  }
}

const toPx = (value) => `${value}px`;

function CSSPropertyEditor() {
  const [state, dispatch] = useReducer(styleReducer, initialState);
  const renderCount = useRef(0);

  useEffect(() => {
    renderCount.current += 1;
  });

  return (
    <div className="container">
      Render Count: {renderCount.current}
      <div
        className="themed"
        style={{
          backgroundColor: state.theme.background.color,
          color: state.theme.textColor,
          border: `${toPx(state.theme.borderStyle.width)} ${
            state.theme.borderStyle.style
          } ${state.theme.borderStyle.color}`,
          borderRadius: toPx(state.theme.borderStyle.radius),
          width: toPx(state.theme.size),
          height: toPx(state.theme.size),
          boxShadow: state.theme.boxShadow
        }}
      >
        <h1>Themed Container</h1>
      </div>
      <div className="controls-container">
        <label>
          {" "}
          Background color:
          <input
            type="color"
            value={state.theme.background.color}
            onChange={(e) =>
              dispatch({
                type: "CHANGE_BACKGROUND_COLOR",
                value: e.target.value
              })
            }
          />
        </label>
        <label>
          {" "}
          Text color:
          <input
            type="color"
            value={state.theme.textColor}
            onChange={(e) =>
              dispatch({ type: "CHANGE_TEXT_COLOR", value: e.target.value })
            }
          />
        </label>
        <label>
          {" "}
          border color:
          <input
            type="color"
            value={state.theme.borderStyle.color}
            onChange={(e) =>
              dispatch({ type: "CHANGE_BORDER_COLOR", value: e.target.value })
            }
          />
        </label>
        <label>
          {" "}
          border Radius:
          <input
            type="range"
            min="0"
            max="100"
            step="1"
            value={state.theme.borderStyle.radius}
            onChange={(e) =>
              dispatch({ type: "CHANGE_BORDER_RADIUS", value: e.target.value })
            }
          />
        </label>
        <label>
          {" "}
          Border size:
          <input
            type="range"
            min="0"
            max="100"
            step="1"
            value={state.theme.borderStyle.width}
            onChange={(e) =>
              dispatch({ type: "CHANGE_BORDER_WIDTH", value: e.target.value })
            }
          />
        </label>
        <label>
          {" "}
          Size:
          <input
            type="range"
            min="50"
            max="200"
            value={state.theme.size}
            onChange={(e) =>
              dispatch({ type: "CHANGE_SIZE", value: e.target.value })
            }
          />
        </label>
        <label>
          {" "}
          Box Shadow:
          <input
            type="range"
            min="0"
            max="20"
            value={parseInt(state.theme.boxShadow.split(" ")[2], 10)}
            onChange={(e) =>
              dispatch({ type: "CHANGE_BOX_SHADOW", value: e.target.value })
            }
          />
        </label>
      </div>
      <pre>
        {JSON.stringify(
          {
            backgroundColor: state.theme.background.color,
            color: state.theme.textColor,
            border: `${state.theme.borderStyle.width} ${state.theme.borderStyle.style} ${state.theme.borderStyle.color}`,
            borderRadius: toPx(state.theme.borderStyle.radius),
            width: toPx(state.theme.size),
            height: toPx(state.theme.size),
            boxShadow: state.theme.boxShadow
          },
          null,
          2
        )}
      </pre>
    </div>
  );
}

ReactDOM.render(<CSSPropertyEditor />, document.getElementById("root"));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.