* Let browsers below the legacy floor continue at their own risk
Browsers below the floor get a "Continue anyway" button on the launch
screen instead of a dead end, e.g. for a wall dashboard. The warning returns
monthly, and from the first reminder on offers "Don't show again".
* Space the launch screen without max() on Chrome below 79
The launch screen's top spacer and OHF logo margins use max() with var()
inside. Chrome below 79 drops those after the cascade, leaving no margin,
so the logo touched the bottom edge (Chrome 67 to 78 are in the legacy
floor). Plain margins now come first, the max() rules behind @supports.
* Keep the browser warning up while the app loads
Once the user continued, the launch screen went blank until the legacy
build took over, which can take a while on these devices. Keep the message
and only drop the buttons.
* Say the browser is no longer supported instead of too old
With the option to continue it does run, so "too old to run Home Assistant"
contradicted the button. The same text now reads right before and after
continuing.
* Use a plain color for the launch screen buttons
Theme variables are not set yet while the launch screen shows, so
var(--primary-color) always fell back anyway.
* Add selection mode with bulk remove to the Marketplace repositories page
* Guard bulk remove against double clicks and drop stale selections
* Clear the table selection when a selected repository gets installed
* Restore the comments that still apply
* Use a Marketplace string for the bulk action menu
* Drop rendering-only tests
* Uncheck data table rows that can no longer be selected
* Use one Remove chip and let the table drop installed rows
---------
Co-authored-by: Aidan Timson <[email protected]>
* End the ZHA permit subscription when the search ends
* End the ZHA search when the connection drops
* Don't send a stale ZHA search after a reconnect
* Hold the last value across gaps in history graphs
* Hold values across gaps in every graph, without an opt-in
* Hold the real last state across gaps and keep their curves tight
* Only hold stretches the raw history was quiet for
* Keep the temperature forecast curving across gaps
* Decide which stretches to hold once, from the raw history
* Hold neither across unavailable states nor below the sampling frame
* Show which integrations use an integration loaded as a dependency
Some integrations, like Modbus, have no config flow and are loaded
because another integration lists them in its manifest dependencies.
The frontend treated these as YAML integrations. The integration page
told the user to configure it in configuration.yaml, and the dashboard
showed a YAML card for it.
The integration page now fetches the loaded manifests for integrations
without a config flow. If a loaded integration depends on the domain,
the page shows "Used by <integrations>" instead of the YAML text. The
dashboard does not show a YAML card for a domain that a loaded
integration depends on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Show the integrations that use a dependency as linked cards
Replace the "Used by" text with a "Used by" section. It lists each
loaded integration that depends on this integration, with its logo and
a link to its integration page. The entries section shows "No entries"
instead of the YAML text for such an integration.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Show only the "Used by" section for a dependency
An integration that other loaded integrations depend on, and that has no
config entries, now shows only the "Used by" section. The page does not
show the empty entries section. It also does not show the "Add entry"
button, which only opens the "set up in YAML" dialog for these
integrations.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Match the demo Modbus and LoRaWAN manifests to core
Modbus and LoRaWAN have no config flow, and the integrations that use
them list them as dependencies. The demo now does the same, so their
integration pages show the "Used by" section.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Hide system integrations from the "Used by" section
System integrations, like Default Configuration, depend on many
integrations. Listing them in "Used by" does not help the user.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Read the dependents from the manifests context
The integration page now finds the integrations that depend on it from
the shared manifests context, instead of its own manifest/list call.
It subscribes to the context only for an integration without a config
flow, so other integration pages do not make the context fetch the
manifests.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Link the integration page to the integration's settings panel
The Connectivity settings panels, like Zigbee and Modbus, are not
reachable from the integration page unless the integration has a config
entry. A user that opens the integration page looks for these settings.
The integration page now shows a button that opens the panel of the
integration. The button uses the panel name from the Connectivity page.
LoRaWAN, Modbus, Radio frequency, and USB (Serial) are added to the map
of integrations with a panel.
An integration with a panel and no config flow does not show the
"Add entry" button. For these integrations, it only opens the "set up
in YAML" dialog, and the panel is where to set them up.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Hide the YAML texts for integrations set up in their panel
An integration with a settings panel and no config flow, like Infrared,
is set up in that panel. Its integration page told the user to set it up
in configuration.yaml. The page now shows only the settings button for
such an integration when it has no entries.
The demo Infrared and Radio frequency manifests now match core, so these
pages show it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Make the settings button primary when it is the only action
An integration that is set up in its panel shows no "Add entry" or
"Add device" button, so the settings button is its only action.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Show the settings button only when there are no entries
Each config entry row of an integration with a panel already has a
link to that panel, so the button repeats it on pages like Zigbee.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Link the MCP integration pages to the AI settings
The AI settings show how to connect to the MCP server and the URL of
each of its APIs. The MCP client and MCP server integration pages now
have an "AI settings" button that opens them. The button is the
primary action when the page has no "Add entry" button.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Scroll the AI settings to the MCP card from the MCP pages
The AI settings page now scrolls to the section named in the URL hash,
like the backup settings page. The "AI settings" button on the MCP
integration pages links to the MCP card, which is below the AI task
card.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Keep the demo route when opening the AI settings
The demo routes with the URL hash. The AI settings page cleared the
hash even when it did not name a section, so a reload of the demo lost
the page. It now clears the hash only after it scrolls to a section.
The "AI settings" button links to the page without a section in the
demo, because a link with a hash skips the demo route conversion.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Move the settings panel and MCP buttons to their own PRs
This PR keeps the "Used by" section for integrations that other
integrations depend on. The settings panel button and the MCP link to
the AI settings move to separate PRs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Load the Modbus dependents in the demo
The dashboard reads the dependencies of loaded integrations only. The
demo listed Modbus as loaded, but not Flexit, SolarEdge Modbus, and
Fronius, so it showed a YAML card for Modbus.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Sort the "Used by" list and wait for it before the YAML texts
The manifests come from a set in core, so their order can change
between restarts. The "Used by" list is now sorted by name.
Until the manifests load, the page does not know the dependents. It
showed the YAML texts and "Add entry" first and then replaced them with
"Used by". The page now holds back those texts and the button for an
integration without a config flow until the manifests load.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Apply review feedback
- Make the settings button primary whenever it is the only action,
like the MCP button. Thread, or MQTT with its one entry, have no
"Add entry" button.
- Set the demo LoRaWAN manifest to the service type, like core, so the
demo dashboard checks its dependents.
- Fix the punctuation of the YAML text.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Show the entries while the dependents load
The page waits for the manifests of the loaded integrations before it
shows the YAML texts. If that request fails, the wait never ends. Only
a page without entries can show "Used by", so only such a page waits.
A page with entries now shows them even when the manifests do not load.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Clear the manifest when the integration page changes domain
The integration page is reused when you follow a "Used by" link. It
kept the previous integration's manifest until the new one loaded, so
going back to Modbus from Flexit briefly showed "Add entry" and the
empty entries section. The page now clears the manifest on a domain
change, and a page without entries waits for the manifest before it
shows the YAML texts and "Add entry".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
---------
Co-authored-by: Claude <[email protected]>
Stop rounding and distorting integration icons on the area page
The generic img rule meant for the area picture also applied to the 24px
brand icons in the device list, clipping square integration logos (for
example Awair) into circles. Scope that rule to the area picture and size
the icons with width/height attributes like the device page does.
Co-authored-by: Claude Fable 5.1 <[email protected]>
* Only match an OTBR to a Thread network it is part of
findOTBRInfoForDataset returned the dataset's preferred border router
without checking that it is still on that network. When the border
router had moved to another network, the Thread panel offered to reset
it from the card of a network it no longer belongs to, which would
replace the border router's current network.
Require the extended PAN ID to match for the preferred border router
too, and drop the active dataset check in the network information page
that worked around the same problem.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Update findOTBRInfoForDataset tests for the network check
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep findOTBRInfoForDataset fallback tests independent of key order
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
End slider and color wheel interaction when a pan is cancelled
ha-control-slider and ha-hs-color-picker restored their value on
pancancel without firing an event, so consumers never learned that the
interaction ended. The light color pickers then kept ignoring state
updates until the next interaction. Fire the same end-of-interaction
event as panend (and as ha-control-scrubber already does), and restore
the wheel's local value along with its cursor position.
* Narrow helper create and area update data functions to the API they use
The create helper dialog can then pass the API context instead of the
full hass object.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eHviQBgc6SiiNrMfyY
* Consume contexts in helper forms instead of hass
The helper forms only read translations, locale and config, so they now
consume the internationalization and config contexts. This avoids
rerendering them on every unrelated hass change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eHviQBgc6SiiNrMfyY
* Consume contexts in the create helper dialog instead of hass
The dialog reads translations, config, the API and the connection from
their contexts and no longer passes hass to the helper forms.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eHviQBgc6SiiNrMfyY
* Refactor API calls to use HomeAssistantApi for improved type safety and consistency across data handling
---------
Co-authored-by: Claude <[email protected]>
* Give automation editor rows a config path
Each list and row in the automation and script editor extends the path
of its ancestor with its own segment through a Lit context, e.g.
["actions", 0, "then", 1]. Rows that open in the sidebar register in a
per-editor registry by path, as groundwork to find the row a config path
belongs to, e.g. to point at an error in it.
Move the generic path type and helpers from the Lovelace editor to
common/util/config-path and use ConfigPath everywhere.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Test config path helpers on their own
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
The Settings > System menu said "Backups" while the page header said
"Backup". Reuse the caption key like the other system pages do, so
the two can't drift apart again.
* Add a health dialog to config entries
* Address review feedback
* Address review feedback
* Address review feedback
* Address review feedback
* Use the integration filter for the logs link
The helpers table lists disabled helpers, but its area filter left them
out, so a disabled helper without an area disappeared when picking
No area, and one in an area disappeared when picking that area. Match
the entities page, which already passes include-disabled-entities.
* Fix stale color sent after quick drag in light color pickers
When the color temperature slider is dragged and released within the
500 ms throttle window, the release handler skipped sending because the
picker value already equalled the final value, relying on the pending
throttled call. A state update from the leading throttled call then
reset the picker value (no longer interacting), so the trailing call
sent the stale initial value and the light ended up at the wrong color
temperature.
Cancel the pending throttled call on release and always send the final
value. Apply the same cancel to the RGB picker, where a pending trailing
call could send a stale color after the final one.
* Keep released value in light color pickers until state settles
After release, keep showing the released value for a short time and
ignore state updates in between, so that late state updates from calls
sent while dragging no longer make the slider jump back before the
final value is reported.
* Don't sync light color pickers while a new drag is active
If a new drag starts before the release hold of the previous one ends,
the hold timer must not overwrite the picker value with the reported
state, as that makes the control jump and lets a pending throttled call
send the older value. The release of the new drag starts a new hold.
* Address review: keep brightness normalization in sync, hold native input
Keep the brightness normalization of RGB-only lights in sync with the
reported state while the picker values are held (during a drag or the
release hold), as it is applied to the next color sent. Otherwise
successive color selections could dim the light repeatedly.
The native color input has no release event and sends throttled, so
refresh the release hold on every input. This keeps state updates from
calls sent while picking from overwriting the pending value.
* Use PendingValueSync in light color pickers and end interaction on release
Replace the fixed release hold timer with PendingValueSync, so state
updates are ignored only while a call is queued or in flight. Also clear
_isInteracting in the release handlers, so a keyboard adjustment or a
cancelled pan no longer stops the picker from following the state.
* Configure remote Bluetooth adapters from the adapters page
Remote scanners such as ESPHome Bluetooth proxies have their scanning
mode and other settings in the options flow of the integration that
provides them. Show the configure button for remote adapters on the
Bluetooth adapters page and open that integration's options flow, found
through the scanner device's via device, so users no longer have to find
the device under Devices & services.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ALzdAQkZAy37oGWd7GMtbQ
* Prefer the providing integration's device when finding the source entry
Other integrations may add config entries to the scanner's own device,
so look at the via device first and only fall back to the scanner's
device.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ALzdAQkZAy37oGWd7GMtbQ
* Only use the via device and skip disabled source entries
Drop the fallback to the scanner's own device, which could pick up an
unrelated integration's entry, and don't offer to configure a remote
adapter whose providing config entry is disabled or has no options flow.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ALzdAQkZAy37oGWd7GMtbQ
* Check for a configurable source entry in the template
Keep _getSourceConfigEntry a plain lookup, as suggested in review, and
skip the cog for disabled or non-configurable source entries where it
is rendered.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ALzdAQkZAy37oGWd7GMtbQ
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Let users hide entities from the maintenance page
Battery and problem sensors land on Maintenance purely by device class, so a car's target charge level showed up with no way out short of hiding the entity everywhere.
Store a hidden_entities list in maintenance frontend system data and let the resolver take it, so the Home dashboard summary badge and the overview check drop the same entities as the page. The pencil enters an inline edit mode: the page regenerates with every tile wrapped in a new entity-visibility card that dims hidden tiles with a dotted border and toggles them on tap, saving at once.
In edit mode every entity is shown anyway, so a tap only flips the wrapper's own hidden flag and the panel just saves; the view is regenerated when edit mode ends. Nothing is rebuilt per tap and focus stays on the tile that fired. A failed save reloads the configuration and forces a rebuild so the wrappers show the stored state again.
Saves go through a queue shared by all panel instances, and a panel loads its config only after that queue drains, so leaving and reopening the page while a save is in flight cannot reload a snapshot that lacks it. A failed save shows a toast and reloads, unless a newer save is already queued on top of it.
* Test hidden entities in the maintenance strategy
Cover both modes of the generated view: hidden entities are left out
normally, and while editing they are kept as entity-visibility wrappers
with hidden set so users can show them again.
* Add option to hide day names in the weather forecast card
Hourly and twice daily forecasts show the weekday where a new day
starts. In the compact layout it takes a separate column with no icon
or temperature, which pushes the last requested slot under the edge
fade of the scroll strip. The show_day_names option, on by default,
hides the label in both the compact and the tall layout.
The editor offers the switch for hourly and twice daily forecasts only,
because daily forecasts already label every item with its day.
* Hide day names in hourly weather forecasts
Hourly forecasts already show 0:00 where a new day starts, so the
weekday label adds nothing there. In the compact layout it also took a
column of its own and pushed the last slot under the edge fade.
Twice daily forecasts keep their day names, because their items only
say day or night.
This replaces the show_day_names card option, because the card is due
for a rework and should not gain new options before it.
The demo kept its own copy of the html/body rules that
_style_base.html.template owns, and the copies had already drifted. That is
the same duplication that let the demo miss the launch screen overlay styles.
Make _style_base.html.template reusable by moving its viewport meta into
_meta_viewport.html.template, included wherever _style_base was emitting it,
so every existing page renders exactly as before. The demo can then include
_style_base and keep only the rules that are really its own, along with its
own viewport meta, which does not set user-scalable=no.
Also drop a short-viewport override in the launch screen partial that
restated the base value, and spell out why the media queries carry a body
prefix.
* Show YAML editor shortcut in sidebar menus
* Remove unused platform import from field selector sidebar
* Show YAML editor shortcut in automation row menus
* Show YAML shortcut in script field row menus
* Fix YAML shortcut hint scope and styling
The color wheel is drawn as a centered square (object-fit: contain), but
the pointer position was mapped using the full width and height of the
canvas box. In Safari the canvas box is wider than it is tall, so the
horizontal position was off and the cursor did not follow the pointer.
Map the pointer position relative to the center of the canvas box and
its shorter side, which is the drawn wheel.
* Keep dialogs on the remaining default-route redirects
The energy panel, the energy config tabs and the media browser fill in
their default route with a replace, which closed a dialog restored from
the URL and dropped the query the restore needs. They now pass
keepDialogs and keep the query, like the router and dashboard redirects.
The more-info restore runs on every location change, so those redirects
re-showed the dialog that was already open. That hoisted it above any
dialog opened on top of it and reset its view. Skip the restore while
the more-info dialog is open.
* Only skip the more-info restore for the entity already shown
The restore skipped whenever a more-info dialog was open. A deep link
that arrived while the previous dialog was still closing after
navigate's wait was dropped, and when two deep links queued up the
older one won and the newer was never opened.
The dialog manager now exposes the params a dialog was shown with. The
restore skips only when the open dialog already shows the URL's entity,
and a queued restore bails when the URL moved on to another entity.
* Drop a queued more-info restore when the URL's view moved on
Two deep links for the same entity with different views queued in one
frame let the older restore open the dialog and write its view back to
the URL. The queued restore now also bails when the URL's view differs
from the one it captured, so the newest deep link wins.
* Remove ha-list and ha-list-item
Nothing uses the mwc-based list components anymore, so remove them
together with the @material/mwc-list dependency, its patch and the
test mocks that still stubbed them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Remove ha-list and ha-list-item
Nothing uses the mwc-based list components anymore, so remove them
together with the @material/mwc-list dependency, its patch and the
test mocks that still stubbed them. Also drop the --mdc-list-* custom
properties that nothing reads anymore.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Add a No area option to the area filter
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fix HTML syntax in ha-filter-floor-areas.ts
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* Match the No area filter to each table's area column
Use the effective device area so child devices that take their parent's
area aren't listed, include entities that only have a state, and only
count the device's area on the entities and helpers tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Only refresh the No area filter when entities are added or removed
Co-Authored-By: Claude Fable 5.1 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* Round the volume shown in the siren advanced controls
The volume is stored as a fraction and was shown as volume * 100, so a
typed 7 came back as 7.000000000000001.
* Drop the siren controls rendering test
Rendering tests are out of scope for the frontend tests.
While editing, the dashboard keeps ?edit=1 in the URL of the current
history entry, so a view left in edit mode stays in history with it.
Leaving edit mode only cleans the current entry, and going back to the
earlier one turned edit mode on again. A history pop now clears the
param when edit mode is off instead of entering it.
* Name energy devices after their entity when a device has several meters
* Keep the device name as placeholder until an energy statistic is picked
* Compute the picker ambiguity set from the memoized arguments
* Count user-set energy device names towards a label collision
* Keep a plain value under its choice in the choose selector
The change handlers spread a plain object value, like a duration, into
the wrapper, so its old keys ended up in the saved value and switching
choices lost it.
* Test the choose selector's value wrapping as a pure function
Rendering tests are out of scope for the frontend tests, so the wrapping
moves to computeChooseValues and is tested directly.
* Use the suggested value on a required integer slider without data
The fallback chained a boolean check with ||, so the slider got true
instead of the suggested value, and a default of 0 was skipped.
* Test the integer slider's value logic as a pure function
Rendering tests are out of scope for the frontend tests, so the value
resolution moves to computeIntegerSliderValue and is tested directly.
* Add hac-card and hac-header as first components of the hac library
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Move hac components into a publishable workspace package built with Rslib
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Rework hac package: tree-shakable entry points, safe registration, standalone theming
- Separate component classes from registration: the root entry exports
classes only, ./card, ./header and ./all register elements. Named
imports from the root are now tree-shaken, and sideEffects lists only
the registering modules (dist and src, as the repo resolves to src).
- Skip registration when a tag is already defined, so Home Assistant and
custom cards can ship the library side by side.
- Fix hac-header empty-slot handling: :has(::slotted()) is not supported
by browsers, so empty icon and action slots added gaps.
- Expose the header title as a heading with a configurable level.
- Add fallbacks for all theme variables so components render outside
Home Assistant, lay out footer actions, drop overflow clipping.
- Resolve the package to its sources via a hac-source export condition
instead of hand-written aliases, add it as a workspace dependency and
include it in lit-analyzer.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Add hac as a workspace dependency of the frontend
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Add global, scoped and dynamic loading modes to hac components
Each component now lives in components/<name>/ with its class, a
version.ts, a CHANGELOG.md and three entry points:
- @home-assistant/hac/<name>: registers globally, as Home Assistant does
- <name>/scoped: registers the bundled copy in a scoped registry
- <name>/dynamic: uses Home Assistant's copy when its version is
compatible, the bundled copy otherwise
ScopedElementsMixin (@home-assistant/hac/scoped) gives a Lit element its
own registry and supports both the standard API and the older API of the
scoped registry polyfill that Home Assistant loads. Without either, it
falls back to global registration.
Home Assistant publishes its components with versions and lazy loaders
at startup. The HTML creates a pending slot first, so extra modules that
load in parallel with the app wait for it instead of missing it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Support plain custom elements in scoped mode and require scoped elements
- Add createScopedElementRegistry, attachScopedShadow and
createScopedElement, so plain custom elements can use scoped and
dynamic components, not just Lit elements.
- ScopedElementsMixin builds on them and now takes the elements as a
required argument: forgetting them is a type error instead of silently
rendering unknown elements. Plain JavaScript gets a clear runtime error.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Add button group and close option for hac-header
- Add the button group with hac-button and hac-button-close, a plain
icon button with a close icon.
- hac-header gets show-close and close-label; the close button fires
hac-close.
- Components declare the hac elements they render as static
dependencies. global registers them globally, so Home Assistant uses
no scoped registries; scoped and dynamic use a variant with its own
registry of bundled dependencies, so a component and its dependencies
always come from the same copy.
- Exclude generated package output from the root type check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Show a dismissable greeting card on the profile page using hac
Trial use of the hac components inside Home Assistant: a hac-card with
a hac-header that has show-close enabled, localized title and close
label. Dismissing hides it until the page is reloaded.
Using it surfaced two things:
- A card with only a header still rendered the padding of its empty
content area, so hac-card now omits it.
- lit-analyzer only follows imports one level into node_modules, where
the workspace package resolves, so files using hac entry points failed
its missing-import check when linted alone, as the pre-commit hook
does. Allow one more level.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Keep the patches comment next to PATCHES_DIR
The hac alias block was inserted between the comment and the constant it
describes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Remove the hac pages from the gallery
The library is a concept for now and should get its own documentation
later.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Give every hac element its own entry points and drop the all export
Groups now only organize elements: a group's directory holds its default
element and variants live in subdirectories, mirroring the import paths.
@home-assistant/hac/button registers hac-button only, and
@home-assistant/hac/button/close registers hac-button-close, each with
its own version, changelog, scoped and dynamic entry points.
The all export registered every bundled copy globally, which a custom
card could use to replace Home Assistant's own components, and nothing
used it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Rename the package to @home-assistant/components
The package name says what it is; hac- stays the prefix of the element
tags and classes. The export condition that resolves workspace packages
to their sources is renamed from hac-source to the neutral ha-source, so
future packages can use it too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Load bundled components in dynamic mode only when they are needed
dynamic entry points now import only the element's version up front and
load the bundled component with a dynamic import when Home Assistant
cannot provide a compatible copy, so bundlers split it into a chunk that
is not downloaded otherwise.
The static version on the component classes is removed: the host
publishes its versions in the provider list, so version.ts is the only
source of truth.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Fall back to the scoped entry point in dynamic mode
Each dynamic entry point loads its bundled element through a named
loadScoped function that imports the element's scoped entry point, so
dynamic uses exactly what scoped mode registers and createDynamicLoader
no longer builds the scoped variant itself.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Drop the registration note from the component docs
How elements are registered is the same for every component and is
documented once in the package README.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Move the slot checks of hac-card and hac-header into a shared helper
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Group the utils of the components package by purpose
registration/ holds what defines elements (global, scoped, dynamic),
element/ the helpers components use themselves.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Define each element once with its tag name next to its version
- version.ts becomes info.ts with TAG_NAME and VERSION, the cheap module
that dynamic, global, HA's provider and dependent components read the
tag name from. Only HTMLElementTagNameMap and Lit templates keep the
literal, as the tooling needs it there.
- scoped and dynamic entry points export one definition object, e.g.
hacCard = { tagName, element }, instead of a single-entry map.
ScopedElementsMixin, createScopedElementRegistry and static
dependencies take lists of definitions.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Drop the pending provider slot from the HTML
Only extra modules can run before the app publishes its components, and
then they simply use their bundled copies. Not worth the inline script
while the library is a concept: the host now just publishes the list.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Remove the root entry point of the components package
Nothing used it and it exposed the registration internals as public API.
Every element, the scoped helpers and the provider have their own entry
points; class types come from an element's scoped entry point with
import type.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Clean up the components package API and naming
- Drop the Hac prefix from library-level names, which are not elements:
ElementDefinition, ElementLoader, ComponentClass, ProvidedComponent(s),
PROVIDER_KEY. HA's provider file becomes components-provider.ts.
- /scoped no longer exports scopedRegistrySupport, and the mixin no
longer adds a static scopedRegistry; both were internals.
- scopedVariant uses the mixin's subclass instead of wrapping it again.
- Rename utils/registration/version.ts to compatibility.ts, as elements
keep their version in info.ts, and keep ComponentClass with the other
definition types.
- Update the outdated Rslib config comment: only global.ts registers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Clarify where to create the scoped registry
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Remove the per-element changelogs from the concept
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Remove the dynamic loading mode from the components package
The concept starts with global and scoped only. Dynamic mode, with the
provider list HA publishes, the version compatibility check and loader
support in the registry helper, can be added later.
Elements keep their VERSION in info.ts.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Regenerate the lockfile on top of dev for the components package
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Use the semantic color tokens in the components
The components use --ha-color-* tokens (surface, on-surface, text,
border, primary fill, focus) instead of the legacy theme variables, with
the light values as fallback outside Home Assistant. User theme colors
still apply because HA derives the --ha-color-primary-* palette from
them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Reduce the components package to the card for the concept
Remove the button group and the header. The profile greeting is a plain
hac-card now, as it had no close button to dismiss it anymore. The
dependency mechanism stays, documented with a generic example, for the
first element that renders other elements.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Remove the dependency mechanism from the components package
Nothing uses it since the header and buttons are gone. The card now
registers itself with define, and its scoped entry point exports the
class directly. It can come back with the first element that renders
other elements.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* Use hac-card for the long-lived access tokens in the profile
The card header is a heading in the header slot, the content needs no
wrapper, and the create button sits in the footer slot.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CV5NJdqS5t7iCSfyK7Xsux
* refactor: update pnpm workspace settings and improve profile dashboard layout
- Excluded 'rs-module-lexer' from allowed builds in pnpm workspace configuration.
- Adjusted footer alignment in the long-lived access tokens card for better layout.
- Removed unnecessary 'hac-card' from the profile dashboard, simplifying the structure.
- Updated CSS to target only 'ha-card' for styling, enhancing consistency.
- Removed greeting title translation to streamline user experience.
* fix: update caching paths and improve long-lived tokens card styles
* fix: update theming fallback order and improve hac-card styles
* fix: replace `replace` with `replaceAll` for consistent wildcard handling in component source aliases
* copilot
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
* Keep rgba() colors in the legacy CSS build
Raising the legacy floor to Chrome 67 lets lightningcss rewrite rgba()
to 8-digit hex (#rrggbbaa), since Chrome 62 supports it. Kiosk webviews
like the Shelly Wall Display get the legacy build but can't parse that,
so var(--divider-color) borders on cards, toggles and buttons fell back
to currentColor and showed as bright outlines, the same symptom as
#52986. Always compile hex alpha colors to rgba() in legacy builds, for
both css`` templates and imported stylesheets. Modern builds are
unchanged.
Also drop the loader's redundant /* global */ header, which ESLint now
rejects because module and require are already built-in globals in
.cjs files.
Fixes#55699
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eGHbhPo6Q2xNuKcJen
* Also keep rgba() colors in the legacy service worker build
The template loader runs with the legacy-sw browserslist env for the
service worker layer, which an exact match on legacy missed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eGHbhPo6Q2xNuKcJen
---------
Co-authored-by: Claude <[email protected]>
* Fix grouped data tables stuttering when scrolling in Safari
Group header actions are rendered by a callback instead of a slot per group
header. The virtualizer adds and removes header rows while scrolling, and
WebKit is slow to add and remove slots.
Fixes#55636
* Keep group header actions when the data or the pinned group changes
Group header rows are keyed by their group, so an open category menu stays open when the data refreshes. The sticky header is keyed by the pinned group, so its actions don't act on the next group's category.
* Keep group header keys apart from row keys
A group named like a row's id gave the header and the row the same virtualizer key. Prefix the keys so they can't collide.
* Don't call the group header actions slotted in the styles
* Add individual devices to gas in energy dashboard
* Fix copilot issues
* Fix conflicts
* Fix issues
* Fix issues
* Fix more issues
* Centralize gas and water dialogs and sankey cards
* Merge conflicts in energy-overview-view-strategy
* Merge conflicts
* Merge conflicts
* Add name and description
* Fix issues
* Don't show via device as area in devices table
The Area and Floor columns fell back to the via device's area or name
when a device had no area. For protocol integrations like ZHA this put
the coordinator's name in the Area column of every unassigned end
device. Only use the device's own area or the one inherited from its
parent device. The device picker keeps the via device hint.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eGXydVGvZF1ETnrXih
* Add 'connected via' translation and update device dashboard to display via device information
* remove comment
---------
Co-authored-by: Claude <[email protected]>
* Choose the area of a helper that has no device
Storage helpers get an Area field in their create form. Config flow
helpers get an area picker on the success step when any of their
entities has no device; the area is set on all of them. The redirect
after creating then uses the entity ID as regenerated for the area.
* Count the area as an unsaved change in the helper dialog
* Disable the helper area picker while saving
* Open the new helper after creating it
From the helpers page, a new helper now opens its device page when its
entities belong to one device, or its more-info dialog otherwise.
* Open the right entity after creating a helper
Look up the storage helper's entity by its unique ID, because its entity
ID can differ from the helper ID. Start the config entry lookup when the
success step shows and skip the redirect if the dialog closed meanwhile.
* Ignore the helper lookup after the dialog closes or reopens
* Ignore a helper created after its dialog closed or reopened
* Keep dialogs while navigating
* Apply suggestions
* Keep navigate async when keeping dialogs
Skipping the await committed the navigation synchronously, so a navigate()
called right after it saw the committed count change and was dropped as
stale.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Give the raw Supervisor client error some context when loading the app
info fails, show a dedicated message when a non-admin opens an
admin-only app, and include the underlying error when creating the
ingress session fails.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Add an embedded mode to hui-root that leaves the page's URL alone
* Add a dashboard component to the demo embed
* Keep embedded dashboards' back navigation, height and sidebar tabs inside the embed
* Follow anchors, replacements and new configs in embedded dashboards
* Go back past a followed back_path in embedded dashboards
* Isolate embedded view containers so view backgrounds show
* Match decoded and aliased views and skip empty embedded dashboards
* Read the sidebar tab once sections views have their dashboard
* Declare the navigate events in HTMLElementEventMap
* Skip the Lovelace info fetch and its mock in embedded dashboards
* Add a view component to the demo embed
* Show only the latest generated dashboard in the demo embed
* Stop stale and repeated strategy results in embedded views
* Draw view themes and backgrounds in embedded views
* Share embed provider lookup and theme in a base element
* Add devices to the demo embed provider
* Add a section component to the demo embed
* Draw section backgrounds and accept more section configs in the demo embed
* Filter the device classes by the chosen unit
* Keep unsupported device classes selectable
* Only preselect a required device class and keep the default rows
---------
Co-authored-by: Xyolyp <[email protected]>
* Add device class column and filter to entities table
* Localize device classes and preserve redirect filters
* Fix import conflict after rebase
* Refactor device class filter based on review feedback
* Avoid rebuilding device class options while filter is collapsed
* Address final device class review feedback
* Use shared device class translation key for filter
* Prevent a double Finish click in the config flow success step
* Keep only the double-click test and stub ha-input
---------
Co-authored-by: Xyolyp <[email protected]>
Since the "lovelace" dashboard got a real url_path (#28446), the panel threw
the config preloaded in core.ts away and fetched it a second time on every
page load at / or /lovelace/.
Use the preload for the "lovelace" dashboard and fetch again if it failed.
Only preload the config on /lovelace/, as / opens the default panel, which
is not known yet and is home for new installs.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Migrate the Cast launcher view picker from ha-list
The view picker in the Cast launcher was the last use of the mwc-based
list outside of open pull requests. It is now a single-select
ha-list-selectable.
Views without an icon get the dashboard icon in the start slot, which
mwc never showed because it was put in a slot ha-list-item does not
have. As every row has an icon when any view has one, the hide-icons
attribute is no longer needed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Enhance view selection in HcCast component with accessible header and click handling
* Type Cast view click event target
Co-authored-by: wendevlin <[email protected]>
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
The security page, the maintenance page, the Home summary badges and
the Home overview each rebuilt the same filter functions and ran
findEntities over every state. Add findFilteredEntities, which takes
the states and registries as one object, and a findSecurityEntities
and findMaintenanceEntities wrapper so every consumer resolves a
page's entity set the same way. No behaviour change.
* Label marketplace open issue count as issues and pull requests
The GitHub open issues count includes pull requests. Rename the
translation keys and update the English strings so the label matches
the number shown.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Update marketplace tests for the renamed open issues keys
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
The entity filter matched the full name and the friendly name, so typing a
device name returned entities whose entity column showed no match. It now
matches the entity ID and the name the entity column shows. When the device
column is hidden, it still matches the full name.
Fixes#55451
Co-authored-by: Claude Opus 5.5 <[email protected]>
The "lovelace" panel is cached by the panel resolver, so it should stay
subscribed to config updates while the user is on another page. Since the
urlPath getter returns "lovelace" instead of null, the null check in
disconnectedCallback always unsubscribed it, and nothing resubscribed on
reconnect. Changes saved from another page, like adding a device section
from the device page, only showed after a browser refresh.
Also reset the refetch flag once used, so returning to the dashboard
without a change doesn't refetch the config again, and let a pending
refetch take precedence over the locale rebuild, which would otherwise
rebuild from the stale config.
Fixes#55440
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Migrate the new automation dialog and zones list from ha-list
Moves the new automation and script dialog and the zones list from the
mwc-based ha-list and ha-list-item to ha-list-base and
ha-list-item-button, handling clicks instead of request-selected.
- Render the get blueprints link as a list item button with an href
inside the blueprints list
- Keep the zone edit buttons in the row's end slot, as their handlers
already stop the click from reaching the row
- Drop the request-selected handling left in the more info dialog and
the webhook trigger, where nothing fires it anymore
- Remove the now unused request-selected helper
- Point the automation e2e helper at the new list items
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Pass the blueprint path and zone id as data attributes
Both are plain strings, so data attributes avoid untyped ad hoc
properties on the list items and their any casts in the handlers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Drop the unused entityId property from the zone edit button
Nothing reads it: the edit handler only checks noEdit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Drop the redundant display block on the zones list
ha-list-base is already a block element.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hide the home zone edit button on narrow screens
The old list item hid its meta slot for the home zone on narrow
screens, where clicking the row already edits it. The new list item
has no such switch, so leave the button out instead.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Type the list item click handlers with their current target
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude <[email protected]>
* Allow fans with up to 11 speeds to show speed buttons
Keep showing buttons by default up to 6 speeds, and add helpers to
resolve the speed style (buttons or slider) for a fan.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Add a switch between buttons and slider for fan speed in more-info
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Add a style option to the fan speed card feature
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Add fans with more speeds to the gallery
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Use contexts in the fan speed card feature editor
Read the fan state and localize from contexts instead of the full hass
object, so the editor only updates when this fan or the language changes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Address review feedback on fan speed style
- Only show the "too many speeds" info in the feature editor when the
fan has too many speeds for buttons, not for an off/on fan.
- Reuse the numeric input style labels and align the more-info switch
labels with covers.
- Show fractional steps in round-trip test names.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep buttons for off/on fans whatever style is requested
Fans that do not offer a style choice now always resolve to their
default style, so an off/on fan configured with the slider style no
longer gets stuck on a slider with a disabled selector.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep dense fan speed buttons from overflowing on short screens
Give dense vertical speed buttons a minimum height based on the number
of segments, so they no longer overflow into the mode switch when the
viewport is short.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Remove the fan speed style switch from more-info
Keep this change to the card feature, as asked in review. The more-info
dialog goes back to its previous behavior: buttons up to 6 positions,
a slider above.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Show a row of segments for the fan speed buttons style
The buttons picture in the fan speed feature editor showed the numeric
input stepper. Use a new picture of a segmented row instead.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Fall back to a slider when fan speed buttons do not fit
Measure the fan speed feature width like the favorite features and show
the slider when the buttons would be too narrow for their labels. Off
and 6 speeds still fit as buttons in a half-width card, while a fan with
10 speeds no longer cuts its last label. The editor now explains this
below the style option.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Clarify fan speed feature examples and helper logic
- Explain the button minimum width next to the constants instead of in
the test.
- Read the disabled state from the schema for the editor helper text.
- Describe the default slider and the width fallback in the gallery
headings.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Use a 24px minimum for fan speed buttons
Buttons in card features have no gap between them, so each one must be
at least 24px wide to meet the WCAG 2.2 AA target size. This also fits
two-digit speeds, so a single minimum replaces the previous pair.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Refine tmp fan entity and config in gallery
* Keep the fan speed button minimum width in the card feature
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Give picker section filter chips a descriptive aria-label
Screen readers announced the section chips in quick search and the
target picker only by their visible text (e.g. "Navigate"), which gives
no hint that the button filters the results. Label them as
"Filter: <section>" instead.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eFvrHAAoLcdEeqDAUg
* Fix fallback for section label localization in ha-picker-combo-box
---------
Co-authored-by: Claude <[email protected]>
Inline setup steps in the Copilot setup workflow
Copilot runs copilot-setup-steps.yml in a context that can't resolve
`$/` self-repository actions, so Copilot code review fails with
"Unable to resolve self-reference '$/'". Inline the setup action's
steps so the workflow only uses pinned remote actions; the actions
lockfile entries stay the same.
Claude-Session: https://claude.ai/code/session_018Kv7eHPGHei6YP9qBPGw1D
Co-authored-by: Claude <[email protected]>
* Keep relative README addresses for the Marketplace rewrite
Images and links in a README with a plain relative path, such as `images/logo.png`, were broken on the Marketplace repository page. xss empties every `src` and `href` that does not start with a scheme, `/`, `./`, `../` or `#`, so the path was gone before `rewriteHtmlUrls` could point it at the repository.
`renderMarkdown` takes `allowRelativeUrls`, which `ha-markdown-element` sets when it rewrites the addresses afterwards. Such an address of a link, image or source is kept as a path below the current one, so it can never carry a scheme, and xss checks it like any other address.
* Trim a relative README address before it gets the ./ prefix
xss trims the spaces written around an attribute value, but not encoded ones. A relative path such as ` images/logo.png` therefore got the space inside the path after the ./ prefix, and the image stayed broken. The value is now decoded and trimmed first, as the browser trims the address.
* Decode a relative README address once and keep data links first
The relative address was decoded before `safeAttrValue` decoded it again, so `&#105;mages` was checked and shown as `images` while the browser reads `images`. Like `srcset`, it is now decoded once with `&` for query strings, dropped when entities are left over, and written back escaped, so the browser reads the path that was checked.
Links to data URLs allowed with `allowDataUrl` are handled before relative addresses again, so they are no longer turned into paths.
* Escape a kept relative README address only once
`safeAttrValue` returns the value escaped already, so escaping its result again turned a quote in a path into `&quot;`, and the browser requested another file. It is now only the check, and the decoded path is escaped once, like `srcset`.
The comments of the change are cut down to the one above the new function, as the code around has few.
* Drop relative README addresses with a scheme and reuse URL_ATTRIBUTES
A relative path never has a scheme, so an address xss empties that still has one after decoding (HTTPS://..., j:alert(1) from javascript:) or is empty is dropped instead of being kept below ./, where it would request a path in the repository that does not exist. The worker imports URL_ATTRIBUTES from rewrite-html-urls, so the attributes it keeps and the ones the rewrite touches cannot drift apart.
* Add option to combine energy sources of the same type
Add a "Combine sources" toggle to the energy period selector menu and a
combine_sources option to the energy cards that list sources separately.
The Summary view always combines sources.
* Make combine_sources a per-card option with each card's current default
Cards render from their own combine_sources option instead of a flag on the
energy data. The power sources graph and the energy and power Sankeys default
to combined and gain a separate mode. The energy dashboard toggle now sets the
option on its cards through the strategies.
Keep stacked series and Sankey columns in the same order when switching.
* Keep usage graph series stable across modes instead of in ha-chart-base
Combined mode puts the sum on the first source's series and keeps the other
sources and the fallback series as empty series, so the series ids stay the
same and ECharts keeps the stack order. Revert the ha-chart-base guard.
* Only offer Combine sources on the energy panel
* Keep the legend entry of a source with only comparison data
* Keep the combine_sources setting on the energy collection
The collection holds the setting, unset by default and saved per collection
only when chosen, and re-publishes the data with it. Cards fall back to it
before their own default. A date picker shows the toggle only with
show_combine_sources, which the Electricity, Gas and Water views enable along
with an initial off value. The setting only applies while a source type is
configured twice.
* Only combine or split source types with two or more sources
A type with a single source keeps each card's current look in both modes.
The Electricity, Gas and Water views only show the toggle when their own
source types have duplicates.
* Keep the solar graph's forecasts from older requests or missing data
* Lock workflow actions with an actions.lock file
* Run the actions lockfile check on every pull request
* Regenerate the actions lockfile after the rebase
* Pin Renovate's gh-actions-lock to the version CI verifies with
* Add virtual parents for offline, parentless, and green power devices
* Tighter pull for virtual groups
* Merge offline with no parent
* Add hidden nodes to better space disconnected clusters
* Ignore neighbor table contributions from offline devices
* Make offline device edges 1.5x weaker
* Differentiate router color from end device color
* Switch `no parent` to `unknown parent`
* Adjust sizing
* Shrink the root symbol on mobile
* Fix tests
* Resolve external statistics in the History panel
The History panel plots external statistics (`<domain>:<object_id>`), for example when the statistics graph card links to it, but treated them as entities everywhere else.
- The sources picker looks up an external statistic in the statistics metadata and shows its name instead of "Entity not found".
- Statistics without an entity take name and unit from their metadata, so the legend and tooltip no longer show the prettified ID without a unit.
- External statistic IDs are no longer sent to `history/stream`. Core rejects the whole subscription for an ID that is not an entity ID, which dropped the state history of every other picked entity.
* Use statistic metadata only for external statistics
The statistics of a removed entity got the unit from their metadata, but no device class. Its recent state history has the same unit and a device class, so both ended up in separate charts and the overlap was no longer trimmed. Other statistics keep a blank unit again and merge into the history line of their entity. The metadata is only fetched for external statistics.
* Reset the zoom when only external statistics remain
Removing the last entity from a zoomed view returned before the zoom was reset. The chart was rebuilt at full range, but the zoom slider kept the previous range.
* Reset the chart zoom when only external statistics are shown
Charts of external statistics stay mounted when the date range changes, because there is no state history to load. Resetting only the zoom range left the chart zoomed while the reset button was disabled. The zoom is now reset on the charts as well, and the normal path is unchanged again.
* Keep the statistics when the metadata lookup fails
A failed metadata lookup rejected the whole request, so the fetched statistics were dropped and the panel could stay on the loading spinner. External statistics are now shown under their ID instead.
* End the loading when the statistics request fails
With only external statistics selected there is no state history, so a failed statistics request left the panel on the loading spinner. A failed request now sets an empty result, guarded by the fetch ID so that an older request cannot overwrite newer data.
* Show external statistics like the statistic picker and inline the stream filter
The sources picker row of an external statistic gets the chart line icon and the source integration as context, as in ha-statistic-picker, instead of the default entity icon. The filter for the history stream has a single caller, so it is inlined in the History panel and its export and test are dropped. The comment on the blank unit of other statistics moves to the isExternalStatistic check it describes.
* Clear the previous statistics before fetching new ones in the History panel
Switching from one external statistic to another kept the chart of the previous one on screen and in the download until the new request was done, as no state history shows the loading then. The statistics are now cleared before the request, so the panel shows its loading state instead.
* Wrap supporting text of entity settings rows
Long explanations such as the visibility description were truncated
with an ellipsis, especially in languages with longer translations.
Fixes#55584
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018Kv7eGRG4gEJgUauHeEZcB
* Update supporting-text styles for row and list items
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* Keep chart tooltips inside the window
ECharts only fits tooltips into the chart, so a tooltip taller than the
chart opened above it and ran off the top of the window. Charts without
their own tooltip position now move it into the window, below the
cursor first.
The energy devices detail tooltip also lists the 10 largest devices,
largest first, and folds the rest into one "N other devices" row.
* Try both sides of the cursor and keep confined tooltips in the chart
When the window fit has to move a tooltip, try the other side of the
cursor horizontally too before clamping, so it does not cover the
hovered point. A confined tooltip now only moves within the visible part
of the chart and keeps its chart-confined spot otherwise, so it is not
clipped by containers that hide overflow.
* Keep confined tooltips on screen and skip hidden rows when folding
When the visible part of a confined chart is too small for the tooltip,
move the tooltip only as far as the window needs instead of leaving it
off screen.
Devices whose value the tooltip shows as 0 are no longer folded into the
"other devices" row, so that row never appears without the larger
devices it refers to.
* Add a level filter to the logs page
* Pass the logs level filter through My links
* Share the supported log levels and the log entry filtering
* Expand one logs filter at a time and count from the other filters
* Drop detected location details after choosing another place in onboarding
* Reset the elevation when searching an address in onboarding
* Keep the chosen country when the browser time zone is unknown in onboarding
* Add optional count badges to the integration filter
* Show log level counts in the logs integration filter
* Label log count badges and hide them in the raw view
* Show log count badges on the integration filter's supporting line
* Migrate the remaining static lists from ha-list
Moves the auth provider picker, the config flow menu step, the
onboarding address search results, the input select options, the
system log card, the Wi-Fi access points, the network storage mounts
and the adjust sum statistics list from the mwc-based ha-list and
ha-list-item to ha-list-base, ha-list-selectable, ha-list-item-button,
ha-list-item-option and ha-list-item-base.
- Make the onboarding address results and the Wi-Fi access points
single-select lists, as they were activatable lists before
- Copy the picked access point into a new Wi-Fi configuration instead
of using the access point object itself, which the form then changed
- Let the config flow menu descriptions wrap, as multiline-secondary did
- Keep the list padding, icon colors and mount icon column of the
previous lists
- Remove unused element imports in the touched files
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Add aria-label attributes to ha-list-base components for improved accessibility
* Refactor onboarding location component to use ha-list and ha-list-item for improved structure and interactivity
* Add reload label to network mounts and update translations for storage
* Refactor storage panel to use ha-list-item-base and ha-list-item-button for improved UI consistency
---------
Co-authored-by: Claude <[email protected]>
Give the to-do panel list pane an accessible name
The migrated ha-list-base pane had no label, so screen readers announced an unnamed list. Reuse the existing "To-do lists" panel title, matching how the calendar panel labels its pane list.
The data URL exception for links wrote the href back unescaped, so a quote
in the value could add attributes. It also added `download` to the cached
whitelist, which then allowed it in all later markdown.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Link the integration page to the integration's settings panel
The Connectivity settings panels, like Modbus and Infrared, are not
reachable from the integration page unless the integration has a config
entry. A user that opens the integration page looks for these settings.
The integration page now shows a button that opens the panel of the
integration when the integration has no entries. With entries, each
entry row already links to the panel. The button uses the panel name
from the Connectivity page. LoRaWAN, Modbus, Radio frequency, and USB
(Serial) are added to the map of integrations with a panel.
An integration with a panel and no config flow is set up in its panel.
For such an integration, the button is the primary action, and the page
does not show the YAML texts, the empty entries section, or the
"Add entry" button.
The demo Infrared and Radio frequency manifests now match core, so
these pages show it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
* Always show the settings panel button
An entry row links to the panel only while the entry is loaded. When
all entries are disabled, not loaded, or still setting up, the page had
no link to the panel. The integration page now always shows the
settings panel button.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
---------
Co-authored-by: Claude <[email protected]>
* Use the dark brand icon in state badges when dark mode is on
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Only follow dark mode from the UI context in state badges
Subscribing to the whole UI context made every state badge run an update
whenever an unrelated value such as the panel URL or the docked sidebar
changed. Consume only `themes.darkMode` through `@transform`, like
ha-media-browser-thumbnail does, so badges update only when dark mode
itself changes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
The AI settings show how to connect to the MCP server and the URL of
each of its APIs. The MCP client and MCP server integration pages now
have an "AI settings" button that opens the MCP card on that page. The
button is the primary action when the page has no "Add entry" button.
The AI settings page scrolls to the section named in the URL hash, like
the backup settings page, and clears the hash after. In the demo, the
hash is the route of the page, so the button links to the page without
a section and the page keeps a hash that names no section.
Claude-Session: https://claude.ai/code/session_01EzDS5Gc7EVw1NsLpEB7yza
Co-authored-by: Claude <[email protected]>
* Seek on slider change in the media control card
A touch drag ends without a click, so the card never seeked after a
drag. Use the slider's change event, which fires when a drag or tap
ends and on arrow keys.
* Remove media control card rendering test
The frontend testing guidance asks for tests of code that computes
something, not rendering tests.
* Align installed apps cards with the search field
The installed apps grid got an 8px margin from the shared apps style
on top of its own 16px padding. The cards sat 24px from the screen
edge while the search field sits at 16px. Reset the margin so the
cards line up with the search field and are wider on mobile.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016677RTobVvbXRTMLYj3N4m
* Limit apps card margin change to mobile screens
Remove the side margin of the installed apps grid only below 600px.
Wider screens keep the 24px edge spacing, which matches the
integrations page.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016677RTobVvbXRTMLYj3N4m
* Match installed apps grid spacing to the integrations dashboard
Use the same container spacing as the integrations dashboard: 16px
from the side edges and 24px below the toolbar on all screen sizes.
The margin from the shared apps style is reset, so it no longer adds
to the padding.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016677RTobVvbXRTMLYj3N4m
---------
Co-authored-by: Claude <[email protected]>
* Announce the number of search results in pickers
Screen readers stay on the search field while the list filters, so typing in a picker or the quick search said nothing. A hidden status message now gives the number of matching items, or the not found label when nothing matches.
* Test the picker search results announcement
The status message is never seen, so a regression would go unnoticed. The test checks the count, the not found label, the cleared search, and that section titles are not counted.
* Count only matches and name the search in the picker announcement
The custom value row and the additional items, like the add new area row, were counted as results, so a search that matched nothing said there were results. They are no longer counted. A live region is only read out when its text changes, so a new search with the same count, or a second search that found nothing, said nothing. The message now names the search.
* Add the picker announcement messages to the gallery demo
The picker gallery's localizer only knew the older keys and returned the key for anything else, so searching a demo announced "ui.components.combo-box.result_count" instead of the count and the search. It now has both new messages, copied from en.json, and formats them with their values, so the demos announce "1 result for ‘desk’", "2 results for ‘kitchen’" and "No results for ‘zzz’".
* Move the search results message into a helper and test it there
The frontend testing guidance asks for no rendering tests, and the picker test mounted the component and checked its status text. The counting and the message now live in searchResultsStatus, a plain function the picker calls, with a unit test in its place: rows that are not results (section titles, placeholders, rows like "Add custom item") are not counted, a not found label that takes the search is used, and the message names the search so a new search is read out. The announcements are unchanged.
* Wait for typing to pause before announcing, and don't count Ask Assist
The picker announcement changed on every key press, so a screen reader started a new announcement for each character, over its own echo of the typed characters. The message now updates 500 ms after the rows stop changing, using the existing debounce helper, and is no longer recounted on every render.
The quick bar adds an "Ask Assist" row to every search through getItems, so it was counted: searching for something that matched nothing announced "1 result". The picker takes a new isSearchResult callback for rows like this, and the quick bar uses it to leave the assist row out. It isn't skipped in _isOption, because that would also stop the row being selectable. The gallery page documents both.
* Clear the picker announcement as soon as the rows change
With the pause, the last message stayed in the status region for half a second after the rows had changed, so it could describe the previous search. Going back to a search that had already been announced also wrote the same text again, so nothing was read out. The message is now cleared as soon as the rows change, at once when the search is emptied, and when the picker is removed. Clearing a status region isn't read out, and the next message is a change, so it is.
Since #54801 the resolver creates a stacking context (isolation: isolate) so
its fixed ::before background sits behind the panel. The resolver is rendered
conditionally, once the startup data is available, and isolating it can
intermittently leave the Android WebView accessibility tree (Chromium
109-124) with an empty panel subtree while the page paints normally. UI
automation then never sees the dashboard; the companion app nightly E2E has
hit this on the legacy build (API 32/33/35) since the change landed.
Move the isolation to home-assistant-main's host, which exists before the
resolver is rendered. The pseudo-element and the Lovelace view background
both stay at z-index -1 in that context, in the same order as before, so the
themed background behaves exactly as #54801 intended. Measured with Maestro
on a Chrome 109 emulator: 0 stale trees in 62 cold loads, against 11 in 100
with the isolation on the resolver.
Each legacy entry bundle carries its own copy of intl-polyfill.ts, so the
module-level guard only stopped re-runs within one bundle. With the bundles
loading in parallel, the second bundle could probe Intl.PluralRules after the
first had installed the polyfill but before its locale data chunk arrived. The
FormatJS should-polyfill probe calls select(), which throws on a data-less
polyfill, rejecting the top-level await so the entry never evaluated. On the
companion app this surfaces as ExternalBusTimeout on old WebViews.
Share one promise per page on globalThis so every bundle waits for the same
run, and import the PluralRules polyfill and its English data from one module
so Intl.PluralRules is never installed without data.
* Migrate the config device, area and integration lists from ha-list
Moves the device child, via and linked devices cards, the device
entities card, the area page, the Matter fabrics and ping dialogs, the
Thread border routers, the Z-Wave remove node dialog and the Z-Wave
config entry picker from the mwc-based ha-list and ha-list-item to
ha-list-base, ha-list-nav, ha-list-item-button and ha-list-item-base.
- Render links as ha-list-item-button with an href instead of an anchor
around a list item, so the rows take part in keyboard navigation
- Render automations and scenes that are not editable as
ha-list-item-base with the existing tooltip, as on the device page
- Wrap the area scripts and the Thread border routers in a list, as
the other sections already were
- Only render the remove fabric button where mwc showed it, and give it
a label
- Keep the list padding and row alignment of the previous lists
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Add aria labels and adjust padding for ha-list components in device and integration dialogs
* Refactor aria labels for related lists in ha-config-area-page and update translations
---------
Co-authored-by: Claude <[email protected]>
* Migrate the remaining selection lists from ha-list to ha-list-selectable
Moves the media management dialog, the calendar panel pane, the expose
entities dialog, the user visibility condition and the select view dialog
from the mwc-based ha-list, ha-check-list-item and ha-radio-list-item to
ha-list-selectable and ha-list-item-option. The read-only ZHA endpoint
list now uses ha-list-base, as its rows already were ha-list-item-base.
- Use ha-list-selectable-virtualized for the expose entities dialog,
replacing the custom click and keyboard handling around lit-virtualizer
- Render the calendar pane as its own list instead of reusing the
dropdown items, sharing the selection logic with the dropdown
- Make the select view dialog a single-select list and keep the icon
column aligned for views without an icon
- Drop the media management workaround for spurious mwc select events
- Render the create calendar row as ha-list-item-button
- Remove unused element imports in the touched files
After this, ha-check-list-item is only used by the todo list card and
ha-radio-list-item is unused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ln7qMagr2YDdssKkaBiqf5
* Refactor ha-list components for improved focusability handling and update list items logic
* Enhance focus handling in ha-list-base and update tests for disabled items
* use helper
---------
Co-authored-by: Claude <[email protected]>
* Show blueprint usage count as text on narrow screens
* Show the blueprint usage count before the path on narrow screens
* Name the blueprint usage column and skip it for broken blueprints
Problem binary sensors were added to the maintenance view using the
battery tile builder, which names every tile after its device. A device
with several problem sensors (overheating, overvoltage, ...) then showed
identical tiles. Problem tiles now use a device plus entity name; the
entity part is dropped automatically when the sensor has no name of its
own, so single-sensor devices still read as just the device name.
Battery tiles keep the device-only name.
Fixeshome-assistant/frontend#55413
* Remember logs page search, integrations and raw view
* Keep stored logs choices from links and loading apps
* Keep logs choices when closing dialogs and while apps load
* Restore stored logs choices when linked to the page again
* Don't hide stop action on playing media players
* Show stop as a secondary button when play/pause exists
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Add media player entity for "Playing The Music" and update media control card
* Implement logic to remove secondary stop control when play or pause is available in media player
* Test removing the secondary stop control
Runs real computeMediaControls output through removeSecondaryStopControl,
like its callers do, to protect when stop is removed and when it has to
stay.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Wendelin <[email protected]>
description:Home Assistant frontend component patterns. Use when implementing or reviewing dialogs, ha-form, ha-alert, keyboard shortcuts, tooltips, panels, Lovelace cards, or ha-button usage.
description:Home Assistant frontend component patterns. Use when implementing or reviewing dialogs, ha-form, ha-alert, loading states, keyboard shortcuts, tooltips, panels, Lovelace cards, or ha-button usage.
---
# HA Frontend Components
@@ -91,6 +91,36 @@ html`
`;
```
## Loading States
Pick the indicator by what is loading, following the [Loading pattern](https://contributors.home-assistant.io/design/patterns/loading/):
- Use a skeleton from `src/components/skeleton/` (`ha-skeleton`, `ha-skeleton-text`, `ha-skeleton-icon`) when content loads into a layout you already know, such as table rows, tile text, or a log. It holds the layout, so nothing jumps when the content arrives.
- Use `ha-spinner` only when a whole area loads and its shape is unknown.
- Use `ha-button` with `loading`, or `ha-progress-button`, for an action started from a button. Don't put a separate spinner next to it.
Wrap the indicator in `ha-fade-in` from `src/components/animation/ha-fade-in.ts`:
- Fade a skeleton in straight away over about 300ms (`.duration=${300}`), as the data table does. It stands in for the content, so a delay would leave an empty gap.
- Delay a spinner or progress bar, usually by `.delay=${500}`, so a load that finishes within that time never flashes it. Some slower areas, such as backups and updates, use `${1000}`.
- Don't fade in the loaded content itself.
Give a skeleton group the `progressbar` role and a translated label, as `ha-spinner` has, rather than visible "Loading" text. A loading state always ends in the content, an empty state, or an error.
Use `ShortcutManager` from `src/common/keyboard/shortcuts.ts` for keyboard shortcuts. It blocks shortcuts in input fields, can prevent shortcuts during text selection, and supports character and KeyCode shortcuts for non-latin keyboards. See `src/state/quick-bar-mixin.ts` for global shortcut examples.
@@ -10,6 +10,7 @@ Use this skill when editing CSS, layout, visual hierarchy, theme integration, re
## Theme And Layout Basics
- Use Home Assistant CSS custom properties instead of hardcoded colors.
- CSS in the static HTML templates under `src/html/` must give custom properties a fallback value (for example `var(--ha-space-4, 16px)`), because the global tokens only exist once the JS-appended global stylesheet from `append-ha-style` has loaded.
- Use `--ha-space-*` spacing tokens instead of hardcoded spacing where possible.
- Keep components mobile-first and enhance for desktop.
- Keep layouts RTL-safe. Prefer logical properties when they fit.
@@ -40,7 +40,7 @@ Never run `tsc` or `pnpm lint:types` with file arguments. When `tsc` receives fi
Detailed guidance lives in `.agents/skills/<name>/SKILL.md`. Load every matching skill before detailed implementation or review. For reviews, load `ha-frontend-review` alongside all companions that apply to the changed code or behavior:
-`ha-frontend-contexts`: Lit contexts, `hass` migration, and rerender-sensitive state access.
-`ha-frontend-components`: dialogs, forms, alerts, shortcuts, tooltips, panels, and Lovelace cards.
@@ -28,10 +28,18 @@ AI can be a helpful tool for writing code and documentation. However, due to the
All contributions must be reviewed and understood by the contributor before submission. You should be able to explain every change in a pull request you submit. Pull requests that appear to be unreviewed AI output will be closed without review.
## Design contributions
AI can be a helpful tool to explore ideas and build mockups and prototypes. But AI tends to give the most common answer, not the one that fits Home Assistant and its users. So we require a human who brings the point of view and owns the design decisions.
You should be able to explain the problem your design solves and why you made your choices. If a mockup or prototype was mostly generated with AI, say so when you share it. Check your work against the [design guidelines](https://contributors.home-assistant.io/design/), as AI tools often make up components, colors, or spacing that don't exist in Home Assistant. Design proposals that look like unreviewed AI output may be closed or hidden.
## Our use of AI
Some of our projects use AI tools to assist with code reviews, issue triaging, reporting, and other project management tasks. These tools may leave comments on pull requests or issues. As with any automated tooling, these comments are not always correct.
We also use AI to help keep the design system, the Figma kit, and the code in sync. The design decisions behind them are made by people.
If an AI tool leaves a comment on your contribution, treat it as you would any other review comment. If you believe it is incorrect, say so; a brief explanation is sufficient. Maintainers always have the final say. If in doubt, ask a maintainer.
content:`With Home Assistant you can easily create interfaces (just like this one) which can be shown on Chromecast devices connected to TVs or Google Assistant devices with a screen.${
content:`With Home Assistant you can easily create interfaces (just like this one) which can be shown on Chromecast devices connected to TVs or Google Home devices with a screen.${
touchSupported
?"\n\nYou are able to interact with this demo using the touch screen."
:"\n\nOn a Google Nest Hub you are able to interact with Home Assistant Cast via the touch screen."
## Open source home automation that puts local control and privacy first
Home Assistant is a free and open-source software for home automation that is designed to be the central control system for smart home devices with a focus on local control and privacy. It can be accessed via a web-based user interface, via apps for Android and iOS, or using voice commands via a supported virtual assistant like Google Assistant and Amazon Alexa.
Home Assistant is a free and open-source software for home automation that is designed to be the central control system for smart home devices with a focus on local control and privacy. It can be accessed via a web-based user interface, via apps for Android and iOS, or using voice commands via a supported virtual assistant like Google Home and Amazon Alexa.
IoT devices and services are supported by modular support for controlling proprietary ecosystems if they provide public access via an Open API for third-party integrations and protocols like Bluetooth, MQTT, Zigbee, and Z-Wave, After the Home Assistant software application is installed as a computer appliance it will act as a central control system for home automation. Information from all entities it sees can be used and controlled from within scripts trigger automations using scheduling and "blueprint" subroutines, e.g. for controlling lighting, climate, entertainment systems, and appliances.
@@ -36,6 +36,6 @@ Durability for the Open Home means that devices are designed and built to keep w
The project was started as a Python application by Paulus Schoutsen in September 2013 and first published publicly on GitHub in November 2013. In July 2017, a managed operating system called Hass.io was initially introduced to make it easier use to use Home Assistant on single-board computers like the Raspberry Pi series. Its bundled "supervisor" management system allowed users to manage, backup, and update the local installation and introduced the option to extend the functionality of the software with add-ons.
An optional subscription service was introduced in December 2017 for $5/month to solve the complexities associated with secured remote access, as well as linking to Amazon Alexa and Google Assistant. Nabu Casa, Inc. was formed in September 2018 to take over the subscription service. The company's funding is based solely on revenue from the subscription service. It is used to finance the project's infrastructure and to pay for full-time employees contributing to the project.
An optional subscription service was introduced in December 2017 for $5/month to solve the complexities associated with secured remote access, as well as linking to Amazon Alexa and Google Home. Nabu Casa, Inc. was formed in September 2018 to take over the subscription service. The company's funding is based solely on revenue from the subscription service. It is used to finance the project's infrastructure and to pay for full-time employees contributing to the project.
In January 2020, branding was adjusted to make it easier to refer to different parts of the project. The main piece of software was renamed to Home Assistant Core, while the full suite of software with the embedded operating system and bundled "supervisor" management system was renamed to Home Assistant.
subtitle: State history as timelines and line charts.
---
`<state-history-charts>` renders the state history of entities: a timeline for entities with text states, and a line chart per unit for numeric ones. It is used by the history panel, the history graph card and the more-info history. The data below is generated, so the charts work without a backend.
subtitle: Long-term statistics as a bar or line chart.
---
`<statistics-chart>` renders long-term statistics from the recorder. It is used by the statistics graph card, the more-info history and the statistics developer tools. The data below is generated, so the charts work without a backend.
Loaded 100 of 593 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.