Bubble supports custom JavaScript through the Run JavaScript workflow action and the Toolbox plugin. You can pass Bubble data into JavaScript, perform calculations or DOM manipulations that Bubble cannot do natively, and return results back to your workflows using the JavaScript to Bubble element. This extends Bubble's no-code capabilities when you hit platform limitations.
Extend Bubble with Custom JavaScript Logic
While Bubble is a no-code platform, there are scenarios where custom JavaScript is the best solution — complex string manipulation, clipboard operations, browser API access, or advanced math. This tutorial shows you how to write and execute JavaScript within Bubble using the Toolbox plugin. You will learn how to run scripts, pass data between Bubble and JavaScript, and handle return values. This guide is for builders who have basic JavaScript knowledge and want to extend their Bubble app's capabilities.
Prerequisites
- A Bubble account with an active app
- Basic understanding of JavaScript (variables, functions, DOM)
- Familiarity with Bubble workflows and element properties
- The Toolbox plugin installed (free in the plugin marketplace)
Step-by-step guide
Install the Toolbox Plugin
Install the Toolbox Plugin
Go to the Plugins tab in your Bubble editor and click '+ Add plugins'. Search for 'Toolbox' — it is one of the most popular free plugins. Click Install. The Toolbox plugin adds several capabilities including 'Run javascript' workflow action, 'Javascript to Bubble' element, 'Expression' element, and 'Server Script' action. After installation, you will see these new options in your element palette and workflow actions.
Expected result: The Toolbox plugin is installed and its elements and actions are available in the editor.
Use the Run JavaScript Workflow Action
Use the Run JavaScript Workflow Action
Create a button on your page labeled 'Run Script'. Go to the Workflow tab and add a workflow: 'When Button Run Script is clicked'. Add an action from the Plugins section: 'Run javascript'. In the script field, you can write any JavaScript code. For a simple test, enter: alert('Hello from JavaScript!'); — this will show a browser alert. You can reference Bubble dynamic data inside the script by clicking 'Insert dynamic data' within the code editor. For example, to use an input value: var name = "dynamic:Input Name's value"; alert('Hello, ' + name + '!');
Pro tip: The Run JavaScript action executes in the browser context, so you have access to the full DOM, window object, and browser APIs. However, it cannot directly access Bubble's server-side data or backend workflows.
Expected result: Clicking the button shows a browser alert with the message, confirming JavaScript execution works.
Add a JavaScript to Bubble Element for Return Values
Add a JavaScript to Bubble Element for Return Values
The Run JavaScript action can execute code but cannot directly return values to Bubble. To send data back, use the 'Javascript to Bubble' element. In the Design tab, drag a 'Javascript to Bubble' element from the plugin elements section onto your page. In its properties, give it a descriptive suffix (e.g., 'js_result'), set the type to 'text' (or number, date, etc. depending on what you are returning), and optionally check 'Publish value with a workflow event' if you want to trigger a workflow when a value is received. Now in your Run JavaScript action, call: bubble_fn_js_result('your return value here'); — this publishes the value to the element, which you can reference anywhere as 'JavascriptToBubble js_result's value'.
Expected result: JavaScript can now send values back to Bubble, accessible as a dynamic data source anywhere on the page.
Build a Practical Example: Copy Text to Clipboard
Build a Practical Example: Copy Text to Clipboard
A common use case is copying text to the clipboard, which Bubble cannot do natively. Add a Multiline Input element and a Button labeled 'Copy to Clipboard'. Create a workflow on the button click. Add a Run JavaScript action with this script: var textToCopy = "dynamic:MultilineInput's value"; navigator.clipboard.writeText(textToCopy).then(function() { bubble_fn_js_result('Copied!'); }).catch(function(err) { bubble_fn_js_result('Failed: ' + err); }); — Then add a second action: 'Show notification' or update a Text element with the JavascriptToBubble element's value to confirm the copy.
1var textToCopy = "dynamic:MultilineInput's value";2navigator.clipboard.writeText(textToCopy).then(function() {3 bubble_fn_js_result('Copied!');4}).catch(function(err) {5 bubble_fn_js_result('Failed: ' + err);6});Expected result: Clicking the button copies the input text to the clipboard and shows a confirmation message.
Pass Complex Data Between Bubble and JavaScript
Pass Complex Data Between Bubble and JavaScript
For more complex scenarios, you may need to pass structured data. Use JSON.stringify and JSON.parse to handle objects. In your Run JavaScript action, you can build a JSON object from multiple Bubble values: var data = { name: "dynamic:Input Name's value", email: "dynamic:Input Email's value", amount: parseFloat("dynamic:Input Amount's value") }; var result = JSON.stringify(data); bubble_fn_js_result(result); — On the Bubble side, you can parse this JSON string using the Toolbox plugin's Expression element or by passing it to an API Connector call.
Pro tip: If you need to return multiple values, use a JSON string and parse it with separate expressions, or use multiple JavaScript to Bubble elements — one for each return value.
Expected result: Complex data structures can be passed between Bubble and JavaScript using JSON serialization.
Complete working example
1PLUGIN REQUIRED: Toolbox (free)23PAGE: custom-js-demo45ELEMENTS:6- Input Name (text input)7- MultilineInput Content (multiline input)8- Button "Copy to Clipboard"9- Button "Calculate Word Count"10- JavascriptToBubble js_clipboard (type: text, trigger workflow: yes)11- JavascriptToBubble js_wordcount (type: number, trigger workflow: yes)12- Text CopyStatus (dynamic: JavascriptToBubble js_clipboard's value)13- Text WordCount (dynamic: "Words: " & JavascriptToBubble js_wordcount's value)1415WORKFLOWS:161. When Button "Copy to Clipboard" is clicked17 → Run javascript:18 var text = [MultilineInput Content's value];19 navigator.clipboard.writeText(text).then(function() {20 bubble_fn_js_clipboard('Copied successfully!');21 }).catch(function(err) {22 bubble_fn_js_clipboard('Copy failed: ' + err);23 });24252. When Button "Calculate Word Count" is clicked26 → Run javascript:27 var text = [MultilineInput Content's value];28 var words = text.trim().split(/\s+/).filter(Boolean).length;29 bubble_fn_js_wordcount(words);30313. When JavascriptToBubble js_clipboard's value changes32 → Show notification: JavascriptToBubble js_clipboard's value3334NOTES:35- [square brackets] represent Bubble dynamic data insertions36- bubble_fn_[suffix] is auto-generated by the JavascriptToBubble element37- The suffix must match the JavascriptToBubble element's suffix property38- Run JavaScript executes client-side only — no server accessCommon mistakes when writing custom logic with JavaScript in Bubble.io: Step-by-Step Guide
Why it's a problem: Forgetting to install the Toolbox plugin before trying to use Run JavaScript
How to avoid: Go to Plugins tab → '+ Add plugins' → search 'Toolbox' → Install.
Why it's a problem: Using bubble_fn_ with the wrong suffix name
How to avoid: Double-check that the suffix in your JavascriptToBubble element properties matches the function call in your JavaScript code exactly (case-sensitive).
Why it's a problem: Trying to access server-side data directly in Run JavaScript
How to avoid: First fetch the data you need using Bubble's native search, store it in an element or Custom State, then reference it in your JavaScript via dynamic data insertion.
Why it's a problem: Not handling asynchronous JavaScript operations properly
How to avoid: Use .then() callbacks or async/await patterns and call bubble_fn_ inside the success handler.
Best practices
- Only use custom JavaScript when Bubble's native features cannot accomplish the task — unnecessary JS adds complexity and maintenance burden.
- Always wrap JavaScript in try/catch blocks and send error messages back via bubble_fn_ for debugging.
- Use meaningful suffix names on JavascriptToBubble elements (e.g., 'js_clipboard_status' not 'js1').
- Keep JavaScript code short and focused — if you need more than 30-40 lines, consider using a plugin or external service instead.
- Test JavaScript in your browser's developer console first before adding it to a Bubble workflow.
- Document what each Run JavaScript action does with a Bubble Note attached to the workflow, since code is harder to maintain than visual workflows.
- Never put sensitive data (API keys, passwords) in client-side JavaScript — it is visible to anyone inspecting the page.
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm using Bubble.io and need to run custom JavaScript. I have the Toolbox plugin installed. I want to: 1) copy text to clipboard from a multiline input, 2) get the word count of that text, and 3) return both values back to Bubble. How do I set up the JavascriptToBubble elements and Run JavaScript actions?
Add a Run JavaScript action to the Copy button workflow that copies the content input's value to the clipboard using navigator.clipboard.writeText and returns a success or error message via the JavascriptToBubble element.
Frequently asked questions
Is JavaScript required to build Bubble apps?
No. The vast majority of Bubble apps are built entirely without JavaScript. Custom JS is only needed for edge cases like clipboard access, browser API integration, or complex calculations that Bubble's built-in features cannot handle.
Can I use external JavaScript libraries in Bubble?
Yes. You can load external libraries by adding a script tag in the page header (Settings → SEO/metatags → Script/meta tags in header) or by using an HTML element. Once loaded, the library's functions are available in your Run JavaScript actions.
Does custom JavaScript affect my app's performance?
Minimal JavaScript has negligible impact. However, heavy DOM manipulation, large libraries, or long-running scripts can slow down the page. Keep scripts lean and avoid blocking the main thread.
Can I run JavaScript on the server side in Bubble?
The Toolbox plugin includes a 'Server Script' action that runs JavaScript server-side, but it has limitations and is less commonly used. For server-side logic, backend workflows or API Connector calls to external services are usually better options.
How do I debug JavaScript errors in my Bubble app?
Open your browser's Developer Tools (F12 or Cmd+Option+I) and check the Console tab. JavaScript errors from Run JavaScript actions appear there with line numbers. Use console.log() statements in your scripts for debugging.
When should I consider hiring a developer instead of writing JavaScript myself?
If you need complex integrations, performance-critical code, or security-sensitive logic, professional developers like the RapidDev team can ensure your JavaScript is robust, secure, and maintainable within your Bubble app.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation