Themes control the visual appearance and user interface of your EverShop store. Unlike extensions (which handle logic), themes focus on the presentation layer using React components and Tailwind CSS.
What is a Theme?
A theme is a collection of React components that define how your store looks and feels. Themes:
Override default UI components with custom designs
Use Tailwind CSS for styling
Support TypeScript for type-safe development
Are modular - only override components you need
Work with areas - inject components into predefined page areas
Directory Structure
A typical theme follows this structure:
themes/[theme-name]/
├── src/
│ └── pages/
│ ├── all/ # Components for all pages
│ ├── frontStore/ # Front-end specific components
│ ├── admin/ # Admin panel components
│ ├── homepage/ # Homepage components
│ ├── account/ # Account pages
│ └── productView/ # Product detail page
├── dist/ # Compiled output (auto-generated)
├── package.json
└── tsconfig.json
Creating Your First Theme
Create the Theme Directory
Create a new directory in the themes folder:
mkdir -p themes/my-theme/src/pages
cd themes/my-theme
Create a package.json file:
{
"name" : "my-theme" ,
"version" : "1.0.0" ,
"private" : true ,
"main" : "src/index.ts" ,
"scripts" : {
"build" : "evershop build:theme"
},
"dependencies" : {},
"devDependencies" : {
"@types/react" : "^19.0.0"
}
}
Create a tsconfig.json file (same as extensions):
{
"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 ,
"isolatedModules" : false ,
"baseUrl" : "." ,
"rootDir" : "./src"
},
"include" : [ "src" ]
}
Set your theme in config/default.json:
{
"system" : {
"theme" : "my-theme"
}
}
Only one theme can be active at a time. Changing the theme requires running npm run build.
Creating Theme Components
Theme components are React components that render on specific pages. Each component must export:
Default export - The React component
layout export - Defines where and when the component renders
query export (optional) - GraphQL query for data fetching
Component Structure
Here’s a real example from the anasuplements theme:
import React from 'react' ;
type HeaderProps = {
storeName ?: string ;
categories ?: {
name : string ;
url : string ;
}[];
};
export default function Header ({
storeName = "My Store" ,
categories = []
} : HeaderProps ) {
return (
< header className = "bg-[#F8FAF9] border-b border-[#E8F5E9]" >
< div className = "container mx-auto px-4 py-4" >
< div className = "flex items-center justify-between" >
< a href = "/" className = "text-2xl font-bold text-[#2D5A3D]" >
{ storeName }
</ a >
< nav className = "hidden md:flex space-x-6" >
{ categories . map (( category , index ) => (
< a
key = { index }
href = { category . url }
className = "text-[#4A5568] hover:text-[#2D5A3D] transition-colors"
>
{ category . name }
</ a >
)) }
</ nav >
< div className = "flex items-center space-x-4" >
< a href = "/cart" className = "text-[#2D5A3D] hover:text-[#1E3D2A]" >
< svg xmlns = "http://www.w3.org/2000/svg" className = "h-6 w-6" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" >
< path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</ svg >
</ a >
< a href = "/account" className = "text-[#2D5A3D] hover:text-[#1E3D2A]" >
< svg xmlns = "http://www.w3.org/2000/svg" className = "h-6 w-6" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" >
< path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</ svg >
</ a >
</ div >
</ div >
</ div >
</ header >
);
}
export const layout = {
areaId: 'header' ,
sortOrder: 1
};
Layout Configuration
The layout export defines where your component appears:
export const layout = {
areaId: 'header' , // Where to render (see Areas below)
sortOrder: 1 // Order within the area (lower = earlier)
};
Page Areas
EverShop uses a component area system. Common areas include:
Area ID Description headerPage header section contentMain content area footerPage footer section sidebarSidebar area productPageMiddleRightProduct page right column homepageHomepage specific area
Use lower sortOrder values to render components earlier in the area.
Directory Organization
Theme components are organized by page type:
Global Components (all/)
Components in src/pages/all/ appear on every page:
src/pages/all/
├── Header.tsx # Site header
├── Footer.tsx # Site footer
└── Navigation.tsx # Global navigation
Area-Specific Components
Components for specific areas (frontStore, admin):
src/pages/frontStore/
└── productView/
└── ProductInfo.tsx
src/pages/admin/
└── dashboard/
└── Stats.tsx
Page-Specific Components
Components for specific pages:
src/pages/homepage/
├── Hero.tsx
├── Features.tsx
└── FeaturedProducts.tsx
src/pages/account/
├── Login.tsx
├── Register.tsx
└── Dashboard.tsx
Working with Data
Use the query export to fetch data with GraphQL:
src/pages/frontStore/productView/SupplementInfo.tsx
import React from 'react' ;
type SupplementInfoProps = {
product : {
productId : string ;
name : string ;
description ?: string ;
extension ?: {
supplement ?: {
ingredients ?: string ;
benefits ?: string [];
dosage ?: string ;
};
};
};
};
export default function SupplementInfo ({ product } : SupplementInfoProps ) {
const supplementData = product ?. extension ?. supplement ;
if ( ! supplementData ) {
return null ;
}
return (
< div className = "bg-[#F8FAF9] border border-[#E8F5E9] rounded-lg p-6 mt-6" >
< h3 className = "text-xl font-bold text-[#2D5A3D] mb-4" >
Información del Suplemento
</ h3 >
{ supplementData . ingredients && (
< div >
< h4 className = "font-semibold text-[#2D5A3D] mb-2" > Ingredientes </ h4 >
< p className = "text-[#4A5568] text-sm" > { supplementData . ingredients } </ p >
</ div >
) }
{ supplementData . benefits && (
< div className = "mt-4" >
< h4 className = "font-semibold text-[#2D5A3D] mb-2" > Beneficios </ h4 >
< ul className = "list-disc list-inside text-[#4A5568] text-sm space-y-1" >
{ supplementData . benefits . map (( benefit : string , index : number ) => (
< li key = { index } > { benefit } </ li >
)) }
</ ul >
</ div >
) }
</ div >
);
}
export const layout = {
areaId: 'productPageMiddleRight' ,
sortOrder: 10
};
export const query = `
query Query {
product(id: getContextValue("productId")) {
productId
name
description
extension {
supplement {
ingredients
benefits
dosage
}
}
}
}
` ;
The query export uses GraphQL to fetch data. Props are automatically passed to your component.
Styling with Tailwind CSS
All themes use Tailwind CSS for styling:
< div className = "bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow" >
< h3 className = "font-semibold mb-3 text-gray-800" > Title </ h3 >
< p className = "text-gray-600 leading-relaxed" > Content </ p >
</ div >
Custom Colors
Use custom color values with bracket notation:
< header className = "bg-[#F8FAF9] border-b border-[#E8F5E9]" >
< h1 className = "text-[#2D5A3D]" > Title </ h1 >
</ header >
Responsive Design
Use responsive modifiers:
< div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" >
{ /* Content */ }
</ div >
Real-World Example: Ana’s Supplements Theme
The anasuplements theme demonstrates a complete theme implementation:
themes/anasuplements/
├── src/
│ └── pages/
│ ├── all/
│ │ ├── Header.tsx
│ │ └── Footer.tsx
│ ├── homepage/
│ │ ├── Hero.tsx
│ │ ├── Features.tsx
│ │ └── FeaturedProducts.tsx
│ └── account/
│ ├── Login.tsx
│ ├── Register.tsx
│ └── Dashboard.tsx
├── package.json
└── tsconfig.json
Best Practices
Component Reusability : Create small, reusable components that can be composed together.
Use TypeScript - Define proper types for props
Responsive First - Design for mobile, then scale up
Accessibility - Use semantic HTML and ARIA labels
Performance - Optimize images and minimize bundle size
Consistent Styling - Use a consistent color palette and spacing
Troubleshooting
Component Not Rendering
Verify the layout export is present
Check that areaId matches a valid area
Ensure the component is in the correct directory
Run npm run build to recompile
Styles Not Applying
Verify Tailwind CSS classes are correct
Check for typos in class names
Ensure custom colors use bracket notation: bg-[#FFFFFF]
Data Not Loading
Verify the GraphQL query is valid
Check that field names match the schema
Test the query in GraphQL playground
Next Steps
Page Components Deep dive into page component architecture
Tailwind Design System Learn about the Tailwind design system