Skip to main content

What Are Custom Widgets?

Protrak is a no-code platform that lets organizations track and manage any kind of data. It shows that data through layouts — pages for viewing, editing, creating, and reporting on records.

A custom widget is a piece of JavaScript code you write to extend or replace parts of those layouts. You can use it to:

  • Show a custom table, chart, or form that Protrak's built-in layout system cannot express
  • Add a button that triggers a specific action (download a file, call a program)
  • Replace how a single field is displayed in a list or view (e.g., mask a sensitive value, show a decoded badge)
  • Build a fully custom create/edit form for complex data structures

Technically, a custom widget is a React 17.x functional component written in a plain .js file. The platform loads it at runtime by injecting a <script> tag into the page, then calls the exported function as window[widgetTitle](pageContext). The result is rendered inside an ErrorBoundary wrapper on the layout.


How Are Widgets Loaded?

When Protrak loads a layout page, it looks up which custom widgets are configured for that layout. For each widget, it:

  1. Downloads the widget's .js file (you upload this in the Admin panel)
  2. Injects the file as a <script> tag into the browser page
  3. Calls window[widgetName](pageContext) — your function receives a pageContext object and returns JSX (React UI)
Browser page
└── Protrak SPA (React app)
└── Layout renderer
└── CustomWidget.jsx
├── Downloads your MyWidget.js file
├── Injects it into <script>
└── Calls window['MyWidget'](pageContext) → renders your JSX

Your widget function runs inside the already-loaded React app. You don't need to set up React yourself — it's already there.

Detailed loading sequence

  1. Admin configures a widget on a layout (e.g., an edit layout group)
  2. When the layout renders, CustomWidget.jsx receives the widget's id (file ID) and title (function name)
  3. useFileDownloadUrl(id) fetches a download URL for the widget's .js file
  4. useScript(widgetUrl) injects a <script> tag — the function is now on window
  5. CustomWidgetLoader calls window[title](pageContext) and renders the result
  6. On unmount, window[title] is set to null to clean up

The Minimal Widget

Every widget is a plain JavaScript function. The function name must exactly match the Widget Title registered in the Admin panel.

function MyWidgetName(pageContext) {
// 1. Access platform utilities and components
const { protrakUtils, protrakComponents } =
React.useContext(customWidgetContext);

// 2. Destructure what you need
const { useProtrakApi } = protrakUtils;
const { Box, H3, Spinner, Container } = protrakComponents;

// 3. Destructure pageContext (shape varies by layout type — see pageContext Reference)
const { instanceId, attributeValues, onAttributeEdit } = pageContext;

// 4. React state and effects
const [data, setData] = React.useState(null);

// 5. Return JSX
return (
<Box>
<H3>Hello from MyWidgetName</H3>
</Box>
);
}

Key constraints

ConstraintWhy
No import or export statementsFile runs in global scope — module syntax would cause a parse error
Function name must exactly match the Widget TitleThe platform looks up window[title] — a mismatch means "Custom widget function not found"
React 17.x only — functional componentsClass components are not supported
No variables or functions defined outside the widget functionAnything outside the function is exposed to window and can conflict with other widgets
All hooks must be called unconditionally at the top levelStandard React hook rules apply — no hooks inside conditionals or loops
React is available as a globalDo not import it — use React.useState, React.useEffect, etc. directly
customWidgetContext is available as a globalProvides all platform utilities and components

What Is pageContext?

pageContext is the single argument your widget function receives. It gives you:

  • Data about the current record — attribute values, instance ID, type name
  • Edit functionsonAttributeEdit, saveInstance to push changes into the form
  • Platform utilities — hooks, API client, date formatters
  • User information — logged-in user's name, roles, profile

The exact content of pageContext depends on which layout type your widget is placed in. See pageContext Reference.


Platform APIs (customWidgetContext)

Your widget accesses two global objects through React's context system:

const { protrakUtils, protrakComponents } =
React.useContext(customWidgetContext);

customWidgetContext is a React Context provided by CustomWidgetContextProvider (see CustomWidgetContext.jsx). It exposes two namespaces:

ObjectWhat it contains
protrakComponentsReady-made UI building blocks (buttons, dropdowns, dialogs, tables, spinners)
protrakUtilsHooks and utilities (useProtrakApi, protrakApiClient, useRouter, date formatters, Enums)

You never import these — they are injected by the platform at runtime. See the API Reference for the full component and utility lists.


Widget Registration (.json file)

Every widget .js file has a paired .json file with the same name. This file is committed to the Protrak customization project and deployed via the protrak-publish-schema.yml pipeline. It registers the widget with the platform:

{
"name": "MyWidgetName",
"displayName": "My Widget Display Name",
"target": "EditLayout",
"description": "Optional description for admin users"
}

Supported target values:

TargetWhere the widget appears
AnyAny layout (general purpose)
HomePageThe home page dashboard
DashboardLayoutA dashboard tab
ViewLayoutA section or tab on a record's view page
ViewLayoutWidgetA relation widget on a view page (replaces the default relation grid)
EditLayoutA section or tab on a record's edit page
CreateLayoutA section on a record's create page
ReportLayoutThe visualization inside a report
CustomActionA button in a bulk-action toolbar
CustomAttributeRendererReplaces the display of a single attribute cell in a list or view
AnnotateFileSupplies data to the Annotate File action on a view page (a data function, not a rendered widget)

Suggested Reading Order

If you are new to custom widgets, read these pages in order:

  1. pageContext Reference — What data is available to every widget
  2. Home Page Widget — Simplest type; good starting point
  3. View Layout Widget — Most common type; read and display record data
  4. Edit / Create Layout Widget — Editing attributes, syncing with the form save
  5. Dashboard Layout Widget — Fetch and display data in a dashboard tab
  6. Report Layout Widget — Custom table/chart inside a report
  7. Custom Attribute Renderer — Replace a single field cell
  8. Custom Action Widget — Bulk action buttons
  9. Annotate File Widget — A data function, not a UI widget
  10. Patterns Catalog — Reusable patterns from real implementations