Magento 2: How to Set a Theme on a Specific Page

Learn how to apply a different Magento theme to a specific frontend page using a custom module, observer, and route configuration.

Overview

Magento 2 allows developers to assign different themes to different storefronts. However, there are situations where you may want to display a completely different theme for only one specific page. In this tutorial, we'll create a custom route and use an observer to dynamically switch the theme when a user visits that page.

Step 1: Create routes.xml

Create the following file:

app/code/Vendor/Extension/etc/frontend/routes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="frontroute" frontName="frontroute">
            <module name="Vendor_Extension"/>
        </route>
    </router>
</config>

This route creates a custom frontend URL: /frontroute/index/index

Step 2: Create Controller

app/code/Vendor/Extension/Controller/Index/Index.php
<?php

namespace Vendor\Extension\Controller\Index;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\PageFactory;

class Index implements HttpGetActionInterface
{
    protected $resultPageFactory;

    public function __construct(PageFactory $resultPageFactory)
    {
        $this->resultPageFactory = $resultPageFactory;
    }

    public function execute(): ResultInterface
    {
        return $this->resultPageFactory->create();
    }
}

Step 3: Create Layout File

app/code/Vendor/Extension/view/frontend/layout/frontroute_index_index.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
layout="1column"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

    <body>
        <referenceContainer name="content">
            <block
                name="index.index"
                class="Vendor\Extension\Block\Index\Index"
                template="Vendor_Extension::index/index.phtml"/>
        </referenceContainer>
    </body>

</page>

Step 4: Create Template File

app/code/Vendor/Extension/view/frontend/templates/index/index.phtml
<?php
/**
 * @var $block \Vendor\Extension\Block\Index\Index
 */
?>

<h2>This page is Magento Blank theme.</h2>

Step 5: Create Block Class

app/code/Vendor/Extension/Block/Index/Index.php
<?php

namespace Vendor\Extension\Block\Index;

class Index extends \Magento\Framework\View\Element\Template
{
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }
}

Step 6: Create Event Configuration

app/code/Vendor/Extension/etc/events.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">

    <event name="layout_load_before">
        <observer
            name="observer_name"
            instance="Vendor\Extension\Observer\SetThemePage"/>
    </event>

</config>

Step 7: Create Observer Class

app/code/Vendor/Extension/Observer/SetThemePage.php
<?php

namespace Vendor\Extension\Observer;

use Magento\Framework\App\Request\Http;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\View\DesignInterface;

class SetThemePage implements ObserverInterface
{
    private Http $request;
    private DesignInterface $design;

    public function __construct(
        Http $request,
        DesignInterface $design
    ) {
        $this->request = $request;
        $this->design = $design;
    }

    public function execute(Observer $observer): void
    {
        $pathInfo = $this->request->getPathInfo();

        if (substr($pathInfo, 0, 11) === '/frontroute') {
            $this->design->setDesignTheme('Magento/blank');
        }
    }
}

Deploy Changes

Run the following Magento commands:

php bin/magento setup:upgrade

php bin/magento setup:static-content:deploy -f

php bin/magento setup:di:compile

php bin/magento cache:flush

Result

After completing the above steps, when users visit:

https://your-domain.com/frontroute/index/index

Magento will automatically load the Magento Blank Theme only for this page while the rest of the storefront continues using the default theme.

Important Notes

  • Replace Magento/blank with your custom theme if needed.
  • Ensure your custom Theme is enabled.
  • Clear Magento cache after changing themes.
  • For production environments, always redeploy static content after theme changes.