No, please reread my previous comment. Use the general CSS styles field in the card configuration UI to change the value of --ha-dialog-surface-background (after updating to 4.10.0).
FYI patch version 4.10.3 renames --size to --icon-size to avoid a CSS custom property name conflict with the ha-adaptive-dialog height property. If you use this property in your custom remote styles, search and replace for all instances of --size with --icon-size.
An absolutely remarkable card.
I am controlling several different TV’s (One Samsung [Smart TV Mode], One Samsung, fed by a Fire TV streamer, and an LG, fed by a Fire TV streamer).
90% of the dashboard yaml is identical.
I just fill in the entities and point to a custom_actions_file that holds all the app commands etc…
So the Samsung + Fire TV is:
- type: custom:universal-remote-card
platform: Fire TV
remote_id: remote.fire_tv_family_192_168_1_65
media_player_id: media_player.fire_tv_family_192_168_1_65
volume_entity: media_player.ma_soundbar_porch
power_entity: media_player.sts_samsung_q90_porch
mute_entity: media_player.sts_samsung_q90_porch
room_name: Porch · Fire TV Remote
custom_actions_file: local/ur_firetv.yaml
and the Samsung Smart TV version is:
- type: custom:universal-remote-card
platform: Samsung TV
remote_id: remote.sts_samsung_q90_porch
media_player_id: media_player.sts_samsung_q90_porch
volume_entity: media_player.ma_soundbar_porch
power_entity: media_player.sts_samsung_q90_porch
mute_entity: media_player.sts_samsung_q90_porch
room_name: Porch · Samsung TV Remote
custom_actions_file: local/ur_samsung.yaml
and the stylized remote is (100% URC):
Happy to share full dashboard yaml and the custom_actions_file if it helps anyone.
Nice! I like the scolling buttons at the top for app/input selection.
Hi! Love this integration, it works pretty well for my assortment of media devices.
I had a question though - is it possible to show the state of a button’s entity on the universal remote card? I’m trying to achieve something like this:
so I can show the current volume level on the remote itself (example image built with
custom:button-cards where the middle one just shows entity state). Thanks!
You can create a custom remote element and use it’s label with a template to show the button entity state. You can use two other custom remote elements for the plus and minus buttons.
You may also be interested in custom card features, which has a spinbox made specifically for displaying and incrementing/decrementing numeric feature states/attributes.
Thank you, the label change was pretty much exactly what I needed!
looks very nice, can you share your yaml and the custom actions
Version 4.11.0 adds keyboard support to the Apple TV platform, along with a few other small improvements. This release requires Home Assistant 2026.5.0, which adds keyboard actions to the Apple TV integration.
I'm using HAIR to learn IR commands from various remotes (mainly older non-IP commanded devices) and would like to integrate them into the Universal Remote card. HAIR creates buttons for each command instead of a remote device.
I tried to use generic remote but couldn't figure out how to map each predefined card button to a button entity. Is there an example or instructions on hwo to do this?
You have to create custom remote button elements in the elements tab of the configuration UI. After creating the element, set the name to be the same as a default one to inherit/overwrite it or create one with a new name and set the interaction tap action to press the button. See the custom elements section of the README for more information.
Thanks. I missed that and now feel sily
Is there a possibility to add nuvio icon and wuplayer icon please? Just updated and noticed streamio and a bunch of Australian icons got added.
Create a feature request with app and platform info and I'll get around to it eventually.
I love the Universal Remote Card! I have three TVs, use a streamline card holding the URC and some other entities (on/off for the speakers and volume control, art_mode, brightness, etc) and one button access to all of our (too many) subscriptions. I put those cards behind conditional cards, so that they don't clutter my dashboard when not in use. Fantastic! Thanks, Nerwyn!
Just wanted to drop in and express my appreciation for this awesome card. @Nerwyn, thank you for the effort in both creating it and for publishing such a comprehensive readme. There’s a mountain of knowledge in there if you’re willing to go look for it, and the examples seemed to be very thoughtfully assembled to cover the gamut in terms of adjustable parameters. I started with zero experience using CSS templates, so I was pretty happy to be able to create a universal remote for my theater that does a somewhat decent job of imitating the native appearance of the individual components and apps.
I do have a couple questions that I wasn’t able to run down, if anyone happens to know. Does this card accept the following template?
{{ states.media_player.apple_tv.attributes.media_duration is defined }}
I’d like to be able to suppress the slider for media position when it’s obviously not relevant, and the above seems to check ok in the template editor, but no luck using it in the layout section of the card. I’m also struggling to define a fixed height for a row that holds single icons or columns depending on input source. I’ve tried
#row-8 { height: 100px; } as an example in the general styles as well as .row {height…} in individual elements. I’m sure I’m missing something simple here.
I’m glad you like it so much! Your remotes look excellent.
This card (and custom card features) use an alternative frontend templating system I developed called ha-nunjucks, which has mostly the same syntax with some minor differences. One of them is the syntax of the states object, as I can’t use the same name for it and the states function. You just have to add an underscore before states.
{{ _states.media_player.apple_tv.attributes.media_duration is defined }}
BUT you should avoid using the states object directly in favor of the state_attr function, which is much more efficient.
{{ state_attr('media_player.apple_tv', 'media_duration') is defined }}
To change an individual row height, unset its flex property so it doesn’t conform to its parent flexbox.
#row-8 {
height: 100px;
flex: unset;
}
Ah thanks, that did it!
Not sure if there are many other Apple TV users in here, but thought I’d share my result of recreating the physical remote. Not quite an exact replica since the remote uses a combination circlepad/touchpad, but still functional.
yaml:
type: custom:universal-remote-card
rows:
- - power
- - touchpad
- - - menu
- play_pause
- volume_mute
- - home
- volume_up
- volume_down
- - null
- null
- - null
- null
- - null
- null
styles: |-
ha-card {
background-color: #A2AAADE0;
border-radius: 40px;
width: 230px;
box-shadow: 3px 4px 0px #A2AAAD90, 0px 0px 3px #111;
}
.empty-button {
height: 92px;
width: 84px;
}
#row-1 {
justify-content: flex-end;
}
#row-2 {
margin: 0px -6px -6px -6px;
}
custom_actions:
- name: power
tap_action:
action: key
key: POWER
platform: Apple TV
hold_action:
action: key
key: suspend
icon: mdi:power
type: button
styles: |
:host {
padding: 8px;
--icon-size: 30px;
--icon-color: #151515;
}
button {
height: var(--button-size);
width: var(--button-size);
box-shadow: 0px -1px 0px #ccc, 0px 1px 1px #000;
--button-size: 36px;
}
- type: touchpad
name: touchpad
tap_action:
action: key
key: select
up:
tap_action:
action: key
key: up
hold_action:
action: repeat
down:
tap_action:
action: key
key: down
hold_action:
action: repeat
left:
tap_action:
action: key
key: left
hold_action:
action: repeat
right:
tap_action:
action: key
key: right
hold_action:
action: repeat
styles: |-
toucharea {
height: 212px;
border-radius: 106px;
background: radial-gradient(circle at top, #080808 15%, #323232 100%);
--icon-color: #444;
}
.icon {
bottom: 40px;
}
- name: menu
tap_action:
action: key
key: menu
icon: mdi:chevron-left
type: button
styles: |-
:host {
--icon-color: #E8E8E8;
}
button {
background: radial-gradient(circle at top, #080808 15%, #323232 100%);
border-radius: 50%;
height: var(--button_size);
width: var(--button_size);
box-shadow: 0px -1px 0px #aaa, 2px 2px 0px #000;
--button_size: 84px;
}
- name: play_pause
tap_action:
action: key
key: select
icon: mdi:play-pause
type: button
styles: |-
.icon {
color: #E8E8E8;
transform: scaleX(0.7) scaleY(0.5);
}
button {
background: radial-gradient(circle at top, #151515 75%, #202020 100%);
border: 1px solid #444;
height: var(--button_size);
width: var(--button_size);
box-shadow: 0px -1px 0px #aaa, 1px 1px 0px #000;
--button_size: 84px;
}
- name: volume_mute
tap_action:
action: key
key: MUTE
icon: mdi:volume-variant-off
type: button
styles: |-
:host {
--icon-size: 32px;
}
.icon {
color: #E8E8E8;
}
button {
background: radial-gradient(circle at top, #151515 75%, #202020 100%);
border: 1px solid #444;
border-radius: 50%;
height: var(--button_size);
width: var(--button_size);
box-shadow: 0px -1px 0px #aaa, 1px 1px 0px #000;
--button_size: 84px;
}
- name: home
tap_action:
action: key
key: home
icon: mdi:television
type: button
styles: |-
:host {
padding-top: 1px;
--icon-size: 34px;
--icon-color: #E8E8E8;
}
button {
background: radial-gradient(circle at top, #151515 75%, #202020 100%);
height: var(--button_size);
width: var(--button_size);
border: 1px solid #444;
border-radius: 42px;
box-shadow: 0px -1px 0px #aaa, 1px 1px 0px #000;
--button_size: 84px;
}
- name: volume_up
tap_action:
action: key
key: VOLUME_UP
hold_action:
action: repeat
icon: mdi:plus
type: button
styles: |
:host {
margin-bottom: -4px;
--icon-size: 32px;
--icon-color: #ddd;
}
.icon {
margin-bottom: 4px;
}
button {
background: radial-gradient(circle at top, #151515 75%, #151515 100%);
border-radius: 42px 42px 0% 0%;
box-shadow: 0px -1px 0px #aaa, 0px 0px 0px #000;
height: 87px;
width: 84px;
}
- name: volume_down
tap_action:
action: key
key: VOLUME_DOWN
hold_action:
action: repeat
icon: mdi:minus
type: button
styles: |-
:host {
margin-top: -4px;
--icon-size: 32px;
--icon-color: #ddd;
}
.icon {
margin-top: 6px;
}
button {
display: flex;
flex-direction: column-reverse;
background: radial-gradient(circle at top, #151515 75%, #303030 100%);
border-radius: 0% 0% 42px 42px;
box-shadow: 0px 0px 0px #000, 0px 1px 0px #000;
height: 87px;
width: 84px;
}
platform: Apple TV
One of the things I’m surprised to see is that no one has posted anything for out of the box control of an Xbox.
One of the problems I first ran into is, I don’t know if its just me not know how to properly integrate it. But I had to manually override the config entry in the yaml code as my xbox would not show up on the list. Though my xbox account shows up there thought that doesn’t help for controlling the xbox.
Also had to build out the yaml code from scratch. I’ll include it in here perhaps someone with better knowledgeable them me can make it better.
Is it normal for there to be a huge delay from when I push the button the on the card and when the input registers in the Xbox.
type: custom:universal-remote-card
config_entry_id: 6b587a1241eff3eda0e840c563dbb524
remote_id: remote.dining_room_xbox_one
media_player_id: media_player.dining_room_jose
device: Xbox One
rows:
- - back
- power
- home
- menu
- - circlepad
- - volume_up
- volume_down
- volume_mute
- - previous
- rewind
- play
- pause
- fast_forward
- next
- - plex
- youtube
platform: Generic Remote
custom_actions:
- type: circlepad
name: circlepad
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: A
up:
icon: mdi:chevron-up
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Up
hold_action:
action: nothing
down:
icon: mdi:chevron-down
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Down
hold_action:
action: nothing
left:
icon: mdi:chevron-left
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Left
hold_action:
action: nothing
right:
icon: mdi:chevron-right
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Right
hold_action:
action: nothing
- name: home
icon: mdi:home
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: GoHome
hold_action:
action: nothing
type: home
- name: play
icon: mdi:play
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Play
hold_action:
action: nothing
type: play
- name: pause
icon: mdi:pause
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Pause
hold_action:
action: nothing
type: pause
- name: menu
icon: mdi:microsoft-xbox
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Nexus
type: menu
- name: plex
icon: mdi:plex
tap_action:
action: call-service
service: media_player.play_media
target:
entity_id: media_player.dining_room_xbox_one
data:
media_content_id: 9NBLGGH3ZZVF
media_content_type: app
type: plex
- name: youtube
icon: mdi:youtube
tap_action:
action: call-service
service: media_player.play_media
target:
entity_id: media_player.dining_room_xbox_one
data:
media_content_id: 9NDP7KTLK7W3
media_content_type: app
type: YouTube
- name: volume_up
icon: mdi:volume-plus
tap_action:
action: call-service
service: media_player.volume_up
target:
entity_id: media_player.dining_room_xbox_one
hold_action:
action: repeat
type: volume Up
- name: volume_down
icon: mdi:volume-minus
tap_action:
action: call-service
service: media_player.volume_down
target:
entity_id: media_player.dining_room_xbox_one
hold_action:
action: repeat
type: volume down
- name: volume_mute
icon: mdi:volume-off
tap_action:
action: call-service
service: media_player.volume_mute
target:
entity_id: media_player.dining_room_xbox_one
type: volume mute
- name: back
icon: mdi:arrow-left
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: GoBack
type: back
- type: rewind
name: rewind
icon: mdi:rewind
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Left
hold_action:
action: nothing
- type: fast_forward
name: fast_forward
icon: mdi:fast-forward
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Right
hold_action:
action: nothing
- type: Next Chapter
name: next
icon: mdi:skip-next
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Next
- type: Previous Chapter
name: previous
icon: mdi:skip-previous
tap_action:
action: call-service
service: remote.send_command
target:
entity_id: remote.dining_room_xbox_one
data:
command: Previous






