Velo is a powerful development platform and sometimes that makes it a bit confusing. That’s especially true if you’re starting out and not sure which bits of code go where and why they don’t work as you expect them to.

If you’re just starting out or have related confusions, this lesson will help you work out where to put your code.

I want to respond to button clicks and page events

Page elements like buttons, text, and inputs have events that are triggered when you interact with them. The most common is when clicking on an element triggers the onClick event. The functions that respond to these events are known as event handlers.

So where do you put your code to respond to these events?

There are two options:

  • In the onReady code block
  • Using the Properties & Events panel


Whenever you create a new page, you automatically get an onReady() code block that looks like this:

// API Reference:
// “Hello, World!” Example:
$w.onReady(function () {
// Write your JavaScript here
// To select an element by ID use: $w("#elementID")
// Click "Preview" to run your code

The onReady event fires when the page has been rendered and is ready for user interaction. Whatever you put in the $w.onReady event handler runs when this event fires. This is the place to define your event handlers for elements on your page. Event handlers defined in onReady are known as Dynamic Event Handlers. Dynamic event handlers can be cut and pasted between pages or sites and will work as long the page element is named correctly.

The simplest example is a button click.

$w.onReady(function () {
$w('#myButton').onClick((event) => {
console.log("myButton was clicked, just saying");

Put this code inside the onReady block so that as soon as the page is ready, it is also able to handle a click event for the myButton element.

You can also put your code in a separate function, which is called from the event handler.

$w.onReady(function () {
$w('#myButton').onClick((event) => {
export function myButtonWasClicked(event) {
console.log("myButton was clicked, just saying");
// add usefull code here

Note that if you define your event handler outside the onReady block, it won’t work unless it’s in a function and that function has been run.

Also note that if you define an event handler in a regular function and you run the function twice, you will get two event handlers, and the code inside them will run twice when the event is triggered.

The best practice is to define your event handlers in the onReady block.

Using the Properties & Events panel

Another way to handle events for page elements is with static event handlers. Set these up in the Editor by selecting the event handler you want from the Properties & Events panel.

This will add the code provided below to your page and can be used instead of the dynamic event handler. These functions are defined outside the onReady block and are “internally wired” via the Properties & Events panel to catch the relevant event. You can’t type these functions directly in the editor — they must be added in the Properties & Events panel to work.

* Adds an event handler that runs when the element is clicked.
* @param {$w.MouseEvent} event
export function myButton_click(event) {
// This function was added from the Properties & Events panel. To learn more, visit
// Add your code for this event here:

Cut and paste with static event handlers

You can’t cut and paste the code for static event handlers between page files or sites, even if the button or page element has the same name. You must set up the event handler using the Properties & Event panel for it to respond to events.

I want some code to run on every page

If you have code that you want to run on every page, put that code in the masterPage.js file. Code in the masterPage.js is common to all pages on your site. If you want to add processing for your header or footer, this is the place to do it. This is also the place to handle elements that you want to put on every page, like a search bar or a shopping cart icon for a store.

The masterPage.js has its own onReady event handler, so be careful not to write code in the masterPage onReady that conflicts or overlaps with code in the page onReady, as the event handlers run in parallel.

Non-persistent state of an element

The state of an element that you set on one page does not persist for other pages or when you return to the page. Let’s say you have an image element that is set to Show on All Pages. Then you add a button and an event handler to change the element’s source on click. When you navigate to another page on your site, the image reverts back to its original source. This is true even if you navigate back to the page where you initiated the click event.

To keep the state of an element the same between pages, you need to store its state using wix-storage:

  1. Inside the event handler callback, use setItem to store a key that indicates the state of the element.
  2. Inside the onReady callback for masterPage.js, add code that checks the stored key and changes the element’s state accordingly.

Where should I put passwords and sensitive data?

If your code contains something that you don’t want anyone to see like private user details, a password, payment information, or some processing that you want to keep hidden, store it in Backend files that aren’t visible to the browser.

The Secrets Manager

For really sensitive information like passwords or keys, you should use the Secrets Manager instead of hardcoding the values in your code.

I want to use functions from somewhere else

The import statement lets you use objects and functions that have been exported by another module. This is how you include functions from your own backend files and other Wix modules in your code. Best practice is to put the import statement at the top of your code file.

Put braces around the function names that you are importing.

For example:

import { myFunction } from 'backend/aModule.jsw'

If you leave out the curly braces, you import the default function of aModule and it gets called myFunction.

import myFunction from 'backend/aModule.jsw'

This will generally result in the following runtime error if you call myFunction (unless you have specifically exported myFunction as the default):

(0 , _aModule2.default) is not a function

However, if you want to import the full module, you should import without the curly braces to access all of the module’s functions.

import wixData from 'wix-data';
import wixStores from 'wix-stores';
import wixUsers from 'wix-users';

Where do I put Wix backend functions?

Any function from a Wix backend library, like wix-pay-backend, wix-users-backend, or wix-events-backend, goes into a backend code file.

Code executed on the backend takes the load off the browser and lets you access functions that run on the web server.

When you define a function in a .jsw file, you will need to import it into your page code before you can call it.

If you try to import a front-end function —— like something from wix-users —— into a backend file, you will get the following runtime error:

Error loading web module backend/aModule.jsw: Cannot find module 'wix-users'

Backend file types

There are two file suffixes that can be used in the backend:

  • .jsw: These are web modules which are accessible to the front-end and have associated permissions to control who can call each function in the file.
  • .js: These files are not directly accessible to users via front-end code and are therefore more secure.

If you try to import a function from a .js file into your front end code, you will get the following error at runtime:

Access to backend script 'backend/new-file.js' denied! Client-side scripts can only import web-modules (.jsw) from backend code context.

To run a function in a .js file from your page code, import the function from the .js file into a .jsw file, then import the .jsw function into your page code.

When you use a backed function, don’t forget to use an await or a .then to wait for the promise to resolve and give you the function’s return values.

//In your page code:
import { myBackendFunction } form 'backend/aModule.jsw'
export function myFrontendFunction() {
// await
const myVariable = await myBackendFunction();
.then((response) => {
const myVariable = response;