Template Inheritence
Most web applications have a common structure shared by many pages, such as a navigation bar, a header, a footer, and a main content area.
Repeating this structure in every template makes your code harder to maintain. If you need to change the navigation, for example, you would have to update every page that contains it.
PyBlade lets you define this shared structure once as a base layout. You can define a shared layout once and let your other templates extend it, keeping the common structure in one place while each page provides its own content.
This is called template inheritance.
Defining a Layout
A layout is a reusable template that provides the common structure shared by multiple pages. Other templates can then inherit this layout and provide the content specific to each page.
Let's start with a simple base layout:
<html>
<head>
<title>My App - {{ title }}</title>
</head>
<body>
<header>
<h1>Welcome to My App</h1>
</header>
<aside>
...
</aside>
<main>
@block("content")
<p>Nothing to display yet.</p>
@endblock
</main>
<footer>
© @now('%Y') - My App
</footer>
</body>
</html>The important part here is the @block directive. A block defines a named area of the layout that child templates can replace.
In this example, content has some default content. If a child template does not provide its own content block, this default content will be displayed.
You can define as many blocks as your layout needs:
@block("header")
<h1>Welcome to My App</h1>
@endblock
@block("content")
<p>Nothing to display yet.</p>
@endblockWe'll see how child templates override these blocks in the next section.
You'll also notice the title variable in the <title> element. Rather than making the page title a block, we'll use a named slot so that each child template can provide its own title.
Extending a Layout
Once you have a layout, a child template can inherit it using the @extends directive:
@extends("layouts.base")The value passed to @extends uses dot notation to identify the layout file. So layouts.base refers to templates/layouts/base.html.
PyBlade also supports regular file paths, meaning you could write @extends("layouts/base.html") instead.
After extending a layout, the child template can provide content for the blocks defined by the parent. Child templates use the @block directive to override a block:
@extends("layouts.base")
<pb-slot name="title">Home</pb-slot>
@block("content")
<p>Welcome to the home page!</p>
@endblockWhen PyBlade renders this template, the content of @block("content") replaces the corresponding @block("content") in the parent layout.
If the parent defined default content for that block, the child's block replaces it completely.
Adding to existing content
Sometimes you don't want to completely replace the content provided by the parent. You may want to keep it and add something of your own.
For this, PyBlade provides the @parent directive:
@block("sidebar")
@parent
<p>This content is added to the sidebar.</p>
@endblock@parent keeps the parent's content and places the child's content after it.
For example, if the parent contains:
<aside>
@block("sidebar")
<p>Default sidebar content.</p>
@endblock
</aside>the child can keep that content and add more:
@block("sidebar")
@parent
<p>This content comes from the child template.</p>
@endblockThe default slot
Not all content in a child template needs to be inside a block.
Any content in the child template that is not inside a @block directive is automatically collected into a default slot named slot.
For example:
@extends("layouts.base")
<h1>Welcome to my page!</h1>
<p>This content is not inside a block.</p>The parent layout can display this content using:
<main>
{{ slot }}
</main>By default, the slot value is not escaped, which means you can use it to render the HTML produced by the child template.
The default slot is simply a convenient way to pass the main content of a child template without having to create a named block for it.
You can also create your own named slots when you need to pass other pieces of content to the layout.
Named slots
Named slots are useful when a child template needs to provide a specific value or piece of content to the layout.
For example, the page title can be provided with a named slot:
<pb-slot name="title">Home</pb-slot>The parent layout can then access it as a variable:
<title>My App - {{ title }}</title>This allows each child template to provide its own title while keeping the <title> element in the layout.
Named slots are not limited to titles. You can create as many named slots as your layout requires.