Custom Button Widget
Custom Buttons let you invoke actions when a user clicks a button on a record page. The button opens a dialog containing your Connected App widget — ideal for generating documents, running bulk operations, or displaying confirmation dialogs with custom logic.


Availability#
| Apps | Mobile |
|---|---|
| Maintenance, Vendor, Requester, Client, Tenant | Yes |
When to use#
- Generating invoices, reports, or other documents from record data
- Running custom actions that require user input or confirmation
- Triggering external API calls with a review step before execution
- Building multi-step action dialogs
Triggers#
| Function | Description | Example |
|---|---|---|
| hide | Hides the custom button dialog | window.facilioApp.interface.trigger('hide'); |
| resize | Resizes the custom button dialog (web only; uses preset sizes, not fixed px) | See example below |
| reloadData | Reloads the summary page (useful after updating the record) | window.facilioApp.interface.trigger('reloadData'); |
| setCloseEvent | Registers a hook for when the user closes the modal (close icon on web, back on mobile). Use when the widget runs timed activity or loading — users may close before it completes; run cleanup, cancel requests, or show confirmation. Works on web and mobile. | window.facilioApp.interface.trigger('setCloseEvent', { key: 'onModelClose' }); |
| clearCloseEvent | Removes the registered close event handler. Call when the operation completes or the user explicitly cancels. | window.facilioApp.interface.trigger('clearCloseEvent'); |
Web only
resize is supported on web only.
Resize example — Pass size with one of: XS, S, M, L, XL
window.facilioApp.interface.trigger('resize', { size: 'L' });Close event — The Custom Button opens as a modal with a close icon. If the widget runs timed activity or loading, users may click close before it completes. Use setCloseEvent to hook into the close action (web: close icon; mobile: back) and run cleanup, cancel requests, or show confirmation:
// Register the close eventwindow.facilioApp.interface.trigger('setCloseEvent', { key: 'onModelClose' });
window.facilioApp.on('onModelClose', () => { // Cleanup, cancel requests, show confirmation, etc.});
// When the operation completes or user explicitly cancels, clear the handlerwindow.facilioApp.interface.trigger('clearCloseEvent');Context#
When a custom button dialog opens, app.getContext() returns the current record data. Use this to access the record's fields for your action.
app.on('app.loaded', (data) => { const record = data.context; console.log('Record ID:', record.id); console.log('Record Name:', record.name);});Example — Invoice PDF generation#
- Javascript
- HTML
- CSS
const app = FacilioAppSDK.init();
app.on('app.loaded', async (data) => { window.facilioApp.interface.trigger('resize', { size: 'XL' });
const invoiceData = data.context; const vendorData = invoiceData.vendor_custom_vendorinvoices_1;
// Convert vendor logo to base64 for PDF rendering let logoBase64 = null; const logoUrl = vendorData?.logo_vendorsUrl; if (logoUrl) { const cleanUrl = logoUrl.replace('/api', ''); const base64 = await app.common.toBase64({ url: cleanUrl }); logoBase64 = `data:image/png;base64,${base64}`; }
// Fetch invoice line items const { list } = await app.api.fetchAll('custom_vendorinvoicelineitems', { viewName: 'all', filters: JSON.stringify({ invoice_custom_vendorinvoicelineitems_1: { operatorId: 36, value: [String(invoiceData.id)] } }), includeParentFilter: true });
renderInvoice(invoiceData, vendorData, list, logoBase64);});
function renderInvoice(invoice, vendor, lineItems, logo) { // Render your invoice HTML with the data document.getElementById('vendor-name').textContent = vendor?.name || ''; document.getElementById('invoice-id').textContent = invoice.id; document.getElementById('invoice-name').textContent = invoice.name;
if (logo) { document.getElementById('vendor-logo').src = logo; }
const tbody = document.getElementById('line-items'); lineItems.forEach((item, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${index + 1}</td> <td>${item?.job_title_custom_vendorinvoicelineitems?.subject || '—'}</td> <td>${item?.execution_date_custom_vendorinvoicelineitems ? new Date(item.execution_date_custom_vendorinvoicelineitems).toDateString() : '—'}</td> <td>${item?.quantity_custom_vendorinvoicelineitems || '—'}</td> <td>$${item?.rate_custom_vendorinvoicelineitems || '—'}</td> <td>$${item?.sub_total_custom_vendorinvoicelineitems || '—'}</td> `; tbody.appendChild(row); });}
function downloadPDF() { window.print();}<html><body> <div id="app" class="invoice-page"> <div class="fc-blue-12">INVOICE</div> <div style="text-align:center"> <img id="vendor-logo" width="75" height="55" /> </div> <div id="vendor-name" class="vendor-name"></div>
<div class="pdf-header"> <div class="margin6"> <div class="bold textColor">Billing Address</div> <div class="address-box"> TMG Properties, <br> P.O. Box 112, <br> Ashland, VA 23005 <br> p: (940) 368-2344 </div> </div> <table class="invoice-details"> <tr><td class="bold">Invoice ID</td><td id="invoice-id" class="pad20"></td></tr> <tr><td class="bold">Invoice Name</td><td id="invoice-name" class="pad20"></td></tr> </table> </div>
<table class="invoice-table-container"> <thead> <tr> <th>S.No</th> <th>Job Title</th> <th>Execution Date</th> <th>Quantity</th> <th>Rate</th> <th>Subtotal</th> </tr> </thead> <tbody id="line-items"></tbody> </table>
<button class="fc-blue-btn" onclick="downloadPDF()" id="printbtn">Download</button> </div></body></html>body { padding: 25px; margin: 0; font-size: 14px; letter-spacing: 0.4px; color: #324056; line-height: 20px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif;}
.invoice-page { max-width: 1360px; margin: 0 auto; overflow-x: hidden;}
.fc-blue-12 { font-size: 16px; font-weight: 600; text-align: right; color: #2b2d31;}
.vendor-name { font-size: 15px; font-weight: bold; color: #2b2d31; padding-top: 7px; text-align: center;}
.pdf-header { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 50px;}
.invoice-details { text-align: left; line-height: 30px;}
.invoice-table-container { width: 100%; line-height: 35px; background-color: #f6f6f6;}
th { color: #2b2d31; font-size: 14px; background-color: #f6f6f6;}
.bold { font-weight: 600; color: #2b2d31; }.pad20 { padding-left: 20px; }
.fc-blue-btn { background: #4d93f6; border-color: #4d93f6; color: #fff; padding: 10px 20px; border-radius: 4px; cursor: pointer; position: fixed; bottom: 14px; left: 45%; z-index: 1000;}
@media print { #printbtn { display: none; }}