Skip to content
Twilight React Playground
ثيم رائدaren

MasterLayout

componentBeginnerserverbrowser

The default page frame: header, main content and footer, plus the login, offer and branch pop-ups a storefront needs.

import { MasterLayout, LayoutProps } from '@salla.sa/twilight-theme-engine/components/layout';

In plain words

Every store page shares a frame: the header with the logo and menu at the top, the footer at the bottom, and the page's own content in between. MasterLayout is that frame. TwilightProvider already wraps every page in it, so a theme gets it without writing anything.

You render it yourself only when you give TwilightProvider a layout of your own and still want the standard frame inside it. See it around the real pages in Built-in pages.

Signature

const MasterLayout: LazyExoticComponent<(props: LayoutProps) => JSX.Element>

interface LayoutProps {
  children: ReactNode;
}

Example

app/components/ThemeLayout.tsx
import { Suspense } from 'react';
import { MasterLayout, type LayoutProps } from '@salla.sa/twilight-theme-engine/components/layout';
import { AnnouncementBar } from './AnnouncementBar';

// In app/routes/__root.tsx: <TwilightProvider translations={…} layout={ThemeLayout}>
export function ThemeLayout({ children }: LayoutProps) {
  return (
    <Suspense fallback={null}>
      <MasterLayout>
        <AnnouncementBar />
        {children}
      </MasterLayout>
    </Suspense>
  );
}

How it behaves

  • It renders <div className="app-inner flex flex-col min-h-full"> holding Header, then <main id="main-content" role="main" className="flex-1"> with the page, then Footer.

  • Beside that div it renders the offer pop-up, the login modal (only while no customer is logged in, configured from store.settings.auth) and the branch picker (only when the store has a scope; mandatory when store.scope.display_as is popup).

  • TwilightProvider uses it as its layout by default, once the provider is ready. layout={MyLayout} replaces it and layout={false} renders pages with no frame.

  • The provider's default is an internal, eager copy. This export is lazy (code-split), so render it inside <Suspense>.

  • Its header can be sticky and its menus depend on the viewport width, which a small demo box cannot show honestly: Built-in pages renders it around every engine page at three widths.

  • To add content above the header or below the footer without a layout of your own, register handlers for the header:start and footer:end hook slots.

  • @salla.sa/twilight-theme-engine/layout is the same module.

Gotchas

  • Rendering MasterLayout (or Header and Footer) inside your pages while TwilightProvider keeps its default layout gives two headers and two footers. docs/04-layout-system.md ("Extending Layouts in Custom Themes") renders Header and Footer inside the provider exactly like that. Pass your frame as the provider's layout instead.

Related

Source and docs