CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-emotion-theming

A CSS-in-JS theming solution, inspired by styled-components

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Emotion Theming

Emotion Theming is a CSS-in-JS theming solution for React applications, inspired by styled-components. It provides a React context-based theming system that integrates seamlessly with Emotion's styling ecosystem, enabling developers to create consistent design systems and dynamic themes across their applications.

Package Information

  • Package Name: emotion-theming
  • Package Type: npm
  • Language: JavaScript with TypeScript definitions
  • Installation: npm install emotion-theming

Core Imports

import { ThemeProvider, withTheme, useTheme } from "emotion-theming";

For CommonJS:

const { ThemeProvider, withTheme, useTheme } = require("emotion-theming");

Basic Usage

import React from "react";
import { ThemeProvider, useTheme, withTheme } from "emotion-theming";
import styled from "@emotion/styled";

// Define your theme
const theme = {
  colors: {
    primary: "hotpink",
    secondary: "turquoise",
  },
  fonts: {
    body: "system-ui, sans-serif",
    heading: "Georgia, serif",
  },
};

// Use theme in styled components (automatic injection)
const Button = styled.button`
  background-color: ${props => props.theme.colors.primary};
  color: white;
  font-family: ${props => props.theme.fonts.body};
`;

// Use theme with useTheme hook
function ThemedText() {
  const theme = useTheme();
  return (
    <p style={{ color: theme.colors.secondary }}>
      Themed text using useTheme hook
    </p>
  );
}

// Use theme with withTheme HOC
const ThemedDiv = withTheme(({ theme, children }) => (
  <div style={{ fontFamily: theme.fonts.heading }}>
    {children}
  </div>
));

// Wrap your app with ThemeProvider
function App() {
  return (
    <ThemeProvider theme={theme}>
      <ThemedDiv>
        <Button>Click me</Button>
        <ThemedText />
      </ThemedDiv>
    </ThemeProvider>
  );
}

Architecture

Emotion Theming is built around several key patterns:

  • React Context API: Uses @emotion/core's ThemeContext for theme distribution throughout the component tree
  • Theme Merging: Supports nested ThemeProviders with object merging and functional theme transformation
  • Performance Optimization: Uses weak memoization to cache theme computations and prevent unnecessary re-renders
  • TypeScript Integration: Full generic type support for theme objects with proper type inference
  • HOC Pattern: Higher-order component pattern for class component integration
  • React Hooks: Modern hook-based API for functional component integration

Capabilities

Theme Provider

React component that injects theme objects into the component tree via React context. Supports both object-based themes and function-based theme transformations for nested providers.

/**
 * React component that provides theme context to descendant components
 * @param props - Component props including theme and children
 * @returns React element that provides theme context
 */
function ThemeProvider<Theme>(
  props: ThemeProviderProps<Theme>
): React.ReactElement;

interface ThemeProviderProps<Theme> {
  /** Theme object or function that transforms parent theme */
  theme: Partial<Theme> | ((outerTheme: Theme) => Theme);
  /** Child components that will receive theme context */
  children?: React.ReactNode;
}

Usage Examples:

import React from "react";
import { ThemeProvider } from "emotion-theming";

// Object-based theme
const baseTheme = {
  colors: { primary: "blue", secondary: "green" },
  spacing: { small: "8px", medium: "16px" }
};

// Function-based theme for nested providers
const darkTheme = (parentTheme) => ({
  ...parentTheme,
  colors: {
    ...parentTheme.colors,
    primary: "darkblue",
    background: "black"
  }
});

function App() {
  return (
    <ThemeProvider theme={baseTheme}>
      <div>
        {/* Nested provider with theme transformation */}
        <ThemeProvider theme={darkTheme}>
          <DarkModeSection />
        </ThemeProvider>
      </div>
    </ThemeProvider>
  );
}

Theme Hook

React hook that returns the current theme object from the nearest ThemeProvider ancestor. Causes component re-renders when theme changes.

/**
 * React hook that returns the current theme from context
 * @returns Current theme object
 */
function useTheme<Theme>(): Theme;

Usage Examples:

import React from "react";
import { useTheme } from "emotion-theming";

function ThemedComponent() {
  const theme = useTheme();
  
  return (
    <div style={{
      color: theme.colors.primary,
      padding: theme.spacing.medium,
      fontFamily: theme.fonts.body
    }}>
      Content styled with theme
    </div>
  );
}

// With TypeScript for better type safety
interface MyTheme {
  colors: { primary: string; secondary: string; };
  spacing: { small: string; medium: string; };
}

function TypedThemedComponent() {
  const theme = useTheme<MyTheme>();
  // theme is now properly typed as MyTheme
  
  return (
    <button style={{ backgroundColor: theme.colors.primary }}>
      Typed theme usage
    </button>
  );
}

Theme Higher-Order Component

Higher-order component that injects the current theme as a prop into the wrapped component. Useful for class components and complex component wrapping scenarios.

/**
 * Higher-order component that injects theme as a prop
 * @param component - React component to wrap with theme injection
 * @returns Component with theme prop injected
 */
function withTheme<C extends React.ComponentType<any>>(
  component: C
): React.FC<AddOptionalTo<PropsOf<C>, 'theme'>>;

Usage Examples:

import React from "react";
import { withTheme } from "emotion-theming";

// Class component usage
class ClassButton extends React.Component {
  render() {
    const { theme, children, ...otherProps } = this.props;
    return (
      <button
        style={{
          backgroundColor: theme.colors.primary,
          color: theme.colors.text,
          padding: theme.spacing.medium
        }}
        {...otherProps}
      >
        {children}
      </button>
    );
  }
}

const ThemedClassButton = withTheme(ClassButton);

// Functional component usage (alternative to useTheme)
const FunctionalButton = ({ theme, children, ...props }) => (
  <button
    style={{
      backgroundColor: theme.colors.secondary,
      borderRadius: theme.borderRadius
    }}
    {...props}
  >
    {children}
  </button>
);

const ThemedFunctionalButton = withTheme(FunctionalButton);

// Usage in JSX
function App() {
  return (
    <div>
      <ThemedClassButton>Class Component Button</ThemedClassButton>
      <ThemedFunctionalButton>Functional Component Button</ThemedFunctionalButton>
    </div>
  );
}

Error Handling

Emotion Theming includes development-time validation with helpful error messages:

// Theme must be an object or function
<ThemeProvider theme={null} /> // Error: Please make your theme prop a plain object

// Theme functions must return objects
<ThemeProvider theme={() => null} /> // Error: Please return an object from your theme function

// Arrays are not valid themes
<ThemeProvider theme={[]} /> // Error: Please make your theme prop a plain object

Types

interface ThemeProviderProps<Theme> {
  theme: Partial<Theme> | ((outerTheme: Theme) => Theme);
  children?: React.ReactNode;
}

interface EmotionTheming<Theme> {
  ThemeProvider(props: ThemeProviderProps<Theme>): React.ReactElement;
  withTheme<C extends React.ComponentType<any>>(
    component: C
  ): React.FC<AddOptionalTo<PropsOf<C>, 'theme'>>;
}

type PropsOf<
  C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<C, React.ComponentPropsWithRef<C>>;

type Omit<T, U> = T extends any ? Pick<T, Exclude<keyof T, U>> : never;

type AddOptionalTo<T, U> = Omit<T, U> & Partial<Pick<T, Extract<keyof T, U>>>;

Integration with Emotion Ecosystem

Emotion Theming integrates seamlessly with other Emotion packages:

With @emotion/styled

import styled from "@emotion/styled";
import { ThemeProvider } from "emotion-theming";

// Theme is automatically injected into styled components
const Button = styled.button`
  background-color: ${props => props.theme.colors.primary};
  padding: ${props => props.theme.spacing.medium};
`;

// No need to manually pass theme - it's injected automatically
<ThemeProvider theme={theme}>
  <Button>Automatically themed</Button>
</ThemeProvider>

With @emotion/core css prop

/** @jsx jsx */
import { jsx } from "@emotion/core";
import { ThemeProvider } from "emotion-theming";

function MyComponent() {
  return (
    <div
      css={theme => ({
        color: theme.colors.primary,
        fontSize: theme.typography.body
      })}
    >
      CSS prop with theme function
    </div>
  );
}

<ThemeProvider theme={theme}>
  <MyComponent />
</ThemeProvider>

Common Patterns

Conditional Theming

const lightTheme = { mode: 'light', colors: { bg: 'white', text: 'black' } };
const darkTheme = { mode: 'dark', colors: { bg: 'black', text: 'white' } };

function App({ isDark }) {
  return (
    <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
      <MyApp />
    </ThemeProvider>
  );
}

Theme Inheritance and Overrides

const baseTheme = {
  colors: { primary: 'blue', secondary: 'green' },
  spacing: { small: '8px', medium: '16px' }
};

function App() {
  return (
    <ThemeProvider theme={baseTheme}>
      <Header />
      {/* Override specific colors for this section */}
      <ThemeProvider theme={parent => ({ 
        ...parent, 
        colors: { ...parent.colors, primary: 'red' } 
      })}>
        <AlertSection />
      </ThemeProvider>
    </ThemeProvider>
  );
}

Performance Optimization

// ✅ Good: Theme object is hoisted and stable
const theme = { colors: { primary: 'blue' } };

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

// ❌ Bad: Theme object is recreated on every render
function BadApp() {
  return (
    <ThemeProvider theme={{ colors: { primary: 'blue' } }}>
      <Content />
    </ThemeProvider>
  );
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/emotion-theming@10.3.x
Publish Source
CLI
Badge
tessl/npm-emotion-theming badge