description | cover | coverY |
---|---|---|
CBWIRE is a ColdBox module that uses Livewire and Alpine.js to help you build modern, reactive BoxLang and CFML applications in record time without building backend APIs. |
.gitbook/assets/CleanShot 2025-08-08 at [email protected] |
0 |
CBWIRE revolutionizes BoxLang and CFML web development by bringing reactive UI capabilities directly to your server-side code. Build dynamic, interactive interfaces without writing JavaScript, managing APIs, or dealing with complex frontend frameworks.
Register for our upcoming 2-day CBWIRE workshop at CFSummit!
Let's create a reactive counter component to demonstrate CBWIRE's power. Download and install CommandBox, then run these commands:
mkdir cbwire-playground --cd
install cbwire@4
install commandbox-boxlang
coldbox create app
server start cfengine=boxlang javaVersion=openjdk21_jdk
Insert a counter component into your Main layout using wire("Counter")
:
{% tabs %} {% tab title="BoxLang" %}
<!-- layouts/Main.bxm -->
<bx:output>
<!doctype html>
<html>
<head>
<title>CBWIRE Demo</title>
</head>
<body>
<!-- Insert our reactive counter -->
#wire("Counter")#
</body>
</html>
</bx:output>
{% endtab %}
{% tab title="CFML" %}
<!-- layouts/Main.cfm -->
<cfoutput>
<!doctype html>
<html>
<head>
<title>CBWIRE Demo</title>
</head>
<body>
<!-- Insert our reactive counter -->
#wire("Counter")#
</body>
</html>
</cfoutput>
{% endtab %} {% endtabs %}
Define your Counter component:
{% tabs %} {% tab title="BoxLang" %}
// wires/Counter.bx
class extends="cbwire.models.Component" {
data = {
"counter": 0
};
function increment() {
data.counter++;
}
function decrement() {
data.counter--;
}
}
{% endtab %}
{% tab title="CFML" %}
// wires/Counter.cfc
component extends="cbwire.models.Component" {
data = {
"counter" = 0
};
function increment() {
data.counter++;
}
function decrement() {
data.counter--;
}
}
{% endtab %} {% endtabs %}
Define the counter template:
{% tabs %} {% tab title="BoxLang" %}
<!-- wires/counter.bxm -->
<bx:output>
<div>
<h1>Count: #counter#</h1>
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
</div>
</bx:output>
{% endtab %}
{% tab title="CFML" %}
<!-- wires/counter.cfm -->
<cfoutput>
<div>
<h1>Count: #counter#</h1>
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
</div>
</cfoutput>
{% endtab %} {% endtabs %}
Navigate to your application in the browser. Click the + and - buttons to see the counter update instantly without page refreshes or JavaScript code! 🤯
CBWIRE seamlessly bridges your server-side BoxLang or CFML code with dynamic frontend behavior:
- Initial Render: CBWIRE renders your component with its default data values
- User Interaction: When a user clicks a button with
wire:click
, Livewire.js captures the event - Server Request: The interaction triggers an AJAX request to your CBWIRE component's action method
- Data Processing: Your server-side action method processes the request and updates component data
- Response & Update: The updated HTML is sent back and Livewire.js efficiently updates only the changed parts of the DOM
This approach gives you the responsiveness of modern JavaScript frameworks while keeping your logic in familiar server-side code.
Building our reactive counter with CBWIRE meant we:
- ✅ Developed a responsive interface without writing JavaScript
- ✅ Avoided creating backend APIs - everything stays in your ColdBox application
- ✅ Eliminated page refreshes while maintaining server-side control
- ✅ Skipped complex build processes like webpack or JavaScript compilation
- ✅ Stayed in our BoxLang/CFML environment using familiar syntax and patterns
While CBWIRE handles server communication beautifully, sometimes you need instant client-side updates without server round-trips. This is where Alpine.js shines - a lightweight JavaScript framework designed to work perfectly with Livewire (and therefore CBWIRE).
Let's enhance our counter to use Alpine.js for instant updates and add persistence:
{% tabs %} {% tab title="BoxLang" %}
// wires/Counter.bx
class extends="cbwire.models.Component" {
data = {
"counter": 0
};
function onMount() {
data.counter = session.counter ?: 0;
}
function save(counter) {
session.counter = arguments.counter;
}
}
{% endtab %}
{% tab title="CFML" %}
// wires/Counter.cfc
component extends="cbwire.models.Component" {
data = {
"counter" = 0
};
function onMount() {
data.counter = session.counter ?: 0;
}
function save(counter) {
session.counter = arguments.counter;
}
}
{% endtab %} {% endtabs %}
{% tabs %} {% tab title="BoxLang" %}
<!-- wires/counter.bxm -->
<bx:output>
<div
x-data="{
counter: $wire.counter,
increment() { this.counter++; },
decrement() { this.counter--; },
async save() {
await $wire.save(this.counter);
}
}"
wire:ignore.self>
<h1>Count: <span x-text="counter"></span></h1>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="save">Save</button>
</div>
</bx:output>
{% endtab %}
{% tab title="CFML" %}
<!-- wires/counter.cfm -->
<cfoutput>
<div
x-data="{
counter: $wire.counter,
increment() { this.counter++; },
decrement() { this.counter--; },
async save() {
await $wire.save(this.counter);
}
}"
wire:ignore.self>
<h1>Count: <span x-text="counter"></span></h1>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="save">Save</button>
</div>
</cfoutput>
{% endtab %} {% endtabs %}
Now the counter updates instantly on the client side, but only makes server requests when "Save" is clicked to persist the value. The onMount()
method loads the saved counter from the session on page load. Using $wire
, Alpine.js communicates seamlessly with your CBWIRE component.
This combination gives you complete control: instant UI feedback when needed, and server communication when you want to persist data or run complex business logic.
Ready to dive deeper? Explore these essential concepts:
- Getting Started: Complete installation and setup guide
- Components: Learn how to build and organize CBWIRE components
- Templates: Master template syntax and data binding
- Actions: Handle user interactions and component methods
- Properties: Understand data binding and reactivity
- Events: Communicate between components and handle lifecycle events
CBWIRE leverages the incredible JavaScript libraries Livewire and Alpine.js for DOM diffing and client-side functionality. CBWIRE wouldn't exist without the brilliant work of Caleb Porzio, creator of both Livewire and Alpine.js. CBWIRE brings these powerful tools into the ColdBox and BoxLang/CFML ecosystem.
The CBWIRE module is developed and maintained by Grant Copley, Luis Majano, and the team at Ortus Solutions.
Please consider becoming one of our Patreon supporters to help us continue developing and improving CBWIRE.