diff --git a/src/ui/panes/valve_control.rs b/src/ui/panes/valve_control.rs
index d1971b68d77ef8ae0a1cea8dab7e8db4d36b18ec..618e29e0eb2254c6857e94272742db1d5541cd69 100644
--- a/src/ui/panes/valve_control.rs
+++ b/src/ui/panes/valve_control.rs
@@ -1,5 +1,6 @@
 mod commands;
 mod icons;
+mod ui;
 mod valves;
 
 use std::{
@@ -8,9 +9,9 @@ use std::{
 };
 
 use egui::{
-    Color32, DragValue, FontId, Frame, Grid, Key, Label, Margin, Modal, Modifiers, Response,
-    RichText, Sense, Stroke, TextFormat, Ui, UiBuilder, Vec2, Widget, Window, text::LayoutJob,
-    vec2,
+    Color32, DragValue, FontId, Frame, Grid, Key, KeyboardShortcut, Label, Modal, Modifiers,
+    Response, RichText, Sense, Stroke, TextFormat, Ui, UiBuilder, Vec2, Widget, Window,
+    text::LayoutJob, vec2,
 };
 use itertools::Itertools;
 use serde::{Deserialize, Serialize};
@@ -20,9 +21,9 @@ use skyward_mavlink::{
 };
 use strum::IntoEnumIterator;
 use tracing::{error, info, warn};
+use ui::ShortcutCard;
 
 use crate::{
-    error::ErrInstrument,
     mavlink::{MavMessage, TimedMessage},
     ui::{
         app::PaneResponse,
@@ -228,7 +229,7 @@ impl ValveControlPane {
                 .show(ui, |ui| {
                     for chunk in &valve_chunks {
                         for (symbol, valve) in chunk {
-                            ui.scope(self.valve_frame_ui(valve, symbol));
+                            ui.scope(self.valve_frame_ui(valve, map_symbol_to_key(symbol)));
                         }
                         ui.end_row();
                     }
@@ -277,7 +278,7 @@ impl ValveControlPane {
         }
     }
 
-    fn valve_frame_ui(&self, valve: Valve, symbol: char) -> impl FnOnce(&mut Ui) {
+    fn valve_frame_ui(&self, valve: Valve, shortcut_key: Key) -> impl FnOnce(&mut Ui) {
         move |ui| {
             profiling::function_scope!("valve_frame_ui");
             let valve_str = valve.to_string();
@@ -357,24 +358,6 @@ impl ValveControlPane {
                 });
             };
 
-            fn inside_frame(
-                valve_title_ui: impl FnOnce(&mut Ui),
-                symbol: char,
-                btn_fill_color: Color32,
-                text_color: Color32,
-                labels_ui: impl FnOnce(&mut Ui),
-            ) -> impl FnOnce(&mut Ui) {
-                move |ui: &mut Ui| {
-                    ui.vertical(|ui| {
-                        valve_title_ui(ui);
-                        ui.horizontal(|ui| {
-                            big_symbol_ui(symbol, btn_fill_color, text_color)(ui);
-                            labels_ui(ui);
-                        });
-                    });
-                }
-            }
-
             ui.scope_builder(
                 UiBuilder::new()
                     .id_salt("valve_".to_owned() + &valve_str)
@@ -395,21 +378,26 @@ impl ValveControlPane {
                         visuals.bg_fill
                     };
 
+                    let inside_frame = |ui: &mut Ui| {
+                        ui.vertical(|ui| {
+                            valve_title_ui(ui);
+                            ui.horizontal(|ui| {
+                                ShortcutCard::new(map_key_to_shortcut(shortcut_key))
+                                    .text_color(text_color)
+                                    .fill_color(btn_fill_color)
+                                    .text_size(20.)
+                                    .ui(ui);
+                                labels_ui(ui);
+                            });
+                        });
+                    };
+
                     Frame::canvas(ui.style())
                         .fill(fill_color)
                         .stroke(Stroke::NONE)
                         .inner_margin(ui.spacing().menu_margin)
                         .corner_radius(visuals.corner_radius)
-                        .show(
-                            ui,
-                            inside_frame(
-                                &valve_title_ui,
-                                symbol,
-                                btn_fill_color,
-                                text_color,
-                                &labels_ui,
-                            ),
-                        );
+                        .show(ui, inside_frame);
 
                     if response.clicked() {
                         info!("Clicked!");
@@ -471,15 +459,11 @@ impl ValveControlPane {
             }
 
             let wiggle_btn_response = btn_ui(valve, Self::WIGGLE_KEY, |ui| {
-                big_symbol_ui(
-                    Self::WIGGLE_KEY
-                        .symbol_or_name()
-                        .chars()
-                        .next()
-                        .log_unwrap(),
-                    ui.visuals().widgets.inactive.bg_fill,
-                    ui.visuals().text_color(),
-                )(ui);
+                ShortcutCard::new(map_key_to_shortcut(Self::WIGGLE_KEY))
+                    .text_color(ui.visuals().text_color())
+                    .fill_color(ui.visuals().widgets.inactive.bg_fill)
+                    .text_size(20.)
+                    .ui(ui);
                 ui.add(
                     Icon::Wiggle
                         .as_image(ui.ctx().theme())
@@ -490,15 +474,11 @@ impl ValveControlPane {
 
             let mut aperture = 0_u32;
             let aperture_btn_response = btn_ui(valve, Self::APERTURE_KEY, |ui| {
-                big_symbol_ui(
-                    Self::APERTURE_KEY
-                        .symbol_or_name()
-                        .chars()
-                        .next()
-                        .log_unwrap(),
-                    ui.visuals().widgets.inactive.bg_fill,
-                    ui.visuals().text_color(),
-                )(ui);
+                ShortcutCard::new(map_key_to_shortcut(Self::APERTURE_KEY))
+                    .text_color(ui.visuals().text_color())
+                    .fill_color(ui.visuals().widgets.inactive.bg_fill)
+                    .text_size(20.)
+                    .ui(ui);
                 ui.add(
                     Icon::Aperture
                         .as_image(ui.ctx().theme())
@@ -517,15 +497,11 @@ impl ValveControlPane {
 
             let mut timing_ms = 0_u32;
             let timing_btn_response = btn_ui(valve, Self::TIMING_KEY, |ui| {
-                big_symbol_ui(
-                    Self::TIMING_KEY
-                        .symbol_or_name()
-                        .chars()
-                        .next()
-                        .log_unwrap(),
-                    ui.visuals().widgets.inactive.bg_fill,
-                    ui.visuals().text_color(),
-                )(ui);
+                ShortcutCard::new(map_key_to_shortcut(Self::TIMING_KEY))
+                    .text_color(ui.visuals().text_color())
+                    .fill_color(ui.visuals().widgets.inactive.bg_fill)
+                    .text_size(20.)
+                    .ui(ui);
                 ui.add(
                     Icon::Timing
                         .as_image(ui.ctx().theme())
@@ -616,27 +592,9 @@ impl ValveControlPane {
                 shortcut_handler.deactivate_mode(ShortcutMode::valve_control());
                 // No window is open, so we can map the keys to open the valve control windows
                 for &symbol in self.valve_symbol_map.keys() {
-                    let key = match symbol {
-                        '1' => Key::Num1,
-                        '2' => Key::Num2,
-                        '3' => Key::Num3,
-                        '4' => Key::Num4,
-                        '5' => Key::Num5,
-                        '6' => Key::Num6,
-                        '7' => Key::Num7,
-                        '8' => Key::Num8,
-                        '9' => Key::Num9,
-                        '-' => Key::Minus,
-                        '/' => Key::Slash,
-                        '.' => Key::Period,
-                        _ => {
-                            error!("Invalid symbol: {}", symbol);
-                            panic!("Invalid symbol: {}", symbol);
-                        }
-                    };
                     key_action_pairs.push((
                         Modifiers::NONE,
-                        key,
+                        map_symbol_to_key(symbol),
                         PaneAction::OpenValveControl(self.valve_symbol_map[&symbol]),
                     ));
                 }
@@ -647,23 +605,32 @@ impl ValveControlPane {
     }
 }
 
-fn big_symbol_ui(symbol: char, fill_color: Color32, text_color: Color32) -> impl Fn(&mut Ui) {
-    move |ui: &mut Ui| {
-        let number = RichText::new(symbol.to_string())
-            .color(text_color)
-            .font(FontId::monospace(20.));
-
-        Frame::canvas(ui.style())
-            .fill(fill_color)
-            .stroke(Stroke::NONE)
-            .inner_margin(Margin::same(5))
-            .corner_radius(ui.visuals().widgets.noninteractive.corner_radius)
-            .show(ui, |ui| {
-                Label::new(number).selectable(false).ui(ui);
-            });
+fn map_symbol_to_key(symbol: char) -> Key {
+    match symbol {
+        '1' => Key::Num1,
+        '2' => Key::Num2,
+        '3' => Key::Num3,
+        '4' => Key::Num4,
+        '5' => Key::Num5,
+        '6' => Key::Num6,
+        '7' => Key::Num7,
+        '8' => Key::Num8,
+        '9' => Key::Num9,
+        '-' => Key::Minus,
+        '/' => Key::Slash,
+        '.' => Key::Period,
+        _ => {
+            error!("Invalid symbol: {}", symbol);
+            panic!("Invalid symbol: {}", symbol)
+        }
     }
 }
 
+#[inline]
+fn map_key_to_shortcut(key: Key) -> KeyboardShortcut {
+    KeyboardShortcut::new(Modifiers::NONE, key)
+}
+
 // ┌───────────────────────────┐
 // │       UTILS METHODS       │
 // └───────────────────────────┘
diff --git a/src/ui/panes/valve_control/icons.rs b/src/ui/panes/valve_control/icons.rs
index b8b14e419b3a6f870b2312af4ea8cf0373c46937..654acae3b8172661da4d46329b42b65648a41e54 100644
--- a/src/ui/panes/valve_control/icons.rs
+++ b/src/ui/panes/valve_control/icons.rs
@@ -1,10 +1,8 @@
-use egui::{Context, Image, ImageSource, SizeHint, TextureOptions, Theme, Ui};
+use egui::{Context, Image, ImageSource, SizeHint, TextureOptions, Theme};
 use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
 use tracing::error;
 
-use crate::error::ErrInstrument;
-
 #[derive(Debug, Clone, Copy, EnumIter)]
 pub enum Icon {
     Wiggle,
diff --git a/src/ui/panes/valve_control/ui.rs b/src/ui/panes/valve_control/ui.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9bbc0568c8fada73f57366613a5b8dcd7ec04c8a
--- /dev/null
+++ b/src/ui/panes/valve_control/ui.rs
@@ -0,0 +1,66 @@
+use egui::{
+    Color32, FontId, Frame, KeyboardShortcut, Label, Margin, ModifierNames, RichText, Stroke,
+    Widget,
+};
+
+pub struct ShortcutCard {
+    shortcut: KeyboardShortcut,
+    text_size: f32,
+    text_color: Option<Color32>,
+    fill_color: Option<Color32>,
+}
+
+impl Widget for ShortcutCard {
+    fn ui(self, ui: &mut egui::Ui) -> egui::Response {
+        #[cfg(target_os = "macos")]
+        let is_mac = true;
+        #[cfg(not(target_os = "macos"))]
+        let is_mac = false;
+
+        let shortcut_fmt = self.shortcut.format(&ModifierNames::SYMBOLS, is_mac);
+        let default_style = ui.style().noninteractive();
+        let text_color = self.text_color.unwrap_or(default_style.text_color());
+        let fill_color = self.fill_color.unwrap_or(default_style.bg_fill);
+        let corner_radius = default_style.corner_radius;
+
+        let number = RichText::new(shortcut_fmt)
+            .color(text_color)
+            .font(FontId::monospace(self.text_size));
+
+        Frame::canvas(ui.style())
+            .fill(fill_color)
+            .stroke(Stroke::NONE)
+            .inner_margin(Margin::same(5))
+            .corner_radius(corner_radius)
+            .show(ui, |ui| {
+                Label::new(number).selectable(false).ui(ui);
+            })
+            .response
+    }
+}
+
+impl ShortcutCard {
+    pub fn new(shortcut: KeyboardShortcut) -> Self {
+        Self {
+            shortcut,
+            text_size: 20.,
+            text_color: None,
+            fill_color: None,
+        }
+    }
+
+    pub fn text_size(mut self, text_size: f32) -> Self {
+        self.text_size = text_size;
+        self
+    }
+
+    pub fn text_color(mut self, text_color: Color32) -> Self {
+        self.text_color = Some(text_color);
+        self
+    }
+
+    pub fn fill_color(mut self, fill_color: Color32) -> Self {
+        self.fill_color = Some(fill_color);
+        self
+    }
+}