Skip to main content
AnimeThemes Web implements a comprehensive theming system with support for light, dark, and system-based color themes, built on CSS custom properties and styled-components.

Theme Structure

The theme is defined in src/theme/index.ts and provides:
src/theme/index.ts
const theme = {
  breakpoints: {
    mobileMax: "720px",
    tabletMin: "721px",
    tabletMax: "870px",
    desktopMin: "871px",
    socialListMax: "1225px",
  },
  shadows: createThemeDefinition(shadows),
  colors: createThemeDefinition(colors),
  zIndices: {
    navigation: 10,
    switcherButton: 1,
    switcherText: 2,
    videoPlayer: 5,
    videoPlayerOverlay: 6,
    toast: 45,
    menuOverlay: 41,
    menuPopover: 40,
    dialog: 50,
    dialogBackdrop: 49,
  },
  scalars: {
    borderRadiusCard: "4px",
  },
};

Color System

Base Colors

The color palette includes grayscale, primary (teal), and warning (red) color scales:
src/theme/colors/index.ts
const baseColors = {
  transparent: "#00000000",
  white: "#ffffff",
  "gray-100": "#f5f2fa",
  "gray-200": "#e6e1f0",
  "gray-300": "#d1cae0",
  "gray-400": "#9f93b8",
  "gray-500": "#72658c",
  "gray-600": "#574e6a",
  "gray-700": "#453d53",
  "gray-800": "#2e293a",
  "gray-900": "#1c1823",
  "primary-100": "#d1fbf1",
  "primary-200": "#a5f6e4",
  "primary-300": "#75ead4",
  "primary-400": "#52d4bf",
  "primary-500": "#40b8a6",
  "primary-600": "#319488",
  "primary-700": "#28766e",
  "primary-800": "#215e59",
  "primary-900": "#1e4e4a",
  "warning-100": "#fee2e2",
  // ... more warning colors
  gold: "gold",
};

Semantic Colors

Semantic color tokens are mapped from base colors:
export const colors = {
  ...baseColors,
  background: baseColors["gray-100"],
  solid: baseColors["white"],
  "solid-primary": baseColors["primary-700"],
  "solid-warning": baseColors["warning-700"],
  "solid-on-card": baseColors["gray-200"],
  text: baseColors["gray-900"],
  "text-muted": baseColors["gray-500"],
  "text-disabled": baseColors["gray-400"],
  "text-warning": baseColors["warning-600"],
  "text-primary": baseColors["primary-600"],
  "text-on-primary": baseColors["primary-100"],
};
Semantic colors provide meaning (e.g., text-muted, solid-primary) rather than using raw color values. This makes it easier to maintain consistent theming.

Color Theme Switching

Available Themes

Users can choose between three color themes:

Light

Light background with dark text

Dark

Dark background with light text

System

Follows system preference

Using the Color Theme Hook

The useColorTheme hook manages theme state:
src/hooks/useColorTheme.ts
import useColorTheme from "@/hooks/useColorTheme";

function ThemeSwitcher() {
  const [theme, setTheme] = useColorTheme();

  return (
    <select value={theme} onChange={(e) => setTheme(e.target.value)}>
      <option value="system">System</option>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  );
}

Theme Persistence

The selected theme is persisted to localStorage and synchronized with the DOM:
const [theme, setTheme] = useLocalStorageState<ColorTheme>("theme", {
  defaultValue: "system",
});

useEffect(() => {
  document.documentElement.dataset.theme = theme;
}, [theme]);
The theme is applied via a data-theme attribute on the root <html> element.

Using Theme in Components

In Styled Components

Access theme values through the theme prop:
import styled from "styled-components";

const Card = styled.div`
  background-color: ${(props) => props.theme.colors.solid};
  color: ${(props) => props.theme.colors.text};
  box-shadow: ${(props) => props.theme.shadows.low};
  border-radius: ${(props) => props.theme.scalars.borderRadiusCard};

  @media (max-width: ${(props) => props.theme.breakpoints.mobileMax}) {
    padding: 12px;
  }
`;

CSS Custom Properties

All theme colors are exposed as CSS custom properties:
.custom-element {
  background: var(--primary-500);
  color: var(--text);
  box-shadow: var(--shadow-low);
}

Shadows

Three shadow levels are available:
src/theme/colors/index.ts
export const shadows = {
  low: `1px 2px 2px hsl(262deg 20% 50% / 0.4)`,
  medium: `
    1px 2px 2px hsl(262deg 20% 50% / 0.15),
    2px 4px 4px hsl(262deg 20% 50% / 0.15),
    3px 6px 6px hsl(262deg 20% 50% / 0.15)
  `,
  high: `
    1px 2px 2px hsl(262deg 20% 50% / 0.1),
    2px 4px 4px hsl(262deg 20% 50% / 0.1),
    4px 8px 8px hsl(262deg 20% 50% / 0.1),
    8px 16px 16px hsl(262deg 20% 50% / 0.1),
    16px 32px 32px hsl(262deg 20% 50% / 0.1)
  `,
};
Usage:
const Button = styled.button`
  box-shadow: ${(props) => props.theme.shadows.low};

  &:hover {
    box-shadow: ${(props) => props.theme.shadows.medium};
  }
`;

Z-Index Management

Consistent layering is enforced through theme z-indices:
const VideoPlayer = styled.div`
  z-index: ${(props) => props.theme.zIndices.videoPlayer};
`;

const Dialog = styled.div`
  z-index: ${(props) => props.theme.zIndices.dialog};
`;

Z-Index Scale

ElementZ-IndexPurpose
navigation10Site navigation
videoPlayer5Video player
videoPlayerOverlay6Player controls
menuPopover40Dropdown menus
menuOverlay41Menu backdrop
toast45Toast notifications
dialogBackdrop49Dialog backdrop
dialog50Modal dialogs

Theme Provider

The theme is provided to all components via ThemeProvider in _app.tsx:
src/pages/_app.tsx
import { ThemeProvider } from "styled-components";
import theme from "@/theme";

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

Best Practices

Always use semantic color tokens (like text-muted, solid-primary) instead of raw color values (like gray-500). This ensures consistent theming and makes it easier to support light/dark modes.
Avoid hardcoding color values, shadow values, or z-index numbers. Always reference theme properties to maintain consistency.

Build docs developers (and LLMs) love