Documentation Index
Fetch the complete documentation index at: https://mintlify.com/medusajs/medusa/llms.txt
Use this file to discover all available pages before exploring further.
The Medusa admin dashboard is highly customizable, allowing you to tailor the appearance and branding to match your business identity.
Theming
The admin dashboard supports light and dark themes out of the box, with automatic system preference detection.
Theme Provider
The dashboard uses a ThemeProvider (packages/admin/dashboard/src/providers/theme-provider/theme-provider.tsx) that:
- Persists theme selection to localStorage
- Supports
light, dark, and system options
- Applies theme changes without page reload
- Manages smooth transitions between themes
Theme Context
Access the current theme in your custom components:
import { useTheme } from "@medusajs/dashboard"
export default function CustomWidget() {
const { theme, setTheme } = useTheme()
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme("dark")}>Dark Mode</button>
<button onClick={() => setTheme("light")}>Light Mode</button>
<button onClick={() => setTheme("system")}>System</button>
</div>
)
}
Color Customization
The dashboard uses CSS variables for theming. You can override these in your own CSS:
/* Custom theme colors */
:root {
--medusa-bg-base: #ffffff;
--medusa-fg-base: #1a1a1a;
--medusa-border-base: #e0e0e0;
/* Primary brand color */
--medusa-bg-interactive: #6366f1;
--medusa-fg-interactive: #ffffff;
}
.dark {
--medusa-bg-base: #1a1a1a;
--medusa-fg-base: #ffffff;
--medusa-border-base: #2a2a2a;
}
Branding
Custom Logo
To replace the Medusa logo with your own:
Prepare Your Logo
Create SVG or PNG versions of your logo:
- Full logo (for sidebar)
- Icon/mark (for collapsed sidebar)
- Recommended size: SVG or 200x50px PNG
Create a Custom Component
Create a custom route or widget to override the logo:// src/admin/widgets/custom-logo.tsx
import { defineWidgetConfig } from "@medusajs/admin-sdk"
const CustomLogo = () => {
return (
<img
src="/path/to/your-logo.svg"
alt="Your Brand"
className="h-8"
/>
)
}
export const config = defineWidgetConfig({
zone: "login.before"
})
export default CustomLogo
Add Custom Styles
Override default branding with CSS:/* Hide default Medusa branding */
[data-medusa-logo] {
display: none;
}
/* Style your logo */
.custom-logo {
max-height: 32px;
width: auto;
}
Custom Fonts
Add custom fonts to match your brand:
/* Import custom font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
:root {
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
body {
font-family: var(--font-sans);
}
Favicon
To customize the favicon:
- Add your favicon files to the public directory
- Update the HTML head in your build configuration
<link rel="icon" type="image/svg+xml" href="/your-favicon.svg" />
<link rel="icon" type="image/png" href="/your-favicon.png" />
Layout Customization
The sidebar can be customized through the SidebarProvider:
import { useSidebar } from "@medusajs/dashboard"
export default function CustomWidget() {
const { isOpen, toggle, desktop } = useSidebar()
return (
<button onClick={toggle}>
{isOpen ? "Collapse" : "Expand"} Sidebar
</button>
)
}
Custom Navigation
Add custom menu items to the sidebar:
// src/admin/routes/custom-page/page.tsx
import { defineRouteConfig } from "@medusajs/admin-sdk"
import { BuildingStorefront } from "@medusajs/icons"
const CustomPage = () => {
return (
<div>
<h1>Custom Page</h1>
</div>
)
}
export const config = defineRouteConfig({
label: "Custom Page",
icon: BuildingStorefront,
rank: 100 // Controls ordering in sidebar
})
export default CustomPage
Styling Components
Using Medusa UI Components
The dashboard includes the @medusajs/ui design system:
import { Container, Heading, Text, Button } from "@medusajs/ui"
export default function CustomWidget() {
return (
<Container>
<Heading level="h2">Welcome</Heading>
<Text size="small" className="text-ui-fg-subtle">
This is a custom widget
</Text>
<Button variant="primary">Take Action</Button>
</Container>
)
}
Tailwind CSS
The dashboard uses Tailwind CSS for styling. All Tailwind utilities are available:
export default function CustomComponent() {
return (
<div className="flex items-center gap-4 p-4 rounded-lg border border-ui-border-base bg-ui-bg-subtle">
<div className="flex-1">
<h3 className="text-lg font-semibold text-ui-fg-base">
Custom Card
</h3>
<p className="text-sm text-ui-fg-subtle">
Styled with Tailwind utilities
</p>
</div>
</div>
)
}
Custom CSS
Add global styles by creating a CSS file:
/* src/admin/styles/custom.css */
/* Override default spacing */
.custom-container {
@apply px-8 py-6;
}
/* Custom card style */
.custom-card {
@apply rounded-xl shadow-lg border-2 border-ui-border-strong;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* Custom button variant */
.btn-custom {
@apply bg-gradient-to-r from-purple-600 to-indigo-600;
@apply text-white font-semibold px-6 py-3 rounded-lg;
@apply hover:from-purple-700 hover:to-indigo-700;
@apply transition-all duration-200;
}
Import the CSS in your widget or route:
import "./styles/custom.css"
export default function CustomWidget() {
return (
<div className="custom-card">
<button className="btn-custom">Custom Button</button>
</div>
)
}
Advanced Customization
Custom Provider
Wrap the dashboard in your own provider:
import { DashboardApp } from "@medusajs/dashboard"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30000,
retry: 2
}
}
})
const app = new DashboardApp({ plugins })
// Wrap with custom provider
function CustomDashboard() {
return (
<QueryClientProvider client={queryClient}>
{app.render()}
</QueryClientProvider>
)
}
Internationalization
Customize or add translations:
// src/admin/i18n/custom-translations.ts
export const customTranslations = {
en: {
custom: {
welcome: "Welcome to {{storeName}}",
dashboard: "Dashboard Overview"
}
},
es: {
custom: {
welcome: "Bienvenido a {{storeName}}",
dashboard: "Vista General del Panel"
}
}
}
Use translations in your components:
import { useTranslation } from "react-i18next"
export default function CustomWidget() {
const { t } = useTranslation("custom")
return (
<div>
<h1>{t("welcome", { storeName: "My Store" })}</h1>
<p>{t("dashboard")}</p>
</div>
)
}
Best Practices
Maintain Theme Consistency
Always use CSS variables and Tailwind utilities instead of hard-coded colors to ensure your customizations work in both light and dark modes.
Use Design System Components
Leverage the @medusajs/ui components for consistency and automatic theme support.
Ensure your customizations work well on mobile, tablet, and desktop screens.
Keep custom CSS minimal and avoid heavy JavaScript in the main bundle.
Next Steps