Created
August 12, 2025 20:42
-
-
Save richiethomas/5b727be9cf6f2a6142c3a311b64c60be to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Skip to content | |
Chat history | |
You said: | |
How to pass in a component's property value to dynamically determine the styling of a React styled component? | |
ChatGPT said: | |
Thought for 9s | |
Use prop-based interpolations in your styled component. Pass the value as a prop and read it inside the template literal. With styled-components, prefer transient props (prefix with $) so React doesn’t forward unknown attributes to the DOM. | |
Basic (styled-components, JS) | |
import styled, { css } from "styled-components"; | |
const Button = styled.button` | |
padding: ${({ $size }) => | |
$size === "lg" ? "0.85rem 1.25rem" : | |
$size === "sm" ? "0.4rem 0.7rem" : | |
"0.6rem 1rem"}; | |
background: ${({ $intent, theme }) => | |
$intent === "danger" ? theme.colors.red : | |
$intent === "success" ? theme.colors.green : | |
theme.colors.gray}; | |
${({ $active }) => | |
$active && | |
css` | |
box-shadow: 0 0 0 3px rgba(0,0,0,.12); | |
transform: translateY(-1px); | |
`} | |
`; | |
export default function Example({ isPrimary }) { | |
return ( | |
<Button | |
$size="lg" | |
$intent={isPrimary ? "success" : "danger"} | |
$active={isPrimary} | |
> | |
Click me | |
</Button> | |
); | |
} | |
Why the $ prefix? | |
$size, $intent, $active won’t be attached as DOM attributes, avoiding warnings like React does not recognize the 'intent' prop on a DOM element. The values remain available to the style function. | |
TypeScript version | |
type Size = "sm" | "md" | "lg"; | |
type Intent = "default" | "success" | "danger"; | |
interface ButtonProps { | |
$size?: Size; | |
$intent?: Intent; | |
$active?: boolean; | |
} | |
const Button = styled.button<ButtonProps>` | |
/* same CSS as above */ | |
`; | |
Alternative: filter props without $ | |
If you don’t want transient props, configure shouldForwardProp: | |
const Button = styled.button.withConfig({ | |
shouldForwardProp: (prop) => !["variant", "active"].includes(prop) | |
})` | |
background: ${({ variant }) => (variant === "primary" ? "black" : "white")}; | |
color: ${({ variant }) => (variant === "primary" ? "white" : "black")}; | |
opacity: ${({ active }) => (active ? 1 : 0.6)}; | |
`; | |
Dynamic values beyond conditionals | |
You can compute any CSS value from props: | |
const Tag = styled.span` | |
font-size: ${({ $scale = 1 }) => `${0.875 * $scale}rem`}; | |
border: 1px solid ${({ $color = "#999" }) => $color}; | |
color: ${({ $color = "#999" }) => $color}; | |
`; | |
Using the theme + props together | |
const Card = styled.div` | |
border-radius: ${({ theme }) => theme.radii.lg}; | |
border: 1px solid | |
${({ theme, $elevated }) => ($elevated ? theme.colors.primary : theme.colors.border)}; | |
`; | |
Emotion (same idea) | |
/** @jsxImportSource @emotion/react */ | |
import styled from "@emotion/styled"; | |
const Box = styled("div", { | |
shouldForwardProp: (prop) => prop !== "state" | |
})(({ state }) => ({ | |
padding: "1rem", | |
background: state === "ok" ? "#e6ffed" : "#fff5f5", | |
})); | |
Common pitfalls | |
Don’t pass raw, non-standard props to DOM nodes (use $ or shouldForwardProp). | |
Keep the style logic close to the component—avoid scattered conditionals in parents; just pass simple props. | |
For many combinations, consider a variant map to keep styles tidy. | |
Variant map pattern (scales well) | |
const intents = { | |
default: { bg: "#eee", fg: "#111" }, | |
primary: { bg: "#0d6efd", fg: "#fff" }, | |
danger: { bg: "#dc3545", fg: "#fff" }, | |
} as const; | |
type IntentKey = keyof typeof intents; | |
const Button = styled.button<{ $intent?: IntentKey }>` | |
${({ $intent = "default" }) => { | |
const v = intents[$intent]; | |
return css` | |
background: ${v.bg}; | |
color: ${v.fg}; | |
`; | |
}} | |
`; | |
That’s all you need: pass a prop, read it in the styled function, and (ideally) use transient props to keep the DOM clean. | |
No file chosenNo file chosen | |
ChatGPT can make mistakes. Check important info. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment