Claude Code Plugins

Community-maintained marketplace

Feedback
0
0

Implements CSS-in-JS styling with styled-components using tagged template literals, theming, and dynamic props. Use when wanting component-scoped CSS-in-JS, dynamic styling based on props, or theming support.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name styled-components
description Implements CSS-in-JS styling with styled-components using tagged template literals, theming, and dynamic props. Use when wanting component-scoped CSS-in-JS, dynamic styling based on props, or theming support.

styled-components

CSS-in-JS library using tagged template literals to style React components.

Quick Start

Install:

npm install styled-components

Create styled components:

import styled from 'styled-components';

const Button = styled.button`
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  background: #3b82f6;
  color: white;

  &:hover {
    background: #2563eb;
  }
`;

const Container = styled.div`
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 16px;
`;

function App() {
  return (
    <Container>
      <Button>Click me</Button>
    </Container>
  );
}

Props-Based Styling

Transient Props ($ prefix)

Props prefixed with $ are filtered from DOM:

interface ButtonProps {
  $variant?: 'primary' | 'secondary';
  $size?: 'sm' | 'md' | 'lg';
}

const Button = styled.button<ButtonProps>`
  padding: ${props => {
    switch (props.$size) {
      case 'sm': return '8px 16px';
      case 'lg': return '16px 32px';
      default: return '12px 24px';
    }
  }};

  background: ${props => props.$variant === 'secondary' ? '#e5e7eb' : '#3b82f6'};
  color: ${props => props.$variant === 'secondary' ? '#1f2937' : 'white'};
`;

// Usage
<Button $variant="secondary" $size="lg">
  Secondary Button
</Button>

Conditional Styles

const Card = styled.div<{ $elevated?: boolean; $selected?: boolean }>`
  padding: 16px;
  border-radius: 8px;
  background: white;

  ${props => props.$elevated && `
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  `}

  ${props => props.$selected && `
    border: 2px solid #3b82f6;
  `}
`;

Extending Styles

const Button = styled.button`
  padding: 12px 24px;
  border: 2px solid #3b82f6;
  border-radius: 8px;
  background: transparent;
  color: #3b82f6;
  cursor: pointer;
`;

// Extend with additional styles
const PrimaryButton = styled(Button)`
  background: #3b82f6;
  color: white;
`;

const DangerButton = styled(Button)`
  border-color: #ef4444;
  color: #ef4444;

  &:hover {
    background: #ef4444;
    color: white;
  }
`;

Polymorphic Components

Change the rendered element with as:

const Button = styled.button`
  padding: 12px 24px;
  text-decoration: none;
  display: inline-block;
`;

// Render as anchor
<Button as="a" href="/about">About</Button>

// Render as Link (React Router)
<Button as={Link} to="/about">About</Button>

Styling Existing Components

import { Link } from 'react-router-dom';

// Component must accept and pass className
const StyledLink = styled(Link)`
  color: #3b82f6;
  text-decoration: none;

  &:hover {
    text-decoration: underline;
  }
`;

// Custom component
function CustomCard({ className, children }: { className?: string; children: React.ReactNode }) {
  return <div className={className}>{children}</div>;
}

const StyledCard = styled(CustomCard)`
  padding: 16px;
  border-radius: 8px;
`;

Attrs

Attach default or computed attributes:

const Input = styled.input.attrs<{ $size?: string }>(props => ({
  type: 'text',
  placeholder: props.placeholder || 'Enter text...',
}))`
  padding: ${props => props.$size === 'large' ? '16px' : '12px'};
  border: 1px solid #e5e7eb;
  border-radius: 6px;
`;

// Password input with overridden type
const PasswordInput = styled(Input).attrs({
  type: 'password',
  placeholder: 'Enter password',
})``;

Animations

import styled, { keyframes } from 'styled-components';

const fadeIn = keyframes`
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
`;

const spin = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;

const FadeInDiv = styled.div`
  animation: ${fadeIn} 0.3s ease-out;
`;

const Spinner = styled.div`
  width: 24px;
  height: 24px;
  border: 2px solid #e5e7eb;
  border-top-color: #3b82f6;
  border-radius: 50%;
  animation: ${spin} 0.8s linear infinite;
`;

Theming

ThemeProvider

import styled, { ThemeProvider } from 'styled-components';

const theme = {
  colors: {
    primary: '#3b82f6',
    secondary: '#6b7280',
    success: '#10b981',
    error: '#ef4444',
    background: '#ffffff',
    text: '#1f2937',
  },
  spacing: {
    xs: '4px',
    sm: '8px',
    md: '16px',
    lg: '24px',
    xl: '32px',
  },
  borderRadius: {
    sm: '4px',
    md: '8px',
    lg: '16px',
    full: '9999px',
  },
};

type Theme = typeof theme;

declare module 'styled-components' {
  export interface DefaultTheme extends Theme {}
}

// Access theme in components
const Button = styled.button`
  background: ${props => props.theme.colors.primary};
  padding: ${props => props.theme.spacing.md};
  border-radius: ${props => props.theme.borderRadius.md};
`;

// Wrap app
function App() {
  return (
    <ThemeProvider theme={theme}>
      <Button>Themed Button</Button>
    </ThemeProvider>
  );
}

useTheme Hook

import { useTheme } from 'styled-components';

function Component() {
  const theme = useTheme();

  return (
    <div style={{ color: theme.colors.primary }}>
      Using theme in regular component
    </div>
  );
}

Dark Mode

const lightTheme = {
  colors: {
    background: '#ffffff',
    text: '#1f2937',
    primary: '#3b82f6',
  },
};

const darkTheme = {
  colors: {
    background: '#1f2937',
    text: '#f9fafb',
    primary: '#60a5fa',
  },
};

function App() {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
      <AppContainer>
        <button onClick={() => setIsDark(!isDark)}>Toggle Theme</button>
      </AppContainer>
    </ThemeProvider>
  );
}

Global Styles

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    font-family: system-ui, -apple-system, sans-serif;
    background: ${props => props.theme.colors.background};
    color: ${props => props.theme.colors.text};
  }

  a {
    color: ${props => props.theme.colors.primary};
  }
`;

function App() {
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <MainContent />
    </ThemeProvider>
  );
}

CSS Helper

Share style fragments:

import styled, { css } from 'styled-components';

const flexCenter = css`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const truncate = css`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`;

const Card = styled.div`
  ${flexCenter}
  padding: 16px;
`;

const Title = styled.h2`
  ${truncate}
  max-width: 200px;
`;

Component Selectors

Reference other styled components:

const Icon = styled.span`
  color: #6b7280;
  transition: color 0.2s;
`;

const Button = styled.button`
  display: flex;
  align-items: center;
  gap: 8px;

  &:hover ${Icon} {
    color: #3b82f6;
  }
`;

// Usage
<Button>
  <Icon>+</Icon>
  Add Item
</Button>

Best Practices

  1. Define outside render - Prevent recreation on each render
  2. Use transient props - Prefix with $ to avoid DOM warnings
  3. Extend over duplicate - Use styled(Component) for variants
  4. Type your theme - Extend DefaultTheme for autocomplete
  5. Colocate with components - Keep styles near their component

Common Patterns

Responsive Styles

const breakpoints = {
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
};

const Container = styled.div`
  padding: 16px;

  @media (min-width: ${breakpoints.md}) {
    padding: 24px;
  }

  @media (min-width: ${breakpoints.lg}) {
    padding: 32px;
    max-width: 1200px;
    margin: 0 auto;
  }
`;

Variants with Object Syntax

const variants = {
  primary: css`
    background: #3b82f6;
    color: white;
  `,
  secondary: css`
    background: #e5e7eb;
    color: #1f2937;
  `,
  outline: css`
    background: transparent;
    border: 2px solid #3b82f6;
    color: #3b82f6;
  `,
};

const Button = styled.button<{ $variant?: keyof typeof variants }>`
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  cursor: pointer;

  ${props => variants[props.$variant || 'primary']}
`;

Reference Files