Skip to main content

Custom Widgets

warning

Custom widgets are a new feature. Share feedback, ask questions, and discuss ideas in our GitHub Discussions.

Custom widgets allow you to fetch data from any HTTP API and display it on your Homarr dashboard. You define the API endpoint, authentication, and how the response should be rendered - no code compilation or server restart required.

Creating a Custom Widget

To create a custom widget, navigate to the Custom Widgets section in the management sidebar and click the Add button. Fill in the configuration:

  • Name - Display name shown in the widget picker and on the dashboard
  • Description - Optional description shown in tooltips and management UI
  • Icon URL - Optional URL to an icon image for the widget
  • URL - The API endpoint to fetch data from (must include protocol, e.g. https://api.example.com/stats)
  • Authentication - How the API request is authenticated:
    • none - Public APIs with no authentication
    • bearer - Bearer token authentication
    • basic - HTTP Basic auth (username + password)
    • apiKeyHeader - API key sent as a custom HTTP header
    • apiKeyQuery - API key sent as a query parameter
  • Header Name - Custom header or query parameter name for API key auth (e.g. X-API-Key)
  • HTTP Method - GET, POST, PUT, PATCH, or DELETE
  • Request Body - JSON string body for POST/PUT/PATCH requests
  • Display Type - How the API response is rendered (see below)

Display Types

Display TypeDescriptionBest For
Single ValueExtracts a single value with a label and unitMetrics: temperature, uptime, user count
Key ValueMultiple labeled key-value pairs with optional unitsSystem stats: CPU, memory, disk
TableAPI array data rendered as a sortable tableLists of items with columns
Stat GridLabeled values in colored stat cardsCounts: movies, series, albums
Progress BarsValues as progress bars with percentagesUsage: disk, quota, capacity
Status IndicatorGreen/red status dots for health checksService monitoring
Count GridSimple counts in a grid (no colors)Library counts
RawPretty-prints the raw JSON responseDebugging
Action ButtonClickable button executing the API requestTriggers: restart, clear cache
Custom JSXCustom JSX template with Mantine v9 componentsFull layout control

AI-Powered JSX Generation

When editing or creating a custom widget with the Custom JSX display type, you'll find a Copy Prompt button. Clicking it copies a pre-formatted prompt describing your widget's name, API endpoint, and available Mantine components. Paste this into your preferred AI assistant (ChatGPT, Claude, Copilot, etc.) to generate a JSX template tailored to your data.

Example: Pokédex widget using Custom JSX
{
"$schema": "homarr-custom-widget-v2",
"name": "Pokédex",
"description": "Browseable Pokémon list",
"iconUrl": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png",
"url": "https://pokeapi.co/api/v2/pokemon?limit=75",
"authType": "none",
"method": "GET",
"displayType": "customJsx",
"displayConfig": {
"type": "customJsx",
"template": "<Stack gap=\"md\" p=\"xs\">\n <Card withBorder radius=\"xl\" p=\"md\" shadow=\"md\">\n <Group justify=\"space-between\">\n <Title order={3}>Pokédex</Title>\n </Group>\n </Card>\n <PaginatedList pageSize={12}>\n <Grid gutter=\"sm\">\n {data.results.map((pokemon, i) =>\n <Grid.Col span={1.5}>\n <Anchor href={pokemon.url} target=\"_blank\" underline=\"never\">\n <Card withBorder radius=\"xl\" p=\"xs\" shadow=\"md\">\n <Stack gap=\"sm\" align=\"center\">\n <Group justify=\"space-between\" style={{ width: \"100%\" }}>\n <Badge size=\"sm\" color=\"red\">#{i + 1}</Badge>\n <Text fw={800} tt=\"capitalize\">{pokemon.name}</Text>\n </Group>\n <Avatar\n src={\"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/\" + (i + 1) + \".png\"}\n size={92}\n radius=\"xl\"\n />\n </Stack>\n </Card>\n </Anchor>\n </Grid.Col>\n )}\n </Grid>\n </PaginatedList>\n</Stack>"
}
}

Importing and Exporting

Custom widgets can be exported and imported as JSON files. To export, select the widget in the list and click the export button. To import, click the import button and paste the JSON. Secrets (API keys, passwords) are never included in exports and must be configured after import.

The import format uses "$schema": "homarr-custom-widget-v2" to identify the widget version.

Available Mantine Components for Custom JSX

When using the customJsx display type, your template has access to a whitelist of Mantine v9 components. Unrecognized components, event handlers, and dangerous tags are stripped for security.

Layout

ComponentDoc
Stackdocs
Groupdocs
Flexdocs
Grid / Grid.Coldocs
SimpleGriddocs
Centerdocs
Containerdocs
Spacedocs
AspectRatiodocs

Typography & Content

ComponentDoc
Textdocs
Titledocs
Codedocs
Highlightdocs
Markdocs
Kbddocs
Blockquotedocs
Anchordocs
NumberFormatterdocs

Data Display

ComponentDoc
Badgedocs
Card / Card.Sectiondocs
Paperdocs
Alertdocs
ThemeIcondocs
ColorSwatchdocs
Avatar / Avatar.Groupdocs
Imagedocs
BackgroundImagedocs
Indicatordocs
Pilldocs
Spoilerdocs

Tables

ComponentDoc
Table / Table.Thead / Table.Tbodydocs
Table.Tr / Table.Th / Table.Tddocs

Lists

ComponentDoc
List / List.Itemdocs
Timeline / Timeline.Itemdocs

Feedback & Loading

ComponentDoc
Progress / Progress.Sectiondocs
RingProgressdocs
Skeletondocs
Loaderdocs
ComponentDoc
TabsContainer / TabPanelCustom interactive component
Accordion / Accordion.Item / Accordion.Control / Accordion.Paneldocs
ScrollAreadocs
Tooltipdocs

Charts

ComponentDoc
AreaChartdocs
BarChartdocs
LineChartdocs
DonutChartdocs
PieChartdocs
RadarChartdocs
RadialBarChartdocs
Sparklinedocs

Interactive Components

ComponentDescription
PaginatedListClient-side pagination wrapper
CollapsibleExpandable/collapsible section
StatBarHorizontal stat bar
TypeBadgeType-styled badge
Dividerdocs

Template Bindings

Your template receives:

  • data - The sanitized API response object. Access fields via data.fieldName or data.results[0].name.
  • String(v) - Type-safe string conversion
  • Number(v) - Type-safe number conversion
  • Boolean(v) - Type-safe boolean conversion
  • Math - Safe subset: round, floor, ceil, abs, min, max, pow, sqrt, PI
  • JSON.stringify(v) - JSON serialization
  • Array.isArray(v) - Array type check
  • Object.keys(v), Object.values(v), Object.entries(v) - Object utilities

Security Constraints

  • Event handlers (onClick, onChange, etc.) are stripped
  • Dangerous HTML attributes (dangerouslySetInnerHTML) are stripped
  • script, iframe, object, embed, form, style, link, meta, base tags are forbidden
  • Template strings containing eval, Function, import, require, globalThis, window, document, fetch are rejected
  • Anchor href attributes are validated to only allow https://, relative (/), and hash (#) URLs