Creating & Composing Styled Components
Basics
import styled from 'styled-components';
// Define ONCE at module top level — never inside a component's render
// body, which would recreate a new component (and re-inject styles) on every render
const Button = styled.button`
padding: 8px 16px;
border-radius: 4px;
background: ${(props) => (props.primary ? 'blue' : 'gray')};
&:hover {
opacity: 0.9;
}
`;
// Used exactly like any React component — renders a real <button>
// with a unique, auto-scoped class name, no naming collisions possible
function App() {
return <Button primary>Click me</Button>;
}Extending & the `as` Prop
// Extending — composes new styles ON TOP of the original
const PrimaryButton = styled(Button)`
background: darkblue;
font-weight: bold;
`;
// as — same styles, different underlying element/semantics —
// avoids duplicating the whole style block for a link that must LOOK
// like a button but needs correct <a> semantics for accessibility/SEO
<Button as="a" href="/home">Home</Button>
// Styling a custom component — it must forward className to its root DOM node
function Card({ className, children }) {
return <div className={className}>{children}</div>;
}
const StyledCard = styled(Card)`
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;Shared Snippets & Animation
import { css, keyframes } from 'styled-components';
// css — a reusable snippet, not a full component; composes into
// otherwise-unrelated styled components rendering different elements
const cardShadow = css`
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-radius: 8px;
`;
const Card = styled.div`${cardShadow}`;
const Panel = styled.section`${cardShadow}`;
// keyframes — uniquely named, avoids global animation-name collisions
const fadeIn = keyframes`
from { opacity: 0; }
to { opacity: 1; }
`;
const FadeInBox = styled.div`
animation: ${fadeIn} 0.3s ease-in;
`;Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free