🌟
|
Migrating from Bookshop 2.0 to 3.0? Read the Migration Guide first. |
Bookshop defines conventions for writing static components for Hugo. Using these conventions, Bookshop provides an ergonomic way to build pages out of your components, build and browse these components locally, and generate rich live editing experiences in CloudCannon.
For an example of what this looks like in a real-world example, see our Editing MegaKit with Bookshop video.
-
Bookshop requires Node >= 16 installed on your machine.
-
This guide expects that you already have Hugo installed on your machine.
-
Since Hugo Bookshop utilizes the Hugo module system, the Go Programming Language needs to be installed on your machine.
💡
|
Short on time? You can use our Hugo Bookshop Starter Template and jump straight into editing it in CloudCannon. Come back here when you want to build it out further, or create your own from scratch. |
This guide will walk you through getting Bookshop connected to an existing Hugo site. If you don’t have a site already,
running hugo new site mysite
is a good start.
Alternatively, grab one of CloudCannon’s preconfigured Hugo templates.
The first step is to create the directory structure for your Bookshop. To create this structure, you can run the following command in the root of your repository:
npx @bookshop/init --new component-library --framework hugo
This command should provide you with the following directory structure:
component-library/
├─ config.toml
├─ bookshop/
│ └─ bookshop.config.cjs
├─ components/
│ └─ sample/
│ ├─ sample.bookshop.yml
│ ├─ sample.scss
│ └─ sample.hugo.html
└─ shared/
├─ hugo
│ └─ page.hugo.html
└─ styles/
└─ global.scss
Here’s a quick run-through of what has been generated:
- config.toml
-
This file registers your component library as a Hugo Module. This will allow us to use it as a dependency for your site.
- bookshop/bookshop.config.cjs
-
This houses the configuration for your Bookshop project, in this case instructing Bookshop to use the
@bookshop/hugo-engine
package for any live component rendering. - components/
-
This is where you will write your component files, a sample component has been added for you.
- shared/hugo/
-
Any non-component files that you want to be able to use when live editing can be placed here. A page helper has been created, which helps render arrays of components.
- shared/styles/
-
Any SCSS files in this directory will be imported alphabetically before component SCSS files. These are used on both the site, and the component browser.
Creating these files yourself?
Bookshop File Reference
[module]
hugoVersion.extended = true
hugoVersion.min = "0.86.1"
[[module.mounts]]
source = "."
target = "layouts/partials/bookshop"
includeFiles = ["**/*.hugo.html"]
[[module.mounts]]
source = "."
target = "assets/bookshop"
module.exports = {
engines: {
"@bookshop/hugo-engine": {}
}
}
We’ll cover creating components and shared files in Authoring New Components.
Bookshop is distributed as a Hugo Module, so the first step is to make sure that your Hugo site is set up for the Hugo Module system. If there isn’t a go.mod
file in your site root, run hugo mod init site.local
to initialize this.
With your site ready, we need to pull in the primary dependency of bookshop/hugo
, as well as the component library we just created.
The following should be placed in your Hugo site config (usually config.toml
in your root folder).
[module]
replacements = "components.local -> ../component-library"
[[module.imports]]
path = 'components.local'
[[module.imports]]
path = 'github.com/cloudcannon/bookshop/hugo/v3'
Adjust the ../component-library
path in replacements
if you created it with a different name, or in a different place.
💡
|
This path is relative to the Hugo themes directory (whether or not it exists), hence ../component-library actually points to a component library in your Hugo source directory.
|
With that configuration in place, running hugo serve
should download the required module and host your site. Nothing will appear different yet, but we now have access to use components.
Lastly, we’ll need to install a few npm packages for Bookshop. These aren’t used as part of your production build, but they provide the developer tooling that enables structured data and live editing.
These packages should be installed at the root of the repository that contains your site. If this folder doesn’t have a package.json
file yet, run npm init -y
to create one.
To get setup, run the following command to install the needed Bookshop packages:
# npm
npm i --save-exact @bookshop/generate @bookshop/browser @bookshop/hugo-engine
# or yarn
yarn add --exact @bookshop/generate @bookshop/browser @bookshop/hugo-engine
🌟
|
Bookshop uses a fixed versioning scheme, where all packages are released for every version. It is recommended that you keep the npm packages and your plugins at the same version. To help with this, you can run npx @bookshop/up@latest from your repository root to update all Bookshop packages in sync.
|
If you ran the @bookshop/init
command earlier, you should see that you now have a file at components/sample/sample.hugo.html
. Let’s have a go using that component somewhere on our site.
💡
|
Bookshop supports multiple SSG targets, which is why we denote this as .hugo.html .
|
💡
|
We’ll cover creating these components soon — if you want to add a new component now, you can run npx @bookshop/init --component <name> in your Bookshop directory to scaffold it out automatically.
|
Bookshop provides a range of partials which we will cover. The most important of these is the default bookshop
partial that we will use to access our components.
To start, add the following snippet to one of your layouts:
...
{{ partial "bookshop" (slice "sample" (dict "text" "Hello from the sample component")) }}
...
This partial expects a slice where the first element is the Bookshop name of a component, and the second element contains the arguments to that component.
If you now load your Hugo site in a browser, you should see the sample component rendered on the page. There won’t be any styles yet, we’ll cover that soon. First though, there are a few neater ways you can use the bookshop
partial:
Writing a Hugo dict
by hand can be cumbersome, and these will often point to front matter objects. If you have the front matter:
sample:
text: Hello World
Then you can replace the partial we just wrote with the following:
...
{{ partial "bookshop" (slice "sample" .Params.sample) }}
...
To go one step further, you can add the key _bookshop_name
to this object:
sample:
_bookshop_name: sample
text: Hello World
Which lets us pass the object directly to the bookshop
partial:
...
{{ partial "bookshop" .Params.sample }}
...
💡
|
The Bookshop name of a component is the path to its directory. So the name for components/sample/sample.hugo.html is sample ,and the name for components/generic/button/button.hugo.html would be generic/button .
|
💡
|
The structures generated by Bookshop for CloudCannon include a _bookshop_name field for you, which can be used to render components dynamically. We’ll cover this a bit later on in Connecting Bookshop to CloudCannon.
|
Shared Bookshop helpers can be placed in the shared/hugo
directory. i.e:
component-library/
├─ components/
└─ shared/
└─ hugo/
└─ helper.hugo.html
This can then be included using the bookshop_partial
partial:
{{ partial "bookshop_partial" (slice "helper" (dict "lorem" "ipsum")) }}
The arguments are the same as the bookshop
partial. This is otherwise a standard Hugo partial, with the extra feature that it can be used anywhere within your Hugo site or your components.
ℹ️
|
While developing locally, components will have access to the rest of your site. This isn’t true when live editing, which is why these helper files exist. |
You will notice that @bookshop/init
created a page.hugo.html
file for you. Given the following front matter:
content_blocks:
- _bookshop_name: hero
hero_text: Hello World
image: /image.png
- _bookshop_name: cta
heading: Join our newsletter
location: /signup
You can render the array of components using the page helper like so:
{{ partial "bookshop_partial" (slice "page" .Params.content_blocks) }}
This will loop through the given array, and render each component according to its _bookshop_name
key.
Give this a try now — replace the sample component you added with the page
helper, and add the following to your front matter:
content_blocks:
- _bookshop_name: sample
text: A sample example
- _bookshop_name: sample
text: A second sample example
🌟
|
It is essential to render arrays of components using the page helper. Live editing only works within Bookshop components and helpers, so using this method means that rearranging and adding new components will work in the Visual Editor. |
Bookshop provides some helpers for including the component and global styles that you defined in your component library.
ℹ️
|
Locating styles inside your Bookshop is optional — you can always define them with the rest of your site — but authoring your styles in your component library will provide a better experience when we cover using the local component browser. |
@bookshop/init
created a sample.scss
file for you at components/sample/sample.scss
. This file will currently be empty, but you should add a style here to test that the Bookshop SCSS integration is working for you. Something like:
.c-sample {
background-color: blanchedalmond;
}
To include all of your Bookshop styles in Hugo, you can use the bookshop_scss
partial in your baseof.html
layout. This partial returns a slice of all SCSS files, which can then be included into your existing Hugo resource pipeline:
{{ $bookshop_scss_files := partial "bookshop_scss" . }}
{{ $scss := $bookshop_scss_files | resources.Concat "css/bookshop.css" | resources.ToCSS | resources.Minify |
resources.Fingerprint }}
<link rel="stylesheet" href="{{ $scss.Permalink }}">
🌟
|
Bookshop SCSS files are loaded in order of all shared files, followed by all component files, alphabetically. |
💡
|
To create new components, you can simply run npx @bookshop/init --component <name> in an existing Bookshop
|
Components live within the components/
directory, each inside a folder bearing their name. A component is defined with a <name>.bookshop.<format>
file. This file serves as the schema for the component, defining which properties it may be supplied.
Components may also be nested within folders, which are then referenced as part of the component name. For example, the following structure would define the components hero
, button/large
and button/small
:
components/
├─ hero/
| | hero.bookshop.yml
| └─ hero.hugo.html
└─ button/
├─ large/
| | large.bookshop.yml
│ └─ large.hugo.html
└─ small/
| small.bookshop.yml
└─ small.hugo.html
Beyond the naming convention, Bookshop template files are what you would expect when working with Hugo. A basic button component might look like the following:
<a class="c-button" href="{{ .link_url }}">{{ .link_text }}</a>
Components can, of course, reference other components:
<h1>{{ .hero_text }}</h1>
{{ partial "bookshop" (slice "button" (dict "link_url" .url "link_text" "Click me")) }}
A <component>.scss
file can be written alongside your other component files. Beyond the location and the automatic import, there is nothing special about the contents of this file.
The Bookshop file for each component is the most important piece of the Bookshop ecosystem. This file drives the Structured Data in CloudCannon, the local component browser, and Bookshop’s live editing.
The sample.bookshop.yml
file that our init command generated contains the following:
sample.bookshop.yml
# Metadata about this component, to be used in the CMS
spec:
structures:
- content_blocks
label: Sample
description:
icon:
tags:
# Defines the structure of this component, as well as the default values
blueprint:
text: "Hello World!"
# Overrides any fields in the blueprint when viewing this component in the component browser
preview:
# Any extra CloudCannon inputs configuration to apply to the blueprint
_inputs: {}
Let’s walk through an example file section by section to understand what’s going on.
spec:
structures:
- content_blocks
label: Example
description: An example Bookshop component
icon: book
tags:
- example
This section is used when creating the Structure for your component. The structures
array defines which structure keys to register this component with. In other words, with the above snippet, this component will be one of the options within an array named content_blocks
, or another input configured to use _structures.content_blocks
.
The other keys are used when the component is displayed in CloudCannon or in the Bookshop Component Browser. icon
should be the name of a suitable material icon to use as the thumbnail for your component.
blueprint:
text: Hello World!
The blueprint is the primary section defining your component. This will be used as the intitial state for your component when it is added to a page, and should thus include all properties used in your template.
preview:
text: Vestibulum id ligula porta felis euismod semper.
Your blueprint represents the initial state of your component, but in the component browser you might want to see a preview of your component filled out with example data.
The preview object will be merged with your blueprint before a component is rendered in the component browser. This is a deep merge, so given the following specification:
blueprint:
hero_text: "Hello World"
cta:
button_text: ""
button_url: "#"
preview:
cta:
button_text: "Click me"
Your component preview data will be:
hero_text: "Hello World"
cta:
button_text: "Click me"
button_url: "#"
ℹ️
|
In a future Bookshop release, component thumbnails will be automatically generated. This will also use the preview object. |
_inputs:
text:
type: "html"
comment: "This comment will appear in the CMS"
The _inputs
section of your Bookshop file can be used to configure the keys in your blueprint. This object is passed through unaltered to CloudCannon, so see the CloudCannon Inputs Documentation to read more.
This configuration is scoped to the individual component, so you can configure the same key differently across components — even if the components are nested within one another.
Arrays of objects in your blueprint will be transformed into CloudCannon Structures automatically, and initialized as empty arrays. Using the following Blueprint:
blueprint:
text: Sample Text
items:
- item_content: Hello World
A new component added to the page will take the form:
text: Sample Text
items: []
Editors will then be able to add and remove objects to the items
array.
Your blueprint can reference other components and structures to create rich page builder experiences:
blueprint:
hero_text: Hello World
button: bookshop:button
In this example, the button
key will become an Object Structure containing the values specified in your button
component blueprint. If you desired an array of buttons, you could use the following:
blueprint:
hero_text: Hello World
buttons: [bookshop:button] # equivalent
buttons:
- bookshop:button # equivalent
If you’re creating a layout component, you likely want to support a set of components. For this, you can reference the keys we defined in spec.structures
as such:
blueprint:
section_label: My Section
# Make header a single component that can be selected from the content_blocks set
header: bookshop:structure:content_blocks
# Make inner_components an array that can contain components marked content_blocks
inner_components: [bookshop:structure:content_blocks]
To give a concrete example, say we have the following hero.bookshop.yml
file:
spec:
structures: [content_blocks]
blueprint:
hero_text: Hello World
cta_button: bookshop:button
column_components: [bookshop:structure:content_blocks]
Then our hero.hugo.html
file to render this might look like the following:
<div class="hero">
<h1>{{ .hero_text }}</h1>
{{ with .cta_button }}
{{ partial "bookshop" . }}
{{ end }}
<div class="column">
{{ range .column_components }}
{{ partial "bookshop" . }}
{{ end }}
</div>
</div>
🌟
|
Object Structures in CloudCannon may be empty, so testing for the existence of this component in your template is recommended. |
By default, nested components using the bookshop:
shorthand will be initialized empty. For example, the blueprint:
blueprint:
hero_text: Hello World
button: bookshop:button
Will be initialized in CloudCannon as:
hero_text: Hello World
button:
Where button
will provide an editor with the option to add a button component. To instead have the button component exist on creation, you can use the syntax bookshop:button!
:
blueprint:
hero_text: Hello World
button: bookshop:button!
The same setting can be applied to a structure shorthand by specifying the component that should be initialized. Taking the following example:
blueprint:
hero_text: Hello World
column_components:
- bookshop:structure:content_blocks!(hero)
- bookshop:structure:content_blocks!(button)
This will be initialized in CloudCannon as:
hero_text: Hello World
column_components:
- _bookshop_name: hero
# hero fields
- _bookshop_name: button
# button fields
Where column_components
can be then further added to/removed from by an editor, as per the tagged structure.
💡
|
When you run npx @bookshop/init --component <name> you will be prompted to pick which configuration format you want to create the component with.
|
In the examples above, we have been writing the Bookshop configuration files using YAML. This is the recommended format, but you can also choose another if you prefer. Here is a real-world example of a component written in each supported format:
hero.bookshop.yml
# Metadata about this component, to be used in the CMS
spec:
structures:
- content_blocks
- page_sections
label: Hero
description: A large hero component suitable for opening a landing page
icon: crop_landscape
tags:
- Above the Fold
- Multimedia
# Defines the structure of this component, as well as the default values
blueprint:
hero_text: ""
hero_level: h1
hero_image: ""
hero_image_alt: ""
subcomponents: [bookshop:structure:content_blocks]
# Overrides any fields in the blueprint when viewing this component in the component browser
preview:
hero_text: Bookshop Makes Component Driven Development Easy
hero_image: https://placekitten.com/600/400
# Any extra CloudCannon inputs configuration to apply to the blueprint
_inputs:
hero_level:
type: select
options:
values:
- h1
- h2
- h3
- h4
hero.bookshop.toml
# Metadata about this component, to be used in the CMS
[spec]
structures = [ "content_blocks", "page_sections" ]
label = "Hero"
description = "A large hero component suitable for opening a landing page"
icon = "crop_landscape"
tags = [ "Above the Fold", "Multimedia" ]
# Defines the structure of this component, as well as the default values
[blueprint]
hero_text = ""
hero_level = "h1"
hero_image = ""
hero_image_alt = ""
subcomponents = [ "bookshop:structure:content_blocks" ]
# Overrides any fields in the blueprint when viewing this component in the component browser
[preview]
hero_text = "Bookshop Makes Component Driven Development Easy"
hero_image = "https://placekitten.com/600/400"
# Any extra CloudCannon inputs configuration to apply to the blueprint
[_inputs]
hero_level.type = "select"
hero_level.options.values = [ "h1", "h2", "h3", "h4" ]
hero.bookshop.js
module.exports = () => {
const spec = {
structures: [
"content_blocks",
"page_sections",
],
label: "Hero",
description: "A large hero component suitable for opening a landing page",
icon: "crop_landscape",
tags: [
"Above the Fold",
"Multimedia",
]
};
const blueprint = {
hero_text: "",
hero_level: "h1",
hero_image: "",
hero_image_alt: "",
subcomponents: [ "bookshop:structure:content_blocks" ],
};
const preview = {
hero_text: "Bookshop Makes Component Driven Development Easy",
hero_image: "https://placekitten.com/600/400",
};
const _inputs = {
hero_level: {
type: "select",
options: {
values: [
"h1",
"h2",
"h3",
"h4",
]
}
}
};
return {
spec,
blueprint,
preview,
_inputs,
}
}
hero.bookshop.json
{
"spec": {
"structures": [
"content_blocks",
"page_sections"
],
"label": "Hero",
"description": "A large hero component suitable for opening a landing page",
"icon": "crop_landscape",
"tags": [
"Above the Fold",
"Multimedia"
]
},
"blueprint": {
"hero_text": "",
"hero_level": "h1",
"hero_image": "",
"hero_image_alt": "",
"subcomponents": [ "bookshop:structure:content_blocks" ]
},
"preview": {
"hero_text": "Bookshop Makes Component Driven Development Easy",
"hero_image": "https://placekitten.com/600/400"
},
"_inputs": {
"hero_level": {
"type": "select",
"options": {
"values": [
"h1",
"h2",
"h3",
"h4"
]
}
}
}
}
💡
|
Can’t decide? You can always run npx @bookshop/up --format <format> to automatically convert all of your files if you change your mind.
|
When an editor is selecting a component in CloudCannon, the icon
from the component spec will be used as the thumbnail. You can provide a custom image to use instead by placing a <component>.preview.<format>
in your component directory. To provide a custom icon, which will be shown when viewing an array of components, you can also provide a <component>.icon.<format>
file.
components/
└─ hero/
| hero.bookshop.yml
├─ hero.preview.png
├─ hero.icon.svg
└─ hero.hugo.html
See the CloudCannon Structures Reference for extra keys that you can set in your component spec to control the display of these images.
|
Make sure that the config.toml file in your Bookshop has includeFiles = ["*/.hugo.html"] alongside the layouts mount.If this isn’t present, run npx @bookshop/up@latest in your component library to migrate this file.Without this configuration, your Hugo build will error when it enounters an image file in this directory. |
The Bookshop component browser allows you to browse and experiment with your components. When running in development the component browser also provides hot reloading of component templating and styles. An example browser showing the components in our Eleventy starter template can be seen here: https://winged-cat.cloudvent.net/components/
In your local development environment, run:
npx @bookshop/browser
By default, this will discover any Bookshop directories in or under the current working directory, and will host a component library on port 30775.
After running this command, a component browser will be viewable on http://localhost:30775
💡
|
Run npx @bookshop/browser --help to see the available options.
|
Coming Soon — Bookshop Hugo provides a helper for embedding the Bookshop browser in your website. This references the component browser started in the previous command, and embeds a live copy into your website.
This allows you to:
-
Rely on your site layouts and styles in your component
-
Host a component browser on a page of your built site
To install the component browser on a page of your site, use the bookshop_component_browser
partial in that page’s layout.
{{ partial "bookshop_component_browser" }}
If you’re running Hugo locally, open another terminal and run npx @bookshop/browser
in your Bookshop, or a parent directory. You should now be able to visit the page that you installed the component browser on, and see your components in a playground environment.
💡
|
If you’re running the browser command on a custom port, you can pass that port as an argument with
{{ partial "bookshop_component_browser" 1234 }}
|
Any page that contains the bookshop_component_browser
snippet will get picked up by npx @bookshop/generate
(See Connecting Bookshop to CloudCannon) and turned into a hosted component browser, no extra configuration is needed.
ℹ️
|
This guide assumes that your site is already set up with CloudCannon. If this isn’t the case, hop over to the CloudCannon Documentation and get setup with a successful build first. |
Now that you understand how everything works locally, we can integrate Bookshop with CloudCannon. Bookshop does most of the heavy lifting for you, so we’ll get to see the benefits pretty quickly.
The main thing you need to do is create a postbuild script that runs Bookshop’s generate script. This should be placed inside a folder named .cloudcannon
at the root of your repository.
npm i
npx @bookshop/generate
This command will automatically discover your component library as well as the output site from your build, and will then generate CloudCannon Structures for your components. This step will also connect live editing to any pages on your site that contain Bookshop components.
With Hugo, there is one extra step to get live editing working. For any components or helpers in your Hugo layouts, you will need to use the bookshop_bindings
partial to connect it to the page’s front matter.
For most setups, your site layouts will only contain the page
helper, so this snippet will be all you need:
{{ partial "bookshop_bindings" `.Params.content_blocks` }}
{{ partial "bookshop_partial" (slice "page" .Params.content_blocks) }}
If you’re using other components in your layouts, add the bookshop_bindings
partial to them. This partial needs to be passed a string representation of the data being passed to the component that follows it. For example:
{{ partial "bookshop_bindings" `(dict hero_text .Params.hero_text)` }}
{{ partial "bookshop" (slice "hero" (dict hero_text .Params.hero_text)) }}
|
Hugo has a built-in option to minify output files, which is enabled by adding the --minify flag to the hugo command. Be sure to keep the HTML comments though (keepComments = true ), or else Bookshop will not be able to generate the correct page bindings. Refer to the Hugo documentation for more information.
|
With that in place, live editing should work in CloudCannon. If you have the following front matter on a page:
---
content_blocks:
---
And the page
helper listed above in your layout, then in the CloudCannon sidebar you should be able to add our sample component and see it render live on the page.
💡
|
If something isn’t working, browse through our Hugo Bookshop Starter Template to see how everything is configured. |
Once you have components rendered on the page, Bookshop will create Visual Data Bindings automatically.
If a component is passed data from the page front matter, you will be able to interact with that component directly on the page.
By default, Bookshop will add bindings for any components on the page, but will not add bindings for shared helper files. This prevents Bookshop rendering data bindings around our shared page
helper, so that the components within are immediately accessible.
This behavior can be customised by including a flag in the component’s data. Bookshop will look for any of the following keys:
-
data_binding
-
dataBinding
-
_data_binding
-
_dataBinding
For example:
<!-- This component will **not** get a binding -->
{{ partial "bookshop" (slice "item" (dict "data_binding" false "props" props)) }}
<!-- This partial **will** get a binding -->
{{ partial "bookshop_partial" (slice "page" (dict "data_binding" true "props" props)) }}
ℹ️
|
This flag only applies to the component directly and doesn’t cascade down. Any subcomponents will follow the standard rules, or can also specify their own Data Binding flag. |
The npx @bookshop/generate
command connects Bookshop to a subset of your site’s data when live editing.
Data will not be available through .Site.Data
, but will be available through site.Data
. Accessing site pages when live editing is not yet supported in Hugo.
🌟
|
For data to be accessible, you will need to set data_config: true in your CloudCannon Global Configuration file.
|
In order to live edit Bookshop components, Bookshop needs a clear path between a component and the data it draws from. In general, you should avoid adding logic around your Bookshop components in your site layouts, and instead move that logic into a Bookshop component or helper.
An example:
---
hero_text: "Hello World"
---
<!--
This component can make the connection between "text" and ".Params.hero_text",
and will work as expected in the visual editor.
-->
{{ partial "bookshop_bindings" `(dict "text" .Params.hero_text)` }}
{{ partial "bookshop" (slice "hero" (dict "text" .Params.hero_text)) }}
{{ my_title := .Params.hero_text }}
<!--
This component does not have the context to map text back to its origin,
and will error in the visual editor.
(Assignments _inside_ Bookshop components will work correctly)
-->
{{ partial "bookshop_bindings" `(dict text $my_title)` }}
{{ partial "bookshop" (slice "hero" (dict "text" $my_title)) }}
The same is true for site data. Access this directly from inside your component, rather than passing it to the component from your layout.
Bookshop’s Hugo editing is based upon a subset of Hugo running in the browser. As such, not all Hugo features will be available within Bookshop components.
As a general rule: Functions that access files directly (such as resources.Get
), or access other parts of the site (such as site.GetPage
), will not return anything useful in the visual editor.
If you’re encountering an unsupported function, such as finding that resources.Get
returns nil
, see Rendering Different Content When Live Editing
You can render special content in the live editing environment by checking the Bookshop Live Editor flag. This can be useful to show extra information to your editors, or to use a feature that isn’t supported while live editing.
{{ if site.Params.env_bookshop_live }}
<p>I am being edited live!</p>
<h1>Fallback {{ .my_page }} title</h1>
{{ else }}
<p>Standard build output</p>
<h1>{{ with site.GetPage .my_page }}{{ .Title }}{{ end }}</h1>
{{ end }}
Some components won’t be compatible with live editing, in this case you can disable live editing with on a flag in the component’s data. This is intended for components such as navigation and footer blocks that aren’t connected to live editing. In most scenarios, you should use the templating flags in Rendering Different Content When Live Editing.
🌟
|
This setting will only apply if the component is rendered directly from a site layout. If this component is within another component, it will still update live (as the parent re-rendering will encapsulate it). |
Bookshop will look for any of the following keys on a top-level component:
-
live_render
-
liveRender
-
_live_render
-
_liveRender
For example:
<!-- This component will re-render in the visual editor -->
{{ partial "bookshop" (slice "navigation" (dict "props" props)) }}
<!-- This component will **not** re-render in the visual editor -->
{{ partial "bookshop" (slice "navigation" (dict "live_render" false "props" props)) }}
If you have a specific component that you never want to live edit, you can set _live_render
in the component’s blueprint.
ℹ️
|
Since the blueprint only affects the creation of new components, you will need to add the _live_render flag to any existing component data in your front matter.
|