{"id":20961669,"url":"https://github.com/elchininet/home-assistant-query-selector","last_synced_at":"2026-04-05T16:02:35.509Z","repository":{"id":207842526,"uuid":"719325660","full_name":"elchininet/home-assistant-query-selector","owner":"elchininet","description":"Easily query Home Assistant DOM elements in an asynchronous way","archived":false,"fork":false,"pushed_at":"2026-03-30T12:27:22.000Z","size":2678,"stargazers_count":10,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-30T14:33:13.663Z","etag":null,"topics":["dom","dom-query","home-assistant","home-assistant-custom","home-assistant-frontend","javascript","javascript-library","library","promises","query-selector","typecript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elchininet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"elchininet"}},"created_at":"2023-11-15T23:39:41.000Z","updated_at":"2026-03-22T21:13:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"3ddb91a4-e837-4d08-90d9-2bd39ed909c2","html_url":"https://github.com/elchininet/home-assistant-query-selector","commit_stats":null,"previous_names":["elchininet/home-assistant-query-selector"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/elchininet/home-assistant-query-selector","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elchininet%2Fhome-assistant-query-selector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elchininet%2Fhome-assistant-query-selector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elchininet%2Fhome-assistant-query-selector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elchininet%2Fhome-assistant-query-selector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elchininet","download_url":"https://codeload.github.com/elchininet/home-assistant-query-selector/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elchininet%2Fhome-assistant-query-selector/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31441057,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T15:22:31.103Z","status":"ssl_error","status_checked_at":"2026-04-05T15:22:00.205Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dom","dom-query","home-assistant","home-assistant-custom","home-assistant-frontend","javascript","javascript-library","library","promises","query-selector","typecript"],"created_at":"2024-11-19T02:15:14.766Z","updated_at":"2026-04-05T16:02:35.496Z","avatar_url":"https://github.com/elchininet.png","language":"TypeScript","funding_links":["https://github.com/sponsors/elchininet"],"categories":[],"sub_categories":[],"readme":"# home-assistant-query-selector (HAQuerySelector)\n\nEasily query [Home Assistant] DOM elements in an asynchronous way.\n\n[![Deployment Status](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/deploy.yaml/badge.svg)](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/deploy.yaml)\n[![Tests](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/tests.yaml/badge.svg)](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/tests.yaml)\n[![Coverage Status](https://coveralls.io/repos/github/elchininet/home-assistant-query-selector/badge.svg?branch=master)](https://coveralls.io/github/elchininet/home-assistant-query-selector?branch=master)\n[![npm version](https://badge.fury.io/js/home-assistant-query-selector.svg)](https://badge.fury.io/js/home-assistant-query-selector)\n\n[![Home Assistant Beta Nightly Tests](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/ha-beta-tests.yaml/badge.svg)](https://github.com/elchininet/home-assistant-query-selector/actions/workflows/ha-beta-tests.yaml)\n\n## Introduction\n\nWhen one wants to build a `Home Assistant` front-end plugin, like many of the ones published in [HACS], most of the time first thing to do is dealing with query-selection of `DOM` elements. This is a tedius task, because `Home Assistant` elements are custom [WebComponents], so when the `DOM` loads, most of those elements don‘t exist, they will be created in an asynchronous way and not all of them at the same time. On top of that, as they are `WebComponents`, many of them have their own `DOM` subtree under a [ShadowDOM], something that makes the task of query-selecting elements double tedious.\n\nAs I develop and maintain several `Home Assistant` plugins that change the style of the `DOM` elements, I find myself repeating the same piece of logic over and over to select the elements, and when the `Home Asistant` front-end code changes ([something that occurs more than I would like](https://github.com/NemesisRE/kiosk-mode/issues/27)), I need to go and fix the same in all of them.\n\nThis is from where the idea of `home-assistant-query-selector` comes from. Imagine instantiating a class, and without querying for any element, through promises, just wait for the main `Home Assistant` DOM elements to be created and rendered to be able to access them. That sounds great! doesn‘t it?. In that way, the `Home Assistant` plugins that I maintain could be agnostic to the `DOM` tree, and if someting changes with a new version and all the plugins break at the same time, the changes to fix them could be done in a single place, to fix the plugins only a simple update of this library is needed once the patch is released.\n\n### How to detect if something will break with a new Home Assistant version?\n\nThere are exhaustive end-to-end tests in place in this library, when a new version of `Home Assistant` is released, running the end-to-end tests in this repository will ensure that the library still works with the new version, so no need to manually check this.\n\n#### End-to-end tests\n\n![end-to-end tests](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/tests.png)\n\n#### Code coverage\n\n![code-coverage](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/coverage.png)\n\n### Code example\n\nMore details of the API can be consulted in [the API section](#api):\n\n```typescript\nimport { HAQuerySelector } from 'home-assistant-query-selector';\n\nconst instance = new HAQuerySelector();\n\n// This event will be triggered when the listen method is called\n// You can also use the enum value HAQuerySelectorEvent.ON_LISTEN\ninstance.addEventListener('onListen', ({ detail }) =\u003e {\n\n    const { HOME_ASSISTANT, HOME_ASSISTANT_MAIN, HA_SIDEBAR } = detail;\n\n    // Querying the ha-sidebar element from the home-assistant element\n    HOME_ASSISTANT.selector.$.query('home-assistant-main').$.query('ha-sidebar').element\n        .then((sidebar) =\u003e {\n            // sidebar === ha-sidebar element\n        });\n\n    // Deep-querying the sidebar element\n    HOME_ASSISTANT.selector.deepQuery('ha-sidebar').element\n        .then((sidebar) =\u003e {\n            // sidebar === ha-sidebar element\n        });\n\n    // When the sidebar is available in the DOM\n    HA_SIDEBAR.element\n        then((sidebar) =\u003e {\n            // Do whatever we want with the sidebar\n        });\n});\n\n// This event will be triggered when any panel loads\n// You can also use the enum value HAQuerySelectorEvent.ON_PANEL_LOAD\ninstance.addEventListener('onPanelLoad', ({ detail }) =\u003e {\n\n    const { PARTIAL_PANEL_RESOLVER } = detail;\n\n    // When the partial panel resolver is available in the DOM\n    PARTIAL_PANEL_RESOLVER.element\n        .then((partialPanelResolver) =\u003e {\n            // Do whatever we want with the partial panel resolver\n        });\n\n});\n\n// This event will be triggered every time a lovelace dashboard loads\n// You can also use the enum value HAQuerySelectorEvent.ON_LOVELACE_PANEL_LOAD\ninstance.addEventListener('onLovelacePanelLoad', ({ detail }) =\u003e {\n\n    const { HEADER, HA_PANEL_LOVELACE } = detail;\n\n    // When the header is available in the DOM\n    HEADER.element\n        .then((header) =\u003e {\n            // Do whatever we want with the header\n        });    \n\n    // Querying all the ha-icon-button elements inside the .action-items in the header\n    HEADER.selector.query('.action-items ha-icon-button').all\n        .then((buttons) =\u003e {\n            // buttons === Search, Assist, and Open dashboard menu elements (top-right header buttons)\n        });\n\n    // Querying the hui-root shadowRoot\n    HA_PANEL_LOVELACE.selector.$.query('hui-root').$.element\n        .then((shadowRoot) =\u003e {\n            // shadowRoot === hui-root‘s shadowRoot\n        });\n\n});\n\n// This event will be triggered every time a more-info dialog is open\n// You can also use the enum value HAQuerySelectorEvent.ON_MORE_INFO_DIALOG_OPEN\ninstance.addEventListener('onMoreInfoDialogOpen', ({ detail }) =\u003e {\n\n    // When the ha-more-info-info element is available in the DOM\n    detail.HA_MORE_INFO_DIALOG_INFO.element.then((dialogInfo) =\u003e {\n        // Do whatever we want with the dialogInfo element\n    });\n\n});\n\n// Start to listen\ninstance.listen();\n```\n\n## Installation of the library\n\n#### npm\n\n```bash\nnpm install home-assistant-query-selector\n```\n\n#### yarn\n\n```bash\nyarn add home-assistant-query-selector\n```\n\n#### PNPM\n\n```bash\npnpm add home-assistant-query-selector\n```\n\n## API\n\n### Class instantiation\n\nThe `HAQuerySelector` class can be instantiated sending an optional parameter, this parameter will decide how much time is required to query for each element before giving up.\n\n```typescript\nnew HAQuerySelector([config])\n```\n\n#### config optional parameter\n\n```typescript\n{\n    retries?: number;\n    delay?: number;\n    eventThreshold?: number;\n}\n```\n\n| Parameter      | Optional      | Description                                         |\n| -------------- | ------------- | --------------------------------------------------- |\n| retries        | yes           | How many retries trying to find an element in the DOM tree before giving up (defaults to 100) |\n| delay          | yes           | Delay between each retry trying to find an element in the DOM tree (defaults to 50)           |\n| eventThreshold | yes           | Timestamp threshold to fire an event. If two consecutive events of the same type have a timestamp difference lower than this value, the second event will be ignored (defaults to 450) |\n\n### Public methods\n\n`HAQuerySelector` instances count with a public method. When it is called, this method will trigger the `onListen` and `onPanelLoad` (and `onLovelacePanelLoad` if the panel in which it is invoked is a lovelace panel) events inmediatly and start to watch for changes in the `DOM` to trigger the proper events.\n\n```typescript\ninstance.listen();\n```\n\n### Events\n\nThe `HAQuerySelector` class extends from [EventTarget], so it is possible to add events listeners to it. It will dispatch events that will allow us to access the proper elements in the `DOM`.\n\n#### onListen\n\nThis event is triggered when [the listen method](#public-methods) is called. It is useful if you only want to access the main Home Assistant elements only once.\n\n```typescript\ninstance.addEventListener('onListen', function({detail}) {\n    /* detail:\n    {\n        HOME_ASSISTANT: {...},\n        HOME_ASSISTANT_MAIN: {...},\n        HA_DRAWER: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onListen event elements\n\nThis is the list of the elements available inside the `detail` property of the `onListen` event:\n\n![dom tree](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/dom-tree.png)\n\n| Detail element           | DOM element              |\n| ------------------------ | ------------------------ |\n| `HOME_ASSISTANT`         | `home-assistant`         |\n| `HOME_ASSISTANT_MAIN`    | `home-assistant-main`    |\n| `HA_DRAWER`              | `ha-drawer`              |\n| `HA_SIDEBAR`             | `ha-sidebar`             |\n| `PARTIAL_PANEL_RESOLVER` | `partial-panel-resolver` |\n\nAll the available elements contain an `element` property and the `selector` property:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n#### onPanelLoad\n\nThis event is triggered when [the listen method](#public-methods) is called or when any panel is loaded.\n\n```typescript\ninstance.addEventListener('onPanelLoad', function({detail}) {\n    /* detail:\n    {\n        HOME_ASSISTANT: {...},\n        HOME_ASSISTANT_MAIN: {...},\n        HA_DRAWER: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onPanelLoad event elements\n\nThis is the list of the elements available inside the `detail` property of the `onPanelLoad` event:\n\n![dom tree](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/dom-tree.png)\n\n| Detail element           | DOM element              |\n| ------------------------ | ------------------------ |\n| `HOME_ASSISTANT`         | `home-assistant`         |\n| `HOME_ASSISTANT_MAIN`    | `home-assistant-main`    |\n| `HA_DRAWER`              | `ha-drawer`              |\n| `HA_SIDEBAR`             | `ha-sidebar`             |\n| `PARTIAL_PANEL_RESOLVER` | `partial-panel-resolver` |\n\nAll the available elements contain an `element` property and the `selector` property:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n#### onLovelacePanelLoad\n\nThis event is triggered when [the listen method](#public-methods) is called on a lovelace dashboard or when a lovelace dashboard is loaded.\n\n```typescript\ninstance.addEventListener('onLovelacePanelLoad', function({ detail }) {\n    /* detail:\n    {\n        HOME_ASSISTANT: {...},\n        HOME_ASSISTANT_MAIN: {...},\n        HA_DRAWER: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onLovelacePanelLoad event elements\n\nThis is the list of the elements available inside the `detail` property of the `onLovelacePanelLoad` event:\n\n![dom tree](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/lovelace-dom-tree.png)\n\n| Detail element           | DOM element              |\n| ------------------------ | ------------------------ |\n| `HOME_ASSISTANT`         | `home-assistant`         |\n| `HOME_ASSISTANT_MAIN`    | `home-assistant-main`    |\n| `HA_DRAWER`              | `ha-drawer`              |\n| `HA_SIDEBAR`             | `ha-sidebar`             |\n| `PARTIAL_PANEL_RESOLVER` | `partial-panel-resolver` |\n| `HA_PANEL_LOVELACE`      | `ha-panel-lovelace`      |\n| `HUI_ROOT`               | `hui-root`               |\n| `HEADER`                 | `.header`                |\n| `HUI_VIEW`               | `hui-view`               |\n\nAll the available elements contain an `element` property and the `selector` property:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n#### onMoreInfoDialogOpen\n\nThis event is triggered when a more-info dialog is open or when one returns to the main view of the more-info dialog from the `History` or `Settings` view inside the dialog.\n\n```typescript\ninstance.addEventListener('onMoreInfoDialogOpen', function({detail}) {\n    /* detail:\n    {\n        HA_MORE_INFO_DIALOG: {...},\n        HA_DIALOG: {...},\n        HA_DIALOG_CONTENT: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements inside a more-info dialog. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onMoreInfoDialogOpen event elements\n\nThis is the list of the elements available inside the `detail` property of the `onMoreInfoDialogOpen` event:\n\n![more-info dialog dom tree](./images/more-info-dialog-dom-tree.png)\n\n| Detail element             | DOM element              |\n| -------------------------- | ------------------------ |\n| `HA_MORE_INFO_DIALOG`      | `ha-more-info-dialog`    |\n| `HA_DIALOG`                | `ha-adaptive-dialog`     |\n| `HA_DIALOG_CONTENT`        | `.content`               |\n| `HA_MORE_INFO_DIALOG_INFO` | `ha-more-info-info`      |\n\nAll the available elements contain an `element` property and three methods:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n#### onHistoryAndLogBookDialogOpen\n\nThis event is triggered when the `History` view is opened from the header actions of a more-info dialog.\n\n```typescript\ninstance.addEventListener('onHistoryAndLogBookDialogOpen', function({detail}) {\n    /* detail:\n    {\n        HA_MORE_INFO_DIALOG: {...},\n        HA_DIALOG: {...},\n        HA_DIALOG_CONTENT: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements inside a more-info dialog `History` view. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onHistoryAndLogBookDialogOpen event elements\n\nThis is the list of the elements available inside the `detail` property of the `onHistoryAndLogBookDialogOpen` event:\n\n![more-info dialog dom tree](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/more-info-dialog-history-dom-tree.png)\n\n| Detail element                            | DOM element                        |\n| ----------------------------------------- | ---------------------------------- |\n| `HA_MORE_INFO_DIALOG`                     | `ha-more-info-dialog`              |\n| `HA_DIALOG`                               | `ha-adaptive-dialog`               |\n| `HA_DIALOG_CONTENT`                       | `.content`                         |\n| `HA_DIALOG_MORE_INFO_HISTORY_AND_LOGBOOK` | `ha-more-info-history-and-logbook` |\n\nAll the available elements contain an `element` property and three methods:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n#### onSettingsDialogOpen\n\nThis event is triggered when the `Settings` view is opened from the header actions of a more-info dialog.\n\n```typescript\ninstance.addEventListener('onSettingsDialogOpen', function({detail}) {\n    /* detail:\n    {\n        HA_MORE_INFO_DIALOG: {...},\n        HA_DIALOG: {...},\n        HA_DIALOG_CONTENT: {...},\n        ...\n    }\n    */\n});\n```\n\nThe dispatched event is a [CustomEvent] and its `detail` property is an object containing the main `Home Assistant` `DOM` elements inside a more-info dialog `Settings` view. All the properties and methods included in each element are Promises, so they are async and will be resolved when the element is ready to work with it.\n\n##### onSettingsDialogOpen event elements\n\nThis is the list of the elements available inside the `detail` property of the `onSettingsDialogOpen` event:\n\n![more-info dialog dom tree](https://raw.githubusercontent.com/elchininet/home-assistant-query-selector/master/images/more-info-dialog-settings-dom-tree.png)\n\n| Detail element                 | DOM element             |\n| ------------------------------ | ----------------------- |\n| `HA_MORE_INFO_DIALOG`          | `ha-more-info-dialog`   |\n| `HA_DIALOG`                    | `ha-adaptive-dialog`    |\n| `HA_DIALOG_CONTENT`            | `.content`              |\n| `HA_DIALOG_MORE_INFO_SETTINGS` | `ha-more-info-settings` |\n\nAll the available elements contain an `element` property and three methods:\n\n| Property or method        | Description                                                     |\n| ------------------------- | --------------------------------------------------------------- | \n| `element`                 | Promise that resolves in the respective `DOM` element           |\n| `selector`                | Object that allows one to query for elements using dot notation |\n\n### Note\n\n\u003eThe `selector` property used in the library uses behind the secenes the [AsyncSelector] class from [shadow-dom-selector], which is highly inspired in the query philosophy of [lovelace-card-mod].\n\n\n[Home Assistant]: https://www.home-assistant.io\n[HACS]: https://hacs.xyz\n[WebComponents]: https://www.webcomponents.org\n[ShadowDOM]: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM\n[EventTarget]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget\n[CustomEvent]: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent\n[AsyncSelector]: https://github.com/elchininet/shadow-dom-selector#asyncselector-class\n[shadow-dom-selector]: https://github.com/elchininet/shadow-dom-selector\n[lovelace-card-mod]: https://github.com/thomasloven/lovelace-card-mod\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felchininet%2Fhome-assistant-query-selector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felchininet%2Fhome-assistant-query-selector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felchininet%2Fhome-assistant-query-selector/lists"}