BUILDER

Features

Developers

Documentation

Pricing

Github

Docs

App

This page was made in Builder!

Custom code in the Builder visual editor

The Builder editor allows you to add event handlers, bind to state and even add custom JavaScript that will run on your page. This guide will walk through how to do things like access state properties, access events and even run custom JavaScript when your content loads.

State and Actions

Builder allows you to bind state values to Builder blocks as well as adding custom actions when the user interacts with your content. If you want to learn how to add state bindings or action handlers, check out our State and Action Guide.

When adding custom code in a state binding, note that you should not return a value. Instead, should use one of the following examples:

Data Binding: one line expressions

If you have a simple, one line expression you can write it without a return statement in the code editor:

state.foo ? 'bar' : 'baz'

Data Binding: complex code blocks

If you have a more complicated code logic, you'll need to make sure you export a default value:

let value;
if (foo) {
  value = 'bar';
} else {
  value = 'baz';
}
export default value;

Accessing State

You can access Builder state in both state bindings as well as action handlers. State bindings will almost always be bound to Builder, but you can also modify the state value in the binding. For example:

// use the plain value from state
state.someStringValue

// uppercase the state value
state.someStringValue.toUpperCase()

// return a different value depending on state property
state.someBooleanValue ? 'yes' : 'no

Action handlers: using the Event object

Action handlers have an additional object you can access, event. This value is the HTML event emitted by the event you selected. You can use the event to access the target that emitted the event, or you can call methods like preventDefault or stopPropagation:

// access the value attribute (ie from an input)
// and store it in builder state
state.someStateProp = event.currentTarget.value;

// if you have a link with an href, you might want to stop
// default browser navigation and handle this yourself
event.preventDefault();
var targetElementId = event.currentTarget.id;
var elementToScrollTo = document.getElementById(targetElementId);
elementToScrollTo.scrollIntoView({ behavior: 'smooth' });

Editing Custom JavaScript and CSS

Builder also allows you to add totally custom styles or JavaScript to your content by clicking the Edit Custom JS / CSS button on the bottom of the data tab:

This applies to the entire content entry, and not a particular layer. Let's say you wanted to add a some custom styling to all builder text blocks for a particular page, you could add a rule like this to the Custom CSS panel:

.builder-text p {
  margin: 10px;
  color: #000;
}

You can also use the JavaScript panel to listen to run custom code on the page as well. Let's say you're rendering your Builder content lazily on the client and you want support linking directly to certain sections of a page based on the id attribute of the section. You could do this with some custom JavaScript:

const el = location.hash && document.getElementById(location.hash.slice(1))

el.scrollIntoView({ behavior: 'smooth' });

Caution: as with any code you would add to your site, be cautious and thoughtful of the impact your custom code might have on performance and security. For example, Iif you are adding custom event listeners, make sure you passive events.

Server rendering and Async Requests

You can also use the JavaScript panel to listen to run custom code on the page as well. Let's say you're rendering your Builder content lazily on the client and you want support linking directly to certain sections of a page based on the id attribute of the section. You could do this with some custom JavaScript:

You can run client side and/or server side using Builder.isBrowser and Builder.isServer. You also have access to fetch() on the client and server. For server side data you can export a default promise and it'll wait on that promise to resolve with any data before replying:

async function main() {
  // only run if you're in a server environment (not in the browser)
  if (Builder.isServer) {
    await fetch(someUrl)
      .then(res => res.json())
      .then(data => {
        // set the data on the state object so you can access it from your components
        state.someData = data;
     });
  }
}

export default main();

In the example above, the data will be saved on state and accessible in the server and client UIs as data bindings, etc. View our Advanced Data Guide for more information about fetching data and using it in Builder.

Accessing location data

You may have a situation where you want to access data form the url. While you can easily access window.location in the browser, this doesn't really work if you're running in Node.js. To make easier for developers to deal with url data on all platforms, we've added a state.location object that you can access in custom code:

/*
  * properties available on state.location:
  * pathname, hostname, search, host, path, query
*/

async function main() {
  // override a default API url with a query param called apiUrl
  var apiUrl = state.location.query.apiUrl || defaultApiUrl;
  
  // only run if you're in a server environment (not in the browser)
  if (Builder.isServer) {
    await fetch(someUrl)
      .then(res => res.json())
      .then(data => {
        // set the data on the state object so you can access it from your components
        state.someData = data;
     });
  }
}

export default main();