Vacuum Card fills the vacuum gap Home Assistant leaves in Lovelace
Vacuum cleaner card for Home Assistant Lovelace UI
At a glance
- What is it?
- Vacuum Card is a Lovelace custom card that shows a robot vacuum's state and controls it, because Home Assistant ships no card for the vacuum domain. It fits a Home Assistant user who wants a working robot control panel on a dashboard, and it does not fit anyone who needs the visual editor to cover the full option set, since actions, shortcuts and stats still need YAML.
- Who is it for?
- Vacuum Card fits a Home Assistant user with a robot vacuum who wants its state, battery, map and wear stats on a Lovelace dashboard and accepts editing the card in YAML, and it does not fit a dashboard maintained entirely through the visual editor, because the card's own documentation says there is no support for actions, shortcuts and stats in the visual config yet.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The vacuum domain has no stock Lovelace card, and that is the whole gap
By default, Home Assistant does not provide any card for controlling vacuum cleaners. Vacuum Card fills that specific hole: it displays the state of a robot vacuum and allows you to control it, as a Lovelace custom card.
That framing matters for the rest of the article, because it explains both the appeal and the limits. A Lovelace custom card is a JavaScript module that Home Assistant loads as a UI resource and instantiates through the custom: prefix in a dashboard. The card is not an integration, it does not add entities, and it does not talk to the vacuum on its own. It reads the existing vacuum entity and calls the existing services through the Home Assistant websocket API.
So the card is a presentation and control layer over whatever integration already exposes your robot. If your vacuum has no entity in the vacuum domain, there is nothing for the card to render, and the required entity option says as much: it takes an entity_id within the vacuum domain.
The project is MIT licensed, authored by Denys Dovhan, and the last push was on 2026-10-16 with the most recent listed release being v2.12.0 on 2026-02-07. The package is published as vacuum-card on npm and is distributed through HACS, the Home Assistant Community Store.
Installing through HACS is two clicks, and manual is a file and a resource entry
HACS is the supported path and it is short. The card is available in HACS, and the instruction is to search for Vacuum Card in the plugins tab.
The manual path is documented step by step, and it is worth reading because it explains exactly how Lovelace loads custom cards. You download vacuum-card.js from the latest release, put the file into your config/www folder, and then register it as a resource. Through the UI, that is Configuration, then Lovelace Dashboards, then the Resources tab, clicking Plus, setting Url to /local/vacuum-card.js and setting Resource type to JavaScript Module. The Resources tab is only visible if Advanced Mode is enabled in your User Profile, which is a common first stumbling block.
The YAML equivalent of the same registration is:
resources:
- url: /local/vacuum-card.js
type: moduleOnce the resource is registered, you add custom:vacuum-card to the Lovelace UI as you would any other card, using either the editor or YAML configuration. The fact that a single file in config/www is the entire deployment is a feature for anyone who versions their Home Assistant configuration, since the card can be committed alongside the dashboards that use it.
The visual editor only covers entity, and the README says so plainly
The card can be configured from the Lovelace UI editor, and the flow is short: open the three dots in the top left corner, click Configure UI, click Plus to add a new card, find Custom: Vacuum Card in the list, choose entity, and you should see the preview of the card.
Then the limitation, stated in the README's own words: sorry, no support for actions, shortcuts and stats in visual config yet. That sentence should decide whether you adopt the card or not, depending on how you maintain your dashboard.
The distinction in practice is that a card with a chosen entity and nothing else can be added entirely through the browser. Anything involving the actions object, the shortcuts array or the stats object requires editing YAML. The documentation leans on YAML for the richer cases, and the example it gives is a full YAML block with type, entity, actions, stats and shortcuts together.
The alternative workflow is a YAML-only dashboard, where the editor gap does not matter at all. There is also a third option worth knowing about, which is the HACS-managed resource path, where HACS handles the file placement and you configure through YAML.
Actions and shortcuts are where the card does more than show a button
The actions option overrides the default action behaviour with service invocations, and the shortcuts array adds named buttons at the bottom right of the card, each with a service and an icon.
A full configuration looks like this:
type: 'custom:vacuum-card'
entity: vacuum.vacuum_cleaner
actions:
start:
service: xiaomi_miio.vacuum_clean_segment
service_data:
entity_id: vacuum.vacuum_cleaner
segments: [16, 20]
shortcuts:
- name: Clean living room
service: script.clean_living_room
icon: 'mdi:sofa'
- name: Clean bedroom
service: script.clean_bedroom
icon: 'mdi:bed-empty'The example overrides the start action so that it runs a segment clean through the xiaomi_miio integration service xiaomi_miio.vacuum_clean_segment with a segments list, rather than starting a whole-house clean. The shortcuts call Home Assistant scripts, so a room-specific clean is a script you write and the card just triggers it.
The consequence is that the card is a thin trigger layer, and the interesting logic lives in the scripts and automations behind it. That is a sensible division, and it also means the card is not tied to any one vacuum brand: the actions and shortcuts are expressed as generic service calls.
Stats can read attributes or reach into other entities
The stats option takes custom per-state statistics for the vacuum, and it is the most flexible part of the configuration. The README states you can use any attribute of the vacuum, or even any entity by entity_id, and you can combine attribute with entity_id to extract an attribute value of a specific entity.
Each stat entry can carry entity_id for an entity with a state, attribute for an attribute name such as filter_left, a value_template as a Jinja2 template returning a value where the value variable represents the entity_id or attribute state, a unit such as hours, and a subtitle as a friendly name such as Filter.
The YAML in the README shows both modes. One stat reads the vacuum's own attributes directly, with attribute, unit and subtitle. Another uses entity_id with a value_template of '{{ (value | float(0) / 3600) | round(1) }}', which converts seconds to hours, and it is applied to sensor.vacuum_main_brush_left with a subtitle of Main brush.
The value_template option is what makes this useful. Wear indicators from different integrations are reported in different units and sometimes in seconds, and the template lets you normalise them for display without changing the underlying entity.
The failure mode to watch for is naming. The attributes in the example, filter_left, side_brush_left, main_brush_left and sensor_dirty_left, are specific to one integration's schema. If your vacuum reports wear under different names, the stat will render empty, and there is no error, just a blank row.
Optional options let you tune what the card shows
Beyond entity, the option table covers a reasonable amount of surface. battery_entity takes an entity_id in the sensor domain to display battery state and icon. map takes an entity_id in the camera domain for streaming the live vacuum map, and map_refresh sets the update interval for that camera in seconds with a default of 5.
The display options are mostly booleans. show_name defaults to true and shows the friendly name of the vacuum, show_status defaults to true and shows the status, show_toolbar defaults to true and shows the toolbar with actions, and compact_view defaults to false and gives a compact view without the image. The image option takes a path to an image of the vacuum cleaner, defaults to the string default, and the documentation advises png or svg.
The image and compact_view options are the ones with a design purpose rather than a technical one. The card's own preview image is a placeholder for the vacuum's actual picture, and the compact_view flag exists for the case where you want a small card in a row of tiles rather than a large one with a picture.
The build pipeline is Rollup, and the test script is lint plus build
For anyone contributing rather than installing, the repository layout is a modern TypeScript and Rollup project. The package.json sets the type to module, the main entry to dist/vacuum-card.js, and the build to rollup -c with a start script for rollup -c --watch.
The runtime dependencies are the interesting list. custom-card-helpers supplies the Lovelace card base class and helpers, ha-template provides templating, home-assistant-js-websocket is the connection to the Home Assistant API, lit 3.3.2 is the rendering layer, and lodash 4.17.21 for utility functions. The build uses the Rollup plugins for Babel, commonjs, image, json, node-resolve, replace and terser, with Babel handling the transform to a browser-compatible bundle.
The test script is worth reading closely, because it is not a unit test suite: npm run test runs the lint task and then the build. Lint itself is split into lint:src for eslint on src and lint:translations for a node scripts/validate-i18n check, with a separate prettier format step and husky configured through the prepare script.
The hacs.json file at the root is what makes the HACS distribution work, and the repository also has an AGENTS.md, a CONTRIBUTING.md and a CODE_OF_CONDUCT.md. The .husky directory and the prepare script mean the git hooks are installed on a normal npm install.
The version field in package.json reads 2.11.7, while the latest listed GitHub release is v2.12.0, which tells you the release tag and the manifest version are not kept in lockstep in the tree you are reading.
Editorial conclusion
Vacuum Card fits a Home Assistant user with a robot vacuum who wants its state, battery, map and wear stats on a Lovelace dashboard and accepts editing the card in YAML, and it does not fit a dashboard maintained entirely through the visual editor, because the card's own documentation says there is no support for actions, shortcuts and stats in the visual config yet. Before installing, confirm your vacuum exposes an entity in the vacuum domain, and if you use stats, check that the attributes you reference, such as filter_left or main_brush_left, exist on your integration rather than assuming they do.
Frequently asked questions
How do I install Vacuum Card in Home Assistant?
Through HACS, search for Vacuum Card in the plugins tab. Manually, download vacuum-card.js from the latest release, put it in your config/www folder, and register it as a JavaScript Module resource at /local/vacuum-card.js, then add custom:vacuum-card to your dashboard.
Can I configure Vacuum Card from the Lovelace visual editor?
Only partly. You can pick the entity through the editor, but the documentation states there is no support for actions, shortcuts and stats in visual config yet, so those options have to be edited in YAML.
What options does Vacuum Card support?
Required options are type, set to custom:vacuum-card, and entity, an entity_id in the vacuum domain. Optional ones include battery_entity, map, map_refresh, image, show_name, show_status, show_toolbar, compact_view, and the stats, actions and shortcuts objects.
How do I show brush wear hours in Vacuum Card?
Use the stats option with an attribute such as main_brush_left plus a unit of hours, or reference a separate entity by entity_id with a Jinja2 value_template such as '{{ (value | float(0) / 3600) | round(1) }}' to convert seconds into hours.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/denysdovhan-vacuum-card)