Ideally you would build the javascript from the Bloembraaden admin interface, just like the templates, but this is not yet possible. You need to prepare the javascript separately and upload it as script.js to the _site folder of the website you are designing.


The Bloembraaden javascript is simple (stable) old fashioned javascript. It rarely checks whether arguments supplied or elements manipulated are correct. Thus it may throw errors (watch the console output) when used incorrectly. It is by no means pretending to be type safe.

This is because I believe that in a stable design, the supplied arguments and elements manipulated will be the correct and intended ones. If you do not know which stuff you are handling, you need to step back to see what you are doing. If you cannot find out what you are handling, your design is too complex, or you need sleep.

At the same time, Bloembraaden is very lenient with everything. Stuff mostly works even if it is not entirely up to specs. Just check your design for yourself, before handing the site to your client.


Your javascript can subscribe to the following events, that are dispatched on the document by default, or a DOM element (like form) if possible. Quirk: the events are prefixed with peatcms, the old name of Bloembraaden.

For example, if you want to reset a form when it has been posted, use:

document.addEventListener('peatcms.form_posted', function(e) {
    if (e.detail && e.detail.form) e.detail.form.reset();


Next to the carousel, lazy loading sourceset and slideshow, described in the template part of this howto, Bloembraaden exposes a couple of useful objects, most importantly PEAT, the cms instance, NAV, the navigation object, as well as Address, a users address.

Sticky columns

Instantiate a PeatStickyColumns to have two columns behave like position: "sticky"; but nice:

You need to instantiate this separately. The function accepts 3 arguments:

document.addEventListener('peatcms.initialize', function() {
    document.addEventListener( 'peatcms.document_complete', function () {
        new PeatStickyColumns(document.getElementById('left-column'), document.getElementById('right-column'), 20);

The columns #left-column and #right-column need to be next to eachother. Their position will be kept level, using top margin.

#left-column {
    float: left;
    padding: 0 20px 2rem var(--padding);
    width: calc(50% + 200px - var(--padding) - 20px);
#right-column {
    float: right;
    padding: 0 var(--padding) 2rem 0;
    width: calc(50% - 200px - var(--padding));
#left-column {
    transition: margin-top 201ms ease-out;

The transition animation is provided to have the columns move smoothly and draw attention to the moving (supposedly you have a cta or something else that is relatively important in the smaller column).

Default template objects

The Carousel and Lazyload (sourceset) objects are customizable through the template, you should not access them with javascript.

NAV (navigation object)

window.NAV or NAV is the instance of the PEATCMS_navigator object that is present right from initialization. It inherits from PEATCMS_ajax and as such exposes all the ajax methods, that you will probably not need, but are free to checkout.

The navigator object has the following methods. Access them by calling NAV.methodName(arguments). This list is not exhaustive, but I try to mention the most useful methods for a designer.

PEAT (core object)

Bloembraaden exposes useful methods for your website design on the PEAT instantiated cms object, as well as static methods on the PEATCMS object.

Dynamic methods

The PEAT instance of the PEATCMS object is available from the initialization. Call its methods like so: PEAT.methodName(argument).

Static methods

Call these useful static methods directly on the PEATCMS object, like such: PEATCMS.methodName(argument).


To display a message to the visitor, like the standard Bloembraaden messages that you can style with css, use the message method of the PEAT instance.

log messages disappear quickly, other messages only disappear after user action. info is ment to be a very distinctive message but not so catastrophic as an error, and is styled as such by default.


Session variables are automatically synced with the server, if you use the below methods on the PEAT instance. They are guaranteed to be current.

Internal objects

Progressive loading example

The following example loads a ‘Contact’ section into the DOM, only when it would be visible.

function my_client_contact(el) {
    let loading = false; // only one request to load everything please
    function load() {
        if (true === loading) return;
        loading = true;
        NAV.ajax( '/__action__/get_template_by_name', {
            admin: false,
            template_name: 'Contact'
        }, function (data) {
            if (data.hasOwnProperty('__html__')) {
                load_page(new PEATCMS_template(data));
            } else {
                console.error('Template ‘Contact’ missing');
    function load_page(template) {
        NAV.ajax('/Contact', {}, function (json) {
            el.innerHTML = template.render(json);
            el.setAttribute('data-contact-loaded', '1');
    function handle_scroll() {
        el.scrollTo(0, window.scrollY - 130);
    function load_when_visible() {
        if (el.hasAttribute('data-contact-loaded')) return;
        if ('none' === window.getComputedStyle(el).getPropertyValue('display')) return;
    window.addEventListener('resize', load_when_visible, {passive: true});
    document.addEventListener('scroll', handle_scroll, {passive: true});

Call the above function with the DOM element you want the contact Element rendered in, for instance like this:

document.addEventListener( 'peatcms.initialize', function (e) {
    PEAT.addEventListener( 'peatcms.document_complete', function() {
        const el = document.getElementById('contact');
        if (el) {
    }, true);

This javascript could be a bit more isolated but it will work fine like this.