Skip to main content

Interface 1.2+ Any HTML can be your layout

With slots and directives you have all the tools you need to:

  • render into specific areas of the layout using slots
  • control any aspect of your app using directives

Slots and directives lets you decouple content from the layout, so you can use any layout you want, even have multiple layouts for different parts of your app.

Take any HTML, set where content should be rendered using the slot targets, connect directives to control any aspect of your app (layout, theme, etc.) and you have a custom layout.

my-custom-layout.tsx
import { Slots } from "@contember/layout"
import { PropsWithChildren } from "react"
import { useDirectives } from "./components/Directives"
import { SlotTargets } from "./components/Slots"

const { Actions, Back, Logo, Navigation, Sidebar, Title, Profile, Subtitle, Switchers, ...rest } = SlotTargets

// Make sure we implement all the slots:
if (import.meta.env.DEV) {
const __EMPTY_REST_GUARD: { [key: string]: never } = rest
}

export function MyCustomLayout({ children }: PropsWithChildren) {
const slotTargetsIfActive = Slots.useTargetsIfActiveFactory(SlotTargets)

const directives = useDirectives()

return (
<div className="layout" data-full-width={directives ? true : undefined}>
{slotTargetsIfActive(['Logo', 'Actions'], (
<header className="layout__header">
<Logo />
<Actions />
<Profile />
</header>
))}
{slotTargetsIfActive(['Navigation'], (
<aside className="layout__aside">
<Navigation />
</aside>
))}
<main className="layout__main">
<section className="layout__main__content">
{slotTargetsIfActive(['Back', 'Title'], (
<>
<Back />
<Title as="h1" />
</>
))}
{slotTargetsIfActive(['Subtitle'])}
{children}
</section>

{slotTargetsIfActive(['Sidebar'], (
<section className="layout__main__sidebar">
<Sidebar />
</section>
))}
</main>


{slotTargetsIfActive(['Profile', 'Switchers'], (
<footer className="layout__footer">
<Switchers />
<Profile />
</footer>
))}
</div>
)
}

Using your custom layout

Now that we have a layout, we need to connect it with Contember, swap it anytime you need.

admin/components/Layout.tsx
import * as React from 'react'
import { MyCustomLayout } from '../my-custom-layout'

export const Layout = ({
children: pages,
}: React.PropsWithChildren) => (
<>
<MyCustomLayout>
{pages}
</MyCustomLayout>
</>
)