Skip to main content

Directory Structure

A complete EverShop theme follows this structure:
themes/my-theme/
├── src/                      # Source files (development)
│   ├── components/           # Reusable components
│   │   ├── common/          # Shared components
│   │   └── frontStore/      # Store-specific components
│   └── pages/               # Page-specific components
│       ├── all/             # Components for all pages
│       ├── homepage/        # Homepage components
│       ├── productDetail/   # Product page components
│       └── categoryView/    # Category page components
├── dist/                     # Compiled files (production)
│   ├── components/
│   ├── pages/
│   └── tailwind.config.js   # Optional custom Tailwind config
├── package.json             # Theme package configuration
└── tsconfig.json            # TypeScript configuration

Required Files

package.json

Every theme must have a package.json file:
{
  "name": "my-theme",
  "version": "1.0.0",
  "type": "module",
  "private": true,
  "scripts": {
    "build": "tsc"
  }
}
The type: "module" field is required for ESM support.

tsconfig.json

TypeScript configuration for your theme:
{
  "compilerOptions": {
    "module": "NodeNext",
    "target": "ES2018",
    "lib": ["dom", "dom.iterable", "esnext"],
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "declaration": true,
    "sourceMap": true,
    "allowJs": true,
    "checkJs": false,
    "jsx": "react",
    "outDir": "./dist",
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "allowArbitraryExtensions": true,
    "strictNullChecks": true,
    "baseUrl": ".",
    "rootDir": "src",
    "paths": {
      "@components/*": [
        "./src/components/*",
        "../../node_modules/@evershop/evershop/src/components/*"
      ]
    }
  },
  "include": ["src"]
}
Key configurations:
  • outDir: Compiled files go to ./dist
  • rootDir: Source files are in src
  • paths: Alias for importing EverShop components

Directory Breakdown

src/ Directory

The src/ directory contains your theme’s source code during development.

src/pages/

Page-specific components organized by route:
DirectoryPurposeWhen Components Load
pages/all/Components that appear on every pageAll routes
pages/homepage/Homepage-only components/ route
pages/productDetail/Product page components/product/:slug route
pages/categoryView/Category page components/category/:slug route
pages/cart/Shopping cart components/cart route
pages/checkout/Checkout page components/checkout route
Example: A component in pages/all/
// themes/my-theme/src/pages/all/EveryWhere.tsx
import React from 'react';

export default function EveryWhere() {
  return (
    <div className="container mx-auto px-4 py-8">
      <p>This component appears on every page!</p>
    </div>
  );
}

export const layout = {
  areaId: 'content',
  sortOrder: 20
};

src/components/

Reusable components that can be imported by page components:
src/components/
├── common/              # Shared across admin and storefront
│   ├── Button.tsx
│   └── Modal.tsx
└── frontStore/          # Store-specific components
    ├── Header.tsx
    └── Footer.tsx
Example: Reusable component
// themes/my-theme/src/components/common/Button.tsx
import React from 'react';

interface ButtonProps {
  children: React.ReactNode;
  onClick?: () => void;
  variant?: 'primary' | 'secondary';
}

export default function Button({ children, onClick, variant = 'primary' }: ButtonProps) {
  const baseClasses = 'px-4 py-2 rounded font-medium';
  const variantClasses = variant === 'primary' 
    ? 'bg-blue-600 text-white hover:bg-blue-700'
    : 'bg-gray-200 text-gray-800 hover:bg-gray-300';
  
  return (
    <button className={`${baseClasses} ${variantClasses}`} onClick={onClick}>
      {children}
    </button>
  );
}

dist/ Directory

The dist/ directory contains compiled JavaScript files generated by TypeScript:
dist/
├── components/
│   ├── common/
│   │   ├── Button.js
│   │   ├── Button.d.ts
│   │   └── Button.js.map
│   └── frontStore/
└── pages/
    ├── all/
    │   ├── EveryWhere.js
    │   ├── EveryWhere.d.ts
    │   └── EveryWhere.js.map
    └── homepage/
Never edit files in dist/ directly. Always edit source files in src/ and rebuild.

Component File Naming

EverShop has specific naming requirements:
Valid component names (PascalCase):
  • MyComponent.tsx
  • ProductCard.tsx
  • HeaderNav.tsx
Invalid component names:
  • myComponent.tsx (starts with lowercase)
  • my-component.tsx (kebab-case)
  • my_component.tsx (snake_case)
Components must:
  1. Start with an uppercase letter
  2. Use PascalCase naming
  3. Have a .tsx or .jsx extension
  4. Be located in a page-specific directory

Layout Configuration

Every page component must export a layout object:
export const layout = {
  areaId: 'content',    // Required: where to render
  sortOrder: 10         // Required: rendering order
};

Available Area IDs

Common area IDs in the storefront:
Area IDLocationTypical Use
headerTop of pageNavigation, logo, cart icon
contentMain content areaPage-specific content
footerBottom of pageFooter links, copyright
leftLeft sidebarFilters, categories
rightRight sidebarRelated products, ads

Sort Order

Components with lower sortOrder values render first:
// This renders first
export const layout = { areaId: 'content', sortOrder: 5 };

// This renders second
export const layout = { areaId: 'content', sortOrder: 10 };

// This renders third
export const layout = { areaId: 'content', sortOrder: 20 };

Advanced Page Targeting

You can target multiple pages using special naming conventions:

Page Combinations

Use + to target multiple specific pages:
pages/
├── homepage+productDetail/    # Appears on homepage AND product pages
│   └── PromoBar.tsx
└── categoryView+productDetail/ # Appears on category AND product pages
    └── Breadcrumb.tsx

Sample Theme Example

Here’s a real example from the EverShop sample theme:
// themes/sample/src/pages/homepage/OnlyHomePage.tsx
import React from 'react';

export default function OnlyHomePage() {
  return (
    <div className="container mx-auto px-4 py-8 bg-gray-100 rounded-lg shadow-md mt-10">
      <h1 className="font-bold text-center mb-6">Home Page Only</h1>
      <p className="text-gray-700 text-center">
        This component is only rendered on the home page.
      </p>
      <p className="text-gray-700 text-center">
        You can modify this component at{' '}
        <code>themes/sample/src/pages/homepage/OnlyHomePage.tsx</code>
      </p>
    </div>
  );
}

export const layout = {
  areaId: 'content',
  sortOrder: 10
};

Building Your Theme

To compile your theme from src/ to dist/:
npm run build
This runs TypeScript compilation and prepares your theme for production.

Next Steps

Customize Your Theme

Learn how to style components and override core functionality

Create a Theme

Start building your custom theme

Build docs developers (and LLMs) love