Give the security page a hidden_entities list like the other pages and replace its edit dialog with the inline edit mode. In edit mode every tile, favorites included, carries an eye, a star and, for alert-capable domains, a bell that cycles through none, warning and alert. Each tap saves at once. The Home dashboard summary badge, overview check and area views take the same hidden list.
Hidden, favorite and alert flags stay independent, so a hidden entity can still be a favorite or raise alerts, and the Home security summary stays while alerts are configured.
In edit mode the sidebar lists every configured alert, active or not, in its configured color, so a saved alert can always be changed or cleared there, including one whose entity no longer matches the page or was deleted. These entries pick the level with a three-way control instead of the cycling bell, so clearing is an explicit choice and an entry does not vanish on the way from alert back to warning. Changing a level keeps the alert in its place in the list. Favorites and alert entries show regardless of the hidden list, so they carry the star and the alert control but no eye. A deleted entity shows its ID in place of its card, so two stale entries stay distinguishable.
Toggling the eye only flips the wrapper's own flag and saves, like on the other pages. A star or bell tap moves the entity between the grid and the sidebar lists, so those regenerate the view, and the wrapper card's focus restoration covers the star and the alert controls and tells the grid tile and the sidebar entry of one entity apart, so the recreated wrapper focuses the control that fired. When a tap removes the entry itself, focus moves to the same control on the next entry in that list. When the list runs out, the last favorite hands focus to the first tile of the section that takes its place at the top of the page, and the last alert entry to the entity's own page tile if it has one; the strategy puts that fallback on the wrapper. When there is no fallback, or the recreated tile cannot take focus because the narrow layout shows the Activity tab, the card tells the panel and the panel focuses its exit-edit-mode button instead, so keyboard focus never drops to the page. Entering edit mode drops any request left over from an entry without either. ha-control-select gains a focus() that lands on its selected option for this. A failed save reloads the configuration and forces a rebuild so the wrappers show the stored state again.
The dialog, its alerts editor, the entity filter helper and the dialog test go away. Strategy tests pin down that a hidden entity keeps its favorite and alert entries, that stale favorites and alerts only show in edit mode, and the shape of the edit-mode wrappers.
Build the visible area sensor map a single time with the hidden list applied, so the page and the Home badge share one rule and the separate showAreaSensor check goes away. Label the temperature and humidity tiles from the area slot they fill instead of reading device_class back off the state, which produced an empty name for sensors set through the API without a device class. Drop the trend-graph branch for non-area entities, which the climate filters never admit.
Give the climate page the same hidden_entities system data, config
loading and inline visibility edit mode the maintenance page has. The
climate resolver also covers the area temperature and humidity
sensors, which the page adds outside the entity filters, so they can
be hidden too and the Home climate badge skips them.
* 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.
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 485 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.