Widget reference
HTML attributes, embed modes, the JavaScript API, companion entities, and advanced card configuration.
Embed modes
There are three ways to put widget cards on a page. Pick whichever suits your environment.
Custom element mode
Uses <hrv-card> and <hrv-group> as native HTML custom elements.
<script src="https://myhome.example.com/harvest_assets/harvest.min.js"></script>
<script>
HArvest.config({ haUrl: "https://myhome.example.com", token: "hwt_..." });
</script>
<hrv-card entity="light.bedroom_main"></hrv-card>
<!-- Group example -->
<hrv-group>
<hrv-card entity="light.living_room"></hrv-card>
<hrv-card entity="light.dining_room"></hrv-card>
</hrv-group>
The script src points at your HA instance, which serves the widget bundle directly out of the integration's own files at /harvest_assets/harvest.min.js. The widget always matches the running integration version - update HArvest via HACS and every embedded widget picks up the new bundle on the next page load.
Data attribute mode
Uses plain <div> elements with data- attributes. Mostly useful in environments that sanitize custom HTML tags - some page builders, CMSes, or email templates won't allow unknown elements like <hrv-card>.
<script src="https://myhome.example.com/harvest_assets/harvest.min.js"></script>
<div class="hrv-group" data-token="hwt_..." data-ha-url="https://myhome.example.com">
<div class="hrv-mount" data-entity="light.bedroom_main"></div>
</div>
hrv-mount.js (bundled into harvest.min.js) scans the page on load for .hrv-mount and .hrv-group divs and mounts card elements inside them automatically. A MutationObserver handles elements added dynamically after page load.
Programmatic mode
Creates cards via JavaScript using HArvest.create(). Useful when you're building a dynamic UI and want to control exactly when and where cards appear - for example, responding to user interactions or building a dashboard from fetched data.
HArvest.config({ haUrl: "https://myhome.example.com", token: "hwt_..." });
const card = HArvest.create({
entity: "light.bedroom_main",
targetId: "my-container", // ID of the element to append into
});
// Or attach it yourself:
const card2 = HArvest.create({ entity: "sensor.outdoor_temp" });
document.getElementById("sidebar").appendChild(card2);
Token configuration levels
The token and ha-url connection values can be set at three levels. Cards inherit from the nearest level where a value is set - card attributes override group attributes, which override the page-level defaults. You don't have to use all three levels.
| Level | How to set it | Applies to |
|---|---|---|
| Page | HArvest.config({ token, haUrl }) | All cards on the page that don't have a closer override |
| Group | token and ha-url on <hrv-group> | All cards inside that group element |
| Card | token and ha-url on <hrv-card> | That specific card only |
Resolution order: card attribute wins, then the nearest ancestor group, then HArvest.config(). A missing value after all three levels are checked causes the card to show a configuration error.
Page-level (one token for the whole page)
Call HArvest.config() once, put only the entity on each card. The wizard generates this pattern by default when all entities in the snippet belong to the same token.
<script>
HArvest.config({ haUrl: "https://myhome.example.com", token: "hwt_..." });
</script>
<hrv-card entity="light.bedroom_main"></hrv-card>
<hrv-card entity="sensor.outdoor_temp"></hrv-card>
Group-level (multiple tokens on one page)
Use separate <hrv-group> elements when you have cards from different tokens on the same page. Each group carries its own connection settings and shares one WebSocket connection per token.
<hrv-group token="hwt_tokenA..." ha-url="https://myhome.example.com">
<hrv-card entity="light.living_room"></hrv-card>
<hrv-card entity="light.dining_room"></hrv-card>
</hrv-group>
<hrv-group token="hwt_tokenB..." ha-url="https://myhome.example.com">
<hrv-card entity="climate.main_thermostat"></hrv-card>
</hrv-group>
Card-level (each card self-contained)
Put the connection details directly on each card. Useful when cards are dropped into different parts of a page independently - for example, through a CMS shortcode that renders one card at a time.
<hrv-card token="hwt_..." ha-url="https://myhome.example.com" entity="light.bedroom_main"></hrv-card>
Cards sharing the same token and ha-url always share one WebSocket connection regardless of how the values are provided - so card-level configuration doesn't create extra connections compared to page-level.
hrv-card attributes
Only connection-identifying attributes belong on the HTML element. All display configuration (theme, graph settings, companion entities, animations) is managed server-side per entity in the panel and pushed to the widget over WebSocket.
light.bedroom_main, sensor.outdoor_temperature. Use this or alias - not both. If both are present, entity takes priority and a console warning is logged.dJ5x3Apd. Use this or entity - not both. Aliases let you avoid putting real entity IDs in your page source. The server resolves the alias to the real entity ID during auth.HArvest.config() or a parent <hrv-group> for this specific card. Rarely needed - usually set once at the page or group level.HArvest.config() or a parent group. e.g. https://myhome.duckdns.org.hrv-group attributes
<hrv-group> is a context provider that passes connection settings to all descendant <hrv-card> elements. It doesn't render anything itself.
HArvest.config().JavaScript API
The widget exposes a global HArvest object with several methods and properties.
HArvest.config(options)
Sets page-level defaults inherited by all <hrv-card> and <hrv-group> elements on the page. This call is optional - if you set token and ha-url directly on your group or card elements you don't need it. Merges with prior calls - later calls override earlier values for the same key. Connection values are read lazily at WebSocket connection time, so call order relative to element mounting is not a concern.
HArvest.config({
haUrl: "https://myhome.example.com", // HA external URL
token: "hwt_...", // default token for all cards
tokenSecret: "my-hmac-secret", // HMAC secret (if HMAC enabled)
colorScheme: "auto", // "auto" | "light" | "dark"
});
| Option | Type | Notes |
|---|---|---|
haUrl | string | Page-level default HA URL. Inherited by cards/groups that don't set their own. |
token | string | Page-level default token ID. Inherited by cards/groups that don't set their own. |
tokenSecret | string | HMAC signing secret. Only needed when the token has HMAC authentication enabled. |
colorScheme | "auto" | "light" | "dark" | Page-level color scheme fallback. The token's server-side setting takes priority. |
HArvest.create(config)
Programmatically creates an HrvCard element and appends it to a target container. Returns the element instance.
const card = HArvest.create({
entity: "light.bedroom_main",
targetId: "my-container", // ID of the element to append into
// haUrl and token can be specified here or via HArvest.config()
});
HArvest.getCard(entityId)
Returns the HrvCard instance currently registered for a given entity ID, or null if none exists. When multiple cards on the same page subscribe to the same entity, this returns the most recently registered one.
const card = HArvest.getCard("light.bedroom_main");
if (card) {
console.log(card.entityId, card.lastState);
}
HArvest.registerRenderer(key, RendererClass)
Registers a custom renderer class for a given entity domain or device class. Overrides the built-in renderer globally for that key. Last call wins. See the Theming page for details.
HArvest.registerRenderer("light", MyCustomLightCard);
HArvest.registerRenderer("sensor.temperature", MyTempCard); // device class specific
Registering a renderer only handles the display side. If your renderer sends commands (service calls) for a Tier 2 domain, the HA admin must also register that domain's allowed services in the panel under Settings > Custom Domains. Without this step, commands will be rejected with HRV_PERMISSION_DENIED. Tier 1 domains already have built-in service lists and do not need this step. See Entity types - Custom domains for details.
HArvest.renderers
An object exposing all built-in renderer classes so you can extend them:
// Available built-in renderers:
HArvest.renderers.BaseCard
HArvest.renderers.LightCard
HArvest.renderers.SwitchCard
HArvest.renderers.FanCard
HArvest.renderers.ClimateCard
HArvest.renderers.CoverCard
HArvest.renderers.MediaPlayerCard
HArvest.renderers.RemoteCard
HArvest.renderers.TemperatureSensorCard
HArvest.renderers.HumiditySensorCard
HArvest.renderers.BatterySensorCard
HArvest.renderers.GenericSensorCard
HArvest.renderers.BinarySensorCard
HArvest.renderers.InputBooleanCard
HArvest.renderers.InputNumberCard
HArvest.renderers.InputSelectCard
HArvest.renderers.HarvestActionCard
HArvest.renderers.TimerCard
HArvest.renderers.WeatherCard
HArvest.renderers.BadgeCard // compact pill for badge capability
HArvest.renderers.GenericCard // Tier 2 fallback
HArvest.track.anyState(callback)
Registers a callback that fires whenever any entity's state changes on the page. Useful for logging, analytics, or driving custom page logic based on entity state.
HArvest.track.anyState((entityId, state, attributes) => {
console.log(`${entityId} changed to ${state}`);
});
Companion entities
Companions are secondary entities displayed as small status indicators inside a primary card. For example, a motion sensor shown inside a light card, or a lock status shown alongside a cover card.
Companions are configured server-side in the panel (entity detail screen, Display settings, Companion entities). They don't need any HTML attribute on the card element - the server automatically subscribes the companion entities and delivers them alongside the primary entity's definition.
Companion eligibility
Not every entity type can be a companion. Eligible domains:
| Domain | Access in companion role |
|---|---|
| light | Toggle on/off |
| switch | Toggle on/off |
| input_boolean | Toggle on/off |
| fan | Toggle on/off |
| binary_sensor | Read-only state |
| sensor | Read-only state/value |
| cover | Read-only state/position |
| remote | Read-only power state |
There is no per-card companion limit; the 50-entity token budget is the only constraint. Each companion has a "Read only" toggle (default: on). Read-only companions never trigger service calls regardless of the domain. If the primary card is set to "Read only", all its companions are forced to read-only. Badge entities cannot have companions.
Server-managed settings
Card settings are managed server-side per entity in the panel. They are delivered to the widget over WebSocket during authentication and update in real time when changed.
| Setting | Configured in panel | Notes |
|---|---|---|
| Name override | Entity settings card | Custom display name, overrides HA friendly_name |
| Force color scheme | Entity settings card | Auto, Light, or Dark per entity |
| Graph type (line/bar/none) | Entity settings card | History graph for sensor, binary_sensor, input_number |
| Graph hours | Entity settings card | Time window, 1-168 hours |
| Graph period | Entity settings card | Aggregation period in minutes |
| Animate fan icon | Entity settings card | Spinning fan when entity is on |
| Fan display mode | Entity settings card | Auto, On/Off, Continuous, Stepped, or Cycle |
| Light feature toggles | Entity settings card | Show/hide brightness, color temp, RGB controls |
| Climate feature toggles | Entity settings card | Show/hide HVAC modes, presets, fan mode, swing mode |
| Cover feature toggles | Entity settings card | Show/hide position slider, tilt control |
| Media player feature toggles | Entity settings card | Show/hide transport, volume, source selector |
| Input number display mode | Entity settings card | Slider or Buttons |
| Companion entities | Entity settings card | See above |
| Excluded attributes | Entity settings card | Linked with feature toggles bidirectionally |
| Theme / CSS variables | Entities tab, theme card | Pushed on connect and on theme change |
| Language | Preferences tab | BCP 47 tag or "auto" |
| Accessibility mode | Preferences tab | "standard" or "enhanced" |
| On offline behavior | Preferences tab | "dim", "hide", "message", or "last-state" |
| On error behavior | Preferences tab | "dim", "hide", or "message" |
| Offline message text | Preferences tab | Custom text shown when entity is offline |
| Error message text | Preferences tab | Custom text shown on connection error |
All per-entity settings are stored as display_hints on the entity access configuration. Feature toggles and excluded attributes are bidirectionally linked: disabling a feature toggle automatically excludes the corresponding attribute, and vice versa.
Tracking state events
The HArvest.track.anyState() callback receives every state change for every entity on the page. For more targeted tracking, listen on a specific card instance:
// The hrv-card element must be in the DOM before attaching a listener
document.querySelector("hrv-card[entity='light.bedroom']")
.addEventListener("hrv-state-change", (event) => {
const { entityId, state, attributes } = event.detail;
console.log(entityId, state);
});
Offline and error states
When a widget can't reach HA or an entity is unavailable, the card enters an offline or error state. The behavior is configurable per token:
| Setting | On offline behavior |
|---|---|
last-state (default) | Card shows the last known state, dimmed, with a stale indicator |
dim | Card dims but shows no explicit message |
hide | Card collapses to zero height |
message | Card shows the offline message text (configurable per token) |
The on-error setting (for WebSocket or auth errors, not entity-unavailable) follows the same options but without last-state.
Mobile and background tabs
Mobile browsers suspend background tabs and close WebSocket connections after a few seconds. When you switch back to the page, HArvest detects the tab is visible again and reconnects immediately, bypassing the normal backoff delay. During brief disconnects (under 30 seconds), cards continue showing their cached state without any stale indicator. If the disconnect lasts longer than 30 seconds, the "Last known state" banner appears until the connection is restored.