Understanding the Visual Editor
This chapter assumes you’ve read Content Structures and understand how to access your content.
The Visual Editor enables your users to create and edit their content with an in-context preview, including the possibility to click on components in their website. This feature is optional and does not depend on any specific technology. It will not alter the structure of your HTML or rearrange the DOM. The visual editor will not affect your production sites as it can be enabled only when inside the Storyblok UI. The visual editor will not allow inline editing; changing content will always be done in the Storyblok UI and the normal form inputs and custom fields you have defined for your content types and blocks.
- {1} Visual Editor - Preview: Your project embedded in an iFrame.
- {2} Visual Editor - Content: Bloks and Fields on the right-hand side.
Visual Editor - Preview
The left-hand side of the Visual Editor contains an iframe of your actual website, which we call Preview. This is not something we will render on our end, it is in fact your own implementation hosted on your infrastructure completely decoupled from Storyblok. You can configure the location used to embed your site in the Space Settings under the Visual Editor tab. You can configure multiple Preview URLs, which enables you to add development and deployment environments as an option for the Preview source.
While your project is embedded in the Visual Editor, the full_slug
of the story you’re currently editing, and other additional query params, will be appended to the Preview URL. Those parameters allow you to identify when to load the draft content for the Visual Editor Preview if embedded.
If you have problems loading the website preview you might need to add ALLOW-FROM storyblok.com to your X-Frame-Options header. You can do this in your server side code or in your web server configuration settings.
If you have problems loading the website preview in the Visual Editor with an error related to the Content Security Policy directive, you have to add https://app.storyblok.com
as frame-ancestor in the Content Security Policy directive.
Preview URL structure
https://www.yourdomain.com/articles/my-first-article?_storyblok=67341&...
└── Preview URL │ │
└── full_slug └── additional Query Params
Additional Query Params
Query Param | Description |
---|---|
_storyblok |
the numeric story ID |
_storyblok_tk[space_id] |
the space ID |
_storyblok_tk[timestamp] |
a unix timestamp |
_storyblok_tk[token] |
a validation token. Combination of _storyblok_tk[space_id] , _storyblok_tk[timestamp] and your Preview Token - Usage |
_storyblok_release |
id of the active release |
_storyblok_lang |
currently selected language |
_storyblok_c |
content type of the story |
Redirects can remove the URL parameters above and result in the Storyblok Bridge not being initialized. Make sure you don't have redirects and that you pass the query parameters accordingly.
Visual Editor - Content
In this area of the Visual Editor you and your editors are able to adjust and change your content by using the Fields and Bloks you’ve defined for your content type.
Bridge between the Visual Editor Preview and Content
We’ve created a toolkit that enables you to set-up a bridge between the Visual Editor Content and your project embedded in the Preview. We refer to this toolkit as Storyblok JS Bridge. The Storyblok JS Bridge enables you to listen to events such as change
, published
, unpublished
, input
, and enterEditmode
. You can allow click events on your own HTML elements which will then open up the correct Story and Blok in the Visual Editor Content area.
The Storyblok Bridge is used for two main tasks:
- Enabling click events on your HTML elements to open up in the Visual Editor Content area.
- Listen to Visual Editor events to update your content or trigger processes.
Installing the Storyblok Bridge
Installation of the Storyblok Bridge is done by including a script tag on your site or using one of our modules for specific technologies.
<script src="//app.storyblok.com/f/storyblok-v2-latest.js" type="text/javascript">
</script>
Keep in mind that the Storyblok Bridge increases the payload of your site and shouldn't be included in the production builds of your site.
Please check out also our comprehensive guide about the Storyblok Bridge.
Initializing the Storyblok Bridge
Once the script for the bridge is included you need to initialize it. In this example, we also add the functionality of reloading the content of the iFrame for every publish
and change
event.
// Initialize the Storyblok JS Bridge
const { StoryblokBridge, location } = window
const storyblokInstance = new
StoryblokBridge()
storyblokInstance.on(['published', 'change'], () => {
// reload page if save or publish is clicked
location.reload(true)
})
}
Please note that the _editable
property is only included in the draft version of the story.
Enabling click events on your HTML Elements
To enable the click events that will send messages to the Visual Editor you will have to output the content of the _editable
property before each of your own HTML Elements. The content of the _editable
property contains a HTML comment for each Story and Blok. The Storyblok Bridge will then automatically register click events of the HTML Element that follow that HTML comment.
Example Explanation
When you load one story using the URL parameter version=draft
from the Content Delivery API you will receive a response like this:
{
"story": {
"id": 172223,
"content": {
"_editable": "<!--#storyblok#{\"name\": \"page\", \"space\": \"14141\", \"uid\": \"b370f32d-cd89-4dd3-9437-16b5e9746b31\", \"id\": \"172223\"}-->",
"component": "page",
"body": [
{
"_editable": "<!--#storyblok#{\"name\": \"hero\", \"space\": \"14141\", \"uid\": \"98b685a1-da10-4df2-837e-3429d5ea6f88\", \"id\": \"172223\"}-->",
"component":"hero",
"headline": "This is my headline!"
}
]
}
}
}
Read more about the different versions of your Content in Accessing your Content.
We can then push that data through any template engine or framework of your choice to render HTML.
{{story.content._editable}}
<div class="content-type">
{% for blok in story.content.body %}
{{blok._editable}}
<div class="blok">
{{blok.custom_field}}
</div>
{% endfor %}
</div>
You can use any templating engine you want. The example above is using Mustache syntax.
We end up with HTML that looks like this:
<!--#storyblok#{\"name\": \"page\", \"space\": \"14141\", \"uid\": \"b370f32d-cd89-4dd3-9437-16b5e9746b31\", \"id\": \"172223\"}-->
<div class="content-type">
<!--#storyblok#{\"name\": \"hero\", \"space\": \"14141\", \"uid\": \"98b685a1-da10-4df2-837e-3429d5ea6f88\", \"id\": \"172223\"}-->
<div class="blok">
This is my headline!
</div>
</div>
The result of combining the template and the loaded draft content is the above HTML, which will be loaded by the browser. At this point, the Storyblok Bridge will be loaded and initialized. Your part of the integration is already done by adding the HTML comments and from here on out the Storyblok JS Bridge will take over.
During this initialization, the Storyblok Bridge looks for every HTML comment in your HTML. Each HTML comment starting with <!--#storyblok#
will be parsed. The parsed JSON will then be used to add two HTML attributes data-blok-c
and data-blok-uid
and the class storyblok``--``outline
to the HTML element right after the HTML comment.
<!--#storyblok#{\"name\": \"page\", \"space\": \"14141\", \"uid\": \"b370f32d-cd89-4dd3-9437-16b5e9746b31\", \"id\": \"172223\"}-->
<div class="content-type storyblok--outline" data-blok-c="{escapedJSONData}" data-blok-uid="b370f32d-cd89-4dd3-9437-16b5e9746b31">
<!--#storyblok#{\"name\": \"hero\", \"space\": \"14141\", \"uid\": \"98b685a1-da10-4df2-837e-3429d5ea6f88\", \"id\": \"172223\"}-->
<div class="blok storyblok--outline" data-blok-c="{escapedJSONData}" data-blok-uid="98b685a1-da10-4df2-837e-3429d5ea6f88">
This is my headline!
</div>
</div>
The class storyblok--outline
will add a dotted border to your HTML element while hovering on your site in the Visual Editor Preview. Once you click on one HTML element the name of the blok will be added with a █ #09b3af colored border to show which block is currently selected.
In this process, the Storyblok Bridge will also register the click eventListeners on your HTML elements that will open up the story or block in the Visual Editor Content area.
Listen to the Visual Editor events
Events you can listen to on your own site, using the Storyblok Bridge, are events the Visual Editor sends through the bridge so you can react to content changes and UI actions. Some of the events sent to the Storyblok Bridge include a payload for you to use in your project.
// listen to a single event
storyblokInstance.on('event_name', (payload) => {
console.log(payload);
})
// listen to multiple events
storyblokInstances.on(['event_name_1', 'event_name_2'], (payload) => {
console.log(payload);
})
Example Event Usage: Change and Published
To get a new version of the content every time the Save or Publish button is pressed, listen to the change and published events and trigger a reload. You can also update your state manually by loading the content from the Content Delivery API.
// Listens on multiple events and does a basic website refresh
storyblokInstance.on(['change', 'published'], () => {
window.location.reload(true);
})
Example Event Usage: Input
To update the content in your project on input changes in the Visual Editor Content area, even before the content is saved, you can use the input
event. The payload passed in the event contains the updated story, so you can use it to update your project content state in real-time.
Visual Editor Event Types
Event Name | Will be emitted |
---|---|
input | after a user changes the value of a field |
change | after the user saves the content |
published | after the user clicks publish |
unpublished | after the user clicks unpublish |
enterEditmode | after the editor has been initialized in the editmode |