Custom Widget
🧩 Creating a Custom Widget
Custom widgets in Pillars give you the flexibility to display dynamic content using HTML, CSS, templating, and data queries. This guide walks you through each section of creating a custom widget.
To begin, create a new widget of type HTML. See Managing Widgets for more details.
🔧 HTML
The first section of your widget is the HTML, where you define the structure and content.
- You can use any valid HTML supported by modern browsers (typically HTML5).
- HTML inside widgets behaves just like it would in a regular web page.
🎨 CSS
The CSS section defines the styling for your widget.
- Use standard CSS supported by the user's browser.
- You can leverage the main site’s CSS classes directly in your HTML (e.g.,
card
,btn
,row
). - CSS is applied to the entire widget—including the outer container.
Example:
.card {
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px,
rgba(0, 0, 0, 0.24) 0px 1px 2px;
}
💬 Templating
Widgets in Pillars use the Mustache 5 templating engine to inject dynamic data.
- Mustache syntax is simple:
{{variable}}
, loops with{{#each}}
, and conditionals. - The
{{customer}}
object is available by default.
See Customer Fields for available properties.
Example:
<div class="card-body">
<dl class="row">
<dt class="col-5">Name:</dt>
<dd class="col-7">{{customer.fullName}}</dd>
<dt class="col-5">Account:</dt>
<dd class="col-7">{{customer.customerType.name}}</dd>
{{#customer.phoneNumbers}}
<dt class="col-5">{{type}}:</dt>
<dd class="col-7">{{number}}</dd>
{{/customer.phoneNumbers}}
<dt class="col-5">First Phone:</dt>
<dd class="col-7">{{customer.phoneNumbers.0.number}}</dd>
</dl>
</div>
<div class="card-footer">
<a href="/customers/{{customer.id}}/dashboard" class="btn w-100">View Full Profile</a>
</div>
🔍 Query
The Query section fetches data to inject into your widget. There are two query options:
🧬 GraphQL
Use Pillars’ GraphQL API to query structured data directly.
query($customerId: ID) {
customer(id: $customerId) {
firstName
lastName
fullName
profileImage
totalOrders
phoneNumbers {
type
number
}
customerType {
name
}
}
}
🌐 API
You can also make HTTP requests to internal or third-party APIs.
- Use relative paths for Pillars API calls (e.g.,
/api/v1/Customers/{{customer.id}}
). - Results are available in the
{{data}}
context. - If the query fails, the error is stored in
{{data.error}}
.
Example (with GraphQL data):
<div class="card-body">
{{#data.error}}
<span class="badge bg-red">{{data.error}}</span>
{{/data.error}}
<span class="badge bg-blue">{{data.customer.fullName}}</span>
<span class="badge bg-blue">{{data.customer.totalOrders}}</span>
<dl class="row">
<dt class="col-5">Name:</dt>
<dd class="col-7">{{data.customer.fullName}}</dd>
<dt class="col-5">Account:</dt>
<dd class="col-7">{{data.customer.customerType.name}}</dd>
{{#data.customer.phoneNumbers}}
<dt class="col-5">{{type}}:</dt>
<dd class="col-7">{{number}}</dd>
{{/data.customer.phoneNumbers}}
<dt class="col-5">First Phone:</dt>
<dd class="col-7">{{data.customer.phoneNumbers.0.number}}</dd>
</dl>
</div>
<div class="card-footer">
<a href="/customers/{{customer.id}}/dashboard" class="btn w-100">View Full Profile</a>
</div>
🧠 JavaScript
JavaScript is disabled by default in widgets for security and performance reasons.
To use JavaScript, enable the Render in IFrame option in the widget settings.
📊 Example: ApexChart in a Widget
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<div id="chart"></div>
<script>
var options = {
series: [
{
name: 'Website Blog',
type: 'column',
data: [440, 505, 414, 671, 227, 413, 201, 352, 752, 320, 257, 160]
},
{
name: 'Social Media',
type: 'line',
data: [23, 42, 35, 27, 43, 22, 17, 31, 22, 22, 12, 16]
}
],
chart: {
height: 350,
type: 'line',
toolbar: { show: false },
zoom: {
enabled: false,
allowMouseWheelZoom: false
}
},
stroke: {
width: [0, 4]
},
title: {
text: 'Traffic Sources'
},
dataLabels: {
enabled: true,
enabledOnSeries: [1]
},
labels: ['01 Jan 2001', '02 Jan 2001', '03 Jan 2001', '04 Jan 2001', '05 Jan 2001', '06 Jan 2001',
'07 Jan 2001', '08 Jan 2001', '09 Jan 2001', '10 Jan 2001', '11 Jan 2001', '12 Jan 2001'],
yaxis: [
{
title: { text: 'Website Blog' }
},
{
opposite: true,
title: { text: 'Social Media' }
}
]
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
</script>
🧾 JavaScript and Customer Data
Even with JavaScript enabled, templating still works the same way.
If you'd prefer to work with the customer and data objects in JavaScript, define a function called onDataReady
. This function will be called when the widget finishes loading data.
Example:
<div id="jsn"></div>
<script>
function onDataReady(obj) {
var dv = document.getElementById('jsn');
dv.innerText = JSON.stringify(obj, null, 2);
}
</script>
Updated 3 days ago