Skip to content

Strapi Admin Panel Customization — Logo, Colors, and Custom Fields

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn how to customize the Strapi admin panel — changing the logo and brand colors, creating custom fields for the Content-Type Builder, and extending the admin interface with custom React components for a branded content management experience.

What You'll Learn

  • How to customize the admin panel logo and favicon
  • How to change brand colors and typography
  • How to create custom fields for the Content-Type Builder
  • How to add custom admin panel pages
  • How to customize the login page
  • How to override admin panel translations

Why It Matters

A white-labeled admin panel provides a professional experience for your content team. Custom fields let you build specialized input interfaces that are better than generic text fields. These customizations turn Strapi from a generic CMS into a tailored content management tool that matches your brand and workflow.

Real-World Use

A digital agency manages 20 client websites, each running Strapi. Each client needs their own branded admin panel. The agency uses admin panel customization to set each client's logo, colors, and login page. Content editors feel like they are using a custom-built CMS, not a generic tool. The agency also builds a custom "Map Location" field that provides a Google Maps picker instead of entering coordinates manually.

Learning Path

flowchart LR
  A["Custom Plugins"] --> B["Admin Customization
-- You are here"]:::current B --> C["Email & Notifications"] C --> D["Internationalization"] classDef current fill:#4945ff,color:#fff,stroke-width:2px

Logo and Brand Customization

Strapi allows basic branding through the admin panel settings:

// Method 1: Admin panel UI
// Settings > Administration Panel > Admin Panel Settings
// - Upload custom logo (recommended size: 300x80px)
// - Change primary brand color
// - Upload favicon

// Method 2: Configuration file
// src/admin/app.js (Strapi 5)
export default {
  config: {
    head: {
      favicon: "/uploads/logo-favicon.png",
    },
    auth: {
      logo: "/uploads/auth-logo.png",  // Login page logo
    },
    menu: {
      logo: "/uploads/menu-logo.png",  // Sidebar logo
    },
    theme: {
      colors: {
        primary100: "#f0f5ff",
        primary200: "#d6e4ff",
        primary500: "#4f46e5",  // Main brand color
        primary600: "#4338ca",
        primary700: "#3730a3",
        buttonPrimary500: "#4f46e5",
        buttonPrimary600: "#4338ca",
      },
    },
    locales: ["en", "fr", "de"],
    translations: {
      en: {
        "app.components.LeftMenu.navbrand.title": "My CMS",
        "app.components.LeftMenu.navbrand.workplace": "Content Management",
        "Auth.form.welcome.title": "Welcome to My CMS",
        "Auth.form.welcome.subtitle": "Log in to manage your content",
      },
    },
  },
};

The logo files should be stored in the public/uploads/ directory or hosted on your CDN.

Custom Login Page

Customize the login page beyond just the logo:

// src/admin/app.js
export default {
  config: {
    auth: {
      logo: "/uploads/custom-logo.png",
    },
    head: {
      favicon: "/uploads/favicon.ico",
    },
    // Customize the login page background
    theme: {
      colors: {
        // Override login page specific colors
      },
    },
    translations: {
      en: {
        "Auth.form.email.label": "Work Email",
        "Auth.form.password.label": "Password",
        "Auth.form.login.title": "Sign in to Dashboard",
        "Auth.form.register.title": "Create your account",
      },
    },
  },
};

Custom Fields

Custom fields are reusable input components that appear in the Content-Type Builder and Content Manager.

// src/admin/custom-fields/ColorPicker/index.js
import React from "react";
import { useCMEditViewDataManager } from "@strapi/helper-plugin";
import { Box, Typography, Field } from "@strapi/design-system";

const ColorPicker = ({ name, value, onChange, attribute }) => {
  const colors = attribute.options?.colors || [
    "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF"
  ];

  return (
    <Box padding={4}>
      <Typography variant="pi" fontWeight="bold">{attribute.customField}</Typography>
      <Box padding={2} style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
        {colors.map((color) => (
          <button
            key={color}
            type="button"
            onClick={() => onChange({ target: { name, value: color } })}
            style={{
              width: 32,
              height: 32,
              borderRadius: "50%",
              backgroundColor: color,
              border: value === color ? "3px solid #000" : "2px solid transparent",
              cursor: "pointer",
            }}
            aria-label={`Select color ${color}`}
          />
        ))}
      </Box>
      {value && (
        <Typography variant="pi" textColor="neutral600">
          Selected: {value}
        </Typography>
      )}
    </Box>
  );
};

export default ColorPicker;

Register the custom field in a plugin:

// src/plugins/my-custom-fields/admin/src/index.js
import ColorPicker from "./components/ColorPicker";

export default {
  register(app) {
    app.customFields.register({
      name: "color-picker",
      pluginId: "my-custom-fields",
      type: "string",  // Database type
      intlLabel: {
        id: "my-custom-fields.color-picker.label",
        defaultMessage: "Color Picker",
      },
      intlDescription: {
        id: "my-custom-fields.color-picker.description",
        defaultMessage: "Select a color from a predefined palette",
      },
      icon: "paint-brush",
      components: {
        Input: async () => ColorPicker,
      },
      options: {
        base: [
          {
            section: "styles",
            items: [
              {
                name: "options.colors",
                type: "json",
                intlLabel: {
                  id: "my-custom-fields.color-picker.options.colors",
                  defaultMessage: "Available colors (JSON array of hex values)",
                },
              },
            ],
          },
        ],
      },
    });
  },
};

Adding Custom Admin Pages

Add entirely new pages to the admin panel through plugins:

// admin/src/index.js (in a plugin)
export default {
  register(app) {
    // Add a page accessible from the main navigation
    app.addMenuLink({
      to: "/plugins/content-dashboard",
      icon: "Dashboard",
      intlLabel: {
        id: "content-dashboard.plugin.name",
        defaultMessage: "Dashboard",
      },
      Component: async () => {
        const component = await import("./pages/Dashboard");
        return component;
      },
      permissions: [],
    });

    // Add a settings page
    app.addSettingsLink({
      id: "content-dashboard-settings",
      to: "/settings/content-dashboard",
      intlLabel: {
        id: "content-dashboard.settings",
        defaultMessage: "Content Dashboard",
      },
      Component: async () => {
        const component = await import("./pages/Settings");
        return component;
      },
    });

    // Inject a component into an existing view
    app.injectContentManagerComponent("editView", "right-links", {
      name: "publish-history",
      Component: async () => {
        const component = await import("./components/PublishHistory");
        return component;
      },
    });
  },
};

Customizing the Content Manager View

Modify how content types appear in the Content Manager:

// src/admin/extensions/content-manager/index.js
export default {
  bootstrap(app) {
    // Customize the list view configuration per content type
    app.getPlugin("content-manager").apis.configureContentView({
      contentType: "api::article.article",
      config: {
        settings: {
          bulkable: true,
          filterable: true,
          searchable: true,
          pageSize: 20,
          mainField: "title",  // Field shown in list
          defaultSortBy: "createdAt",
          defaultSortOrder: "DESC",
        },
        metadatas: {
          id: { edit: {}, list: { label: "ID" } },
          title: { edit: { label: "Article Title" }, list: { label: "Title" } },
          createdAt: { edit: { label: "Created" }, list: { label: "Created" } },
        },
        layouts: {
          list: ["id", "title", "author", "createdAt"],
          edit: [
            [
              { name: "title", size: 6 },
              { name: "author", size: 6 },
            ],
            [{ name: "content", size: 12 }],
          ],
        },
      },
    });
  },
};

Theme and Styles

Override admin panel styles with custom CSS:

// src/admin/extensions/theme.js
const theme = {
  colors: {
    primary100: "#eef2ff",
    primary200: "#c7d2fe",
    primary500: "#6366f1",
    primary600: "#4f46e5",
    primary700: "#4338ca",
    danger100: "#fef2f2",
    danger500: "#ef4444",
    success100: "#f0fdf4",
    success500: "#22c55e",
    warning100: "#fffbeb",
    warning500: "#f59e0b",
  },
  shadows: {
    popupShadow: "0px 2px 4px rgba(0, 0, 0, 0.1)",
  },
  sizes: {
    borderRadius: "6px",
  },
};

export default theme;

Common Mistakes

  1. Using oversized logo images. The admin panel logo should be optimized for web. Large logo files slow down the admin panel load time. Use a PNG or SVG under 50KB.

  2. Customizing too heavily without testing. Aggressive theme changes can break the admin panel layout. Test customizations in development before applying to production.

  3. Not handling custom field edge cases. Custom fields should handle empty values, loading states, and validation errors gracefully. A broken custom field blocks content creation.

  4. Forgetting to rebuild after admin changes. Admin panel customizations require npm run build to compile. Changes do not appear until the build is complete.

  5. Overriding translations incompletely. If you override some translations but not others, the admin panel shows a mix of custom and default text. Provide complete translation overrides.

Practice Questions

  1. Where do you configure the admin panel logo and colors? Answer: In src/admin/app.js (Strapi 5) or through the admin panel UI at Settings > Administration Panel > Admin Panel Settings.

  2. What is a custom field and how does it differ from a component? Answer: A custom field is a new input type for the Content-Type Builder that provides a specialized editing experience (like a color picker or map selector). A component is a reusable group of fields.

  3. How do you add a custom page to the admin panel? Answer: Through a plugin's register function using app.addMenuLink() to add a navigation item that links to a custom React component page.

  4. Challenge: Create a fully branded admin panel: (1) Upload a custom logo and set brand colors, (2) Customize the login page with custom welcome text, (3) Build a custom "Star Rating" field that provides a 1-5 star clickable rating input, (4) Register the custom field in the Content-Type Builder, (5) Create a custom "Content Overview" dashboard page showing recent entries and pending reviews, (6) Test all customizations across different browsers.

FAQ

Can I change the admin panel URL from /admin to something else?

Strapi does not have a built-in setting for this. Use a reverse proxy (nginx, Caddy) to rewrite the URL path, or configure the server.admin.url option in config/server.js for more advanced setups.

Do custom fields work with the Content-Type Builder's API?

Yes. Custom fields behave like native fields in the API. They store data in the database and appear in API responses. The custom Input component only affects the admin panel editing experience.

Can I have different themes for different admin users?

Strapi does not support per-user theming. The theme is global for the entire admin panel. You would need a custom plugin to implement per-user theme preferences.

How do I reset the admin panel to default?

Remove or comment out the customizations in src/admin/app.js and run npm run build. The panel reverts to the default theme.

Can I customize the admin panel without building a plugin?

Yes. Basic customizations (logo, colors, translations) can be done directly in src/admin/app.js without a plugin. Custom fields, pages, and component injections require a plugin.

Mini Project

Your task: Customize Strapi for a branded client experience.

  1. Set up a branded theme:
    • Replace the logo with a custom SVG
    • Change the primary color to the brand color (#2563eb)
    • Customize the login page title to "Client Content Manager"
  2. Build a custom "URL Slug" field that:
    • Takes a string input
    • Shows a preview of the full URL
    • Auto-generates from a title field if left empty
    • Validates URL-safe characters only
  3. Add a custom "Content Overview" dashboard page that:
    • Shows total entries per content type
    • Lists recently modified entries
    • Shows entries pending review
  4. Apply the custom field to one of your content types.

What's Next

Now that you can customize the admin panel, proceed to Email & Notifications to configure the email plugin, send transactional emails, and customize email templates. After that, explore Internationalization for multi-language content.

Related lessons:

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro