diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
index 055acc1ed46..21336f0b9a5 100644
--- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp
@@ -70,7 +70,7 @@ void GcodeSuite::G29() {
     return;
   }
 
-  int8_t ix, iy;
+  int8_t ix, iy = 0;
 
   switch (state) {
     case MeshReport:
@@ -88,6 +88,7 @@ void GcodeSuite::G29() {
       mbl_probe_index = 0;
       if (!ui.wait_for_move) {
         queue.inject_P(parser.seen_test('N') ? PSTR("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : PSTR("G29S2"));
+        TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart());
         return;
       }
       state = MeshNext;
@@ -109,6 +110,7 @@ void GcodeSuite::G29() {
       else {
         // Save Z for the previous mesh position
         mbl.set_zigzag_z(mbl_probe_index - 1, current_position.z);
+        TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, current_position.z));
         SET_SOFT_ENDSTOP_LOOSE(false);
       }
       // If there's another point to sample, move there with optional lift.
diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp
index b0def618fd0..ddeb02e3be1 100644
--- a/Marlin/src/lcd/extui/ui_api.cpp
+++ b/Marlin/src/lcd/extui/ui_api.cpp
@@ -47,6 +47,7 @@
 
 #include "../marlinui.h"
 #include "../../gcode/queue.h"
+#include "../../gcode/gcode.h"
 #include "../../module/motion.h"
 #include "../../module/planner.h"
 #include "../../module/probe.h"
@@ -353,14 +354,9 @@ namespace ExtUI {
 
   extruder_t getTool(const uint8_t extruder) {
     switch (extruder) {
-      case 7:  return E7;
-      case 6:  return E6;
-      case 5:  return E5;
-      case 4:  return E4;
-      case 3:  return E3;
-      case 2:  return E2;
-      case 1:  return E1;
-      default: return E0;
+      default:
+      case 0: return E0; case 1: return E1; case 2: return E2; case 3: return E3;
+      case 4: return E4; case 5: return E5; case 6: return E6; case 7: return E7;
     }
   }
 
@@ -372,8 +368,8 @@ namespace ExtUI {
     switch (axis) {
       #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
         case X: return axis_should_home(X_AXIS);
-        case Y: return axis_should_home(Y_AXIS);
-        case Z: return axis_should_home(Z_AXIS);
+        OPTCODE(HAS_Y_AXIS, case Y: return axis_should_home(Y_AXIS))
+        OPTCODE(HAS_Z_AXIS, case Z: return axis_should_home(Z_AXIS))
       #else
         case X: case Y: case Z: return true;
       #endif
@@ -385,6 +381,8 @@ namespace ExtUI {
     return !thermalManager.tooColdToExtrude(extruder - E0);
   }
 
+  GcodeSuite::MarlinBusyState getMachineBusyState() { return TERN0(HOST_KEEPALIVE_FEATURE, GcodeSuite::busy_state); }
+
   #if HAS_SOFTWARE_ENDSTOPS
     bool getSoftEndstopState() { return soft_endstop._enabled; }
     void setSoftEndstopState(const bool value) { soft_endstop._enabled = value; }
@@ -396,18 +394,27 @@ namespace ExtUI {
         #if AXIS_IS_TMC(X)
           case X: return stepperX.getMilliamps();
         #endif
-        #if AXIS_IS_TMC(X2)
-          case X2: return stepperX2.getMilliamps();
-        #endif
         #if AXIS_IS_TMC(Y)
           case Y: return stepperY.getMilliamps();
         #endif
-        #if AXIS_IS_TMC(Y2)
-          case Y2: return stepperY2.getMilliamps();
-        #endif
         #if AXIS_IS_TMC(Z)
           case Z: return stepperZ.getMilliamps();
         #endif
+        #if AXIS_IS_TMC(I)
+          case I: return stepperI.getMilliamps();
+        #endif
+        #if AXIS_IS_TMC(J)
+          case J: return stepperJ.getMilliamps();
+        #endif
+        #if AXIS_IS_TMC(K)
+          case K: return stepperK.getMilliamps();
+        #endif
+        #if AXIS_IS_TMC(X2)
+          case X2: return stepperX2.getMilliamps();
+        #endif
+        #if AXIS_IS_TMC(Y2)
+          case Y2: return stepperY2.getMilliamps();
+        #endif
         #if AXIS_IS_TMC(Z2)
           case Z2: return stepperZ2.getMilliamps();
         #endif
@@ -450,18 +457,27 @@ namespace ExtUI {
         #if AXIS_IS_TMC(X)
           case X: stepperX.rms_current(constrain(mA, 400, 1500)); break;
         #endif
-        #if AXIS_IS_TMC(X2)
-          case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break;
-        #endif
         #if AXIS_IS_TMC(Y)
           case Y: stepperY.rms_current(constrain(mA, 400, 1500)); break;
         #endif
-        #if AXIS_IS_TMC(Y2)
-          case Y2: stepperY2.rms_current(constrain(mA, 400, 1500)); break;
-        #endif
         #if AXIS_IS_TMC(Z)
           case Z: stepperZ.rms_current(constrain(mA, 400, 1500)); break;
         #endif
+        #if AXIS_IS_TMC(I)
+          case I: stepperI.rms_current(constrain(mA, 400, 1500)); break;
+        #endif
+        #if AXIS_IS_TMC(J)
+          case J: stepperJ.rms_current(constrain(mA, 400, 1500)); break;
+        #endif
+        #if AXIS_IS_TMC(K)
+          case K: stepperK.rms_current(constrain(mA, 400, 1500)); break;
+        #endif
+        #if AXIS_IS_TMC(X2)
+          case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break;
+        #endif
+        #if AXIS_IS_TMC(Y2)
+          case Y2: stepperY2.rms_current(constrain(mA, 400, 1500)); break;
+        #endif
         #if AXIS_IS_TMC(Z2)
           case Z2: stepperZ2.rms_current(constrain(mA, 400, 1500)); break;
         #endif
@@ -501,66 +517,59 @@ namespace ExtUI {
 
     int getTMCBumpSensitivity(const axis_t axis) {
       switch (axis) {
-        #if ENABLED(X_SENSORLESS)
-          case X:  return stepperX.homing_threshold();
-        #endif
-        #if ENABLED(X2_SENSORLESS)
-          case X2: return stepperX2.homing_threshold();
-        #endif
-        #if ENABLED(Y_SENSORLESS)
-          case Y:  return stepperY.homing_threshold();
-        #endif
-        #if ENABLED(Y2_SENSORLESS)
-          case Y2: return stepperY2.homing_threshold();
-        #endif
-        #if ENABLED(Z_SENSORLESS)
-          case Z:  return stepperZ.homing_threshold();
-        #endif
-        #if ENABLED(Z2_SENSORLESS)
-          case Z2: return stepperZ2.homing_threshold();
-        #endif
-        #if ENABLED(Z3_SENSORLESS)
-          case Z3: return stepperZ3.homing_threshold();
-        #endif
-        #if ENABLED(Z4_SENSORLESS)
-          case Z4: return stepperZ4.homing_threshold();
-        #endif
+        OPTCODE(X_SENSORLESS,  case X:  return stepperX.homing_threshold())
+        OPTCODE(Y_SENSORLESS,  case Y:  return stepperY.homing_threshold())
+        OPTCODE(Z_SENSORLESS,  case Z:  return stepperZ.homing_threshold())
+        OPTCODE(I_SENSORLESS,  case I:  return stepperI.homing_threshold())
+        OPTCODE(J_SENSORLESS,  case J:  return stepperJ.homing_threshold())
+        OPTCODE(K_SENSORLESS,  case K:  return stepperK.homing_threshold())
+        OPTCODE(X2_SENSORLESS, case X2: return stepperX2.homing_threshold())
+        OPTCODE(Y2_SENSORLESS, case Y2: return stepperY2.homing_threshold())
+        OPTCODE(Z2_SENSORLESS, case Z2: return stepperZ2.homing_threshold())
+        OPTCODE(Z3_SENSORLESS, case Z3: return stepperZ3.homing_threshold())
+        OPTCODE(Z4_SENSORLESS, case Z4: return stepperZ4.homing_threshold())
         default: return 0;
       }
     }
 
     void setTMCBumpSensitivity(const_float_t value, const axis_t axis) {
       switch (axis) {
-        #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS
-          #if X_SENSORLESS
-            case X:  stepperX.homing_threshold(value);  break;
-          #endif
-          #if X2_SENSORLESS
-            case X2: stepperX2.homing_threshold(value); break;
-          #endif
-          #if Y_SENSORLESS
-            case Y: stepperY.homing_threshold(value); break;
-          #endif
-          #if Y2_SENSORLESS
-            case Y2: stepperY2.homing_threshold(value); break;
-          #endif
-          #if Z_SENSORLESS
-            case Z: stepperZ.homing_threshold(value); break;
-          #endif
-          #if Z2_SENSORLESS
-            case Z2: stepperZ2.homing_threshold(value); break;
-          #endif
-          #if Z3_SENSORLESS
-            case Z3: stepperZ3.homing_threshold(value); break;
-          #endif
-          #if Z4_SENSORLESS
-            case Z4: stepperZ4.homing_threshold(value); break;
-          #endif
-        #else
-          UNUSED(value);
+        #if X_SENSORLESS
+          case X: stepperX.homing_threshold(value); break;
+        #endif
+        #if Y_SENSORLESS
+          case Y: stepperY.homing_threshold(value); break;
+        #endif
+        #if Z_SENSORLESS
+          case Z: stepperZ.homing_threshold(value); break;
+        #endif
+        #if I_SENSORLESS
+          case I: stepperI.homing_threshold(value); break;
+        #endif
+        #if J_SENSORLESS
+          case J: stepperJ.homing_threshold(value); break;
+        #endif
+        #if K_SENSORLESS
+          case K: stepperK.homing_threshold(value); break;
+        #endif
+        #if X2_SENSORLESS
+          case X2: stepperX2.homing_threshold(value); break;
+        #endif
+        #if Y2_SENSORLESS
+          case Y2: stepperY2.homing_threshold(value); break;
+        #endif
+        #if Z2_SENSORLESS
+          case Z2: stepperZ2.homing_threshold(value); break;
+        #endif
+        #if Z3_SENSORLESS
+          case Z3: stepperZ3.homing_threshold(value); break;
+        #endif
+        #if Z4_SENSORLESS
+          case Z4: stepperZ4.homing_threshold(value); break;
         #endif
         default: break;
       }
+      UNUSED(value);
     }
   #endif
 
@@ -661,9 +670,7 @@ namespace ExtUI {
 
   #if HAS_JUNCTION_DEVIATION
 
-    float getJunctionDeviation_mm() {
-      return planner.junction_deviation_mm;
-    }
+    float getJunctionDeviation_mm() { return planner.junction_deviation_mm; }
 
     void setJunctionDeviation_mm(const_float_t value) {
       planner.junction_deviation_mm = constrain(value, 0.001, 0.3);
@@ -682,7 +689,7 @@ namespace ExtUI {
   #endif
 
   #if PREHEAT_COUNT
-      uint16_t getMaterial_preset_E(const uint16_t index) { return ui.material_preset[index].hotend_temp; }
+    uint16_t getMaterial_preset_E(const uint16_t index) { return ui.material_preset[index].hotend_temp; }
     #if HAS_HEATED_BED
       uint16_t getMaterial_preset_B(const uint16_t index) { return ui.material_preset[index].bed_temp; }
     #endif
@@ -709,9 +716,13 @@ namespace ExtUI {
       switch (axis) {
         #if ENABLED(BABYSTEP_XY)
           case X: babystep.add_steps(X_AXIS, steps); break;
-          case Y: babystep.add_steps(Y_AXIS, steps); break;
+          #if HAS_Y_AXIS
+            case Y: babystep.add_steps(Y_AXIS, steps); break;
+          #endif
+        #endif
+        #if HAS_Z_AXIS
+          case Z: babystep.add_steps(Z_AXIS, steps); break;
         #endif
-        case Z: babystep.add_steps(Z_AXIS, steps); break;
         default: return false;
       };
       return true;
@@ -750,8 +761,8 @@ namespace ExtUI {
               hotend_offset[e][axis] += mm;
 
           normalizeNozzleOffset(X);
-          normalizeNozzleOffset(Y);
-          normalizeNozzleOffset(Z);
+          TERN_(HAS_Y_AXIS, normalizeNozzleOffset(Y));
+          TERN_(HAS_Z_AXIS, normalizeNozzleOffset(Z));
         }
       #else
         UNUSED(linked_nozzles);
@@ -1014,8 +1025,7 @@ namespace ExtUI {
     TERN_(HAS_FAN, thermalManager.zero_fan_speeds());
   }
 
-  bool awaitingUserConfirm() { return wait_for_user; }
-
+  bool awaitingUserConfirm() { return TERN0(HAS_RESUME_CONTINUE, wait_for_user); }
   void setUserConfirmed() { TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); }
 
   void printFile(const char *filename) {
@@ -1038,9 +1048,9 @@ namespace ExtUI {
 
   bool isMediaInserted() { return TERN0(SDSUPPORT, IS_SD_INSERTED() && card.isMounted()); }
 
-  void pausePrint() { ui.pause_print(); }
+  void pausePrint()  { ui.pause_print(); }
   void resumePrint() { ui.resume_print(); }
-  void stopPrint() { ui.abort_print(); }
+  void stopPrint()   { ui.abort_print(); }
 
   void onUserConfirmRequired_P(PGM_P const pstr) {
     char msg[strlen_P(pstr) + 1];
diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h
index 9922fa67999..8d8b0e59e41 100644
--- a/Marlin/src/lcd/extui/ui_api.h
+++ b/Marlin/src/lcd/extui/ui_api.h
@@ -44,6 +44,7 @@
 
 #include "../../inc/MarlinConfig.h"
 #include "../marlinui.h"
+#include "../../gcode/gcode.h"
 
 namespace ExtUI {
 
@@ -53,7 +54,7 @@ namespace ExtUI {
 
   static constexpr size_t eeprom_data_size = 48;
 
-  enum axis_t     : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4 };
+  enum axis_t     : uint8_t { X, Y, Z, I, J, K, X2, Y2, Z2, Z3, Z4 };
   enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 };
   enum heater_t   : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER, COOLER };
   enum fan_t      : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 };
@@ -78,6 +79,8 @@ namespace ExtUI {
   void injectCommands(char * const);
   bool commandsInQueue();
 
+  GcodeSuite::MarlinBusyState getMachineBusyState();
+
   bool isHeaterIdle(const heater_t);
   bool isHeaterIdle(const extruder_t);
   void enableHeater(const heater_t);
@@ -125,6 +128,7 @@ namespace ExtUI {
   float getAxisMaxAcceleration_mm_s2(const extruder_t);
   feedRate_t getMinFeedrate_mm_s();
   feedRate_t getMinTravelFeedrate_mm_s();
+  feedRate_t getFeedrate_mm_s();
   float getPrintingAcceleration_mm_s2();
   float getRetractAcceleration_mm_s2();
   float getTravelAcceleration_mm_s2();
@@ -186,6 +190,8 @@ namespace ExtUI {
     void setHostResponse(const uint8_t);
   #endif
 
+  inline void simulateUserClick() { ui.lcd_clicked = true; }
+
   #if ENABLED(PRINTCOUNTER)
     char* getFailedPrints_str(char buffer[21]);
     char* getTotalPrints_str(char buffer[21]);
diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp
index cff6e193549..d2e26afedfd 100644
--- a/Marlin/src/lcd/marlinui.cpp
+++ b/Marlin/src/lcd/marlinui.cpp
@@ -223,6 +223,10 @@ millis_t MarlinUI::next_button_update_ms; // = 0
 
 #endif
 
+#if EITHER(HAS_LCD_MENU, EXTENSIBLE_UI)
+  bool MarlinUI::lcd_clicked;
+#endif
+
 #if HAS_LCD_MENU
   #include "menu/menu.h"
 
@@ -247,14 +251,6 @@ millis_t MarlinUI::next_button_update_ms; // = 0
     uint8_t MarlinUI::repeat_delay;
   #endif
 
-  bool MarlinUI::lcd_clicked;
-
-  bool MarlinUI::use_click() {
-    const bool click = lcd_clicked;
-    lcd_clicked = false;
-    return click;
-  }
-
   #if EITHER(AUTO_BED_LEVELING_UBL, G26_MESH_VALIDATION)
 
     bool MarlinUI::external_control; // = false
diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h
index 766e46c66b2..14514e2a656 100644
--- a/Marlin/src/lcd/marlinui.h
+++ b/Marlin/src/lcd/marlinui.h
@@ -474,9 +474,6 @@ public:
     static void set_selection(const bool sel) { selection = sel; }
     static bool update_selection();
 
-    static bool lcd_clicked;
-    static bool use_click();
-
     static void synchronize(PGM_P const msg=nullptr);
 
     static screenFunc_t currentScreen;
@@ -527,12 +524,23 @@ public:
 
   #elif HAS_WIRED_LCD
 
-    static constexpr bool lcd_clicked = false;
     static constexpr bool on_status_screen() { return true; }
     FORCE_INLINE static void run_current_screen() { status_screen(); }
 
   #endif
 
+  #if EITHER(HAS_LCD_MENU, EXTENSIBLE_UI)
+    static bool lcd_clicked;
+    static inline bool use_click() {
+      const bool click = lcd_clicked;
+      lcd_clicked = false;
+      return click;
+    }
+  #else
+    static constexpr bool lcd_clicked = false;
+    static inline bool use_click() { return false; }
+  #endif
+
   #if BOTH(HAS_LCD_MENU, ADVANCED_PAUSE_FEATURE)
     static void pause_show_message(const PauseMessage message, const PauseMode mode=PAUSE_MODE_SAME, const uint8_t extruder=active_extruder);
   #else
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index 0042302fc79..2b3a1898844 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -384,7 +384,7 @@ FORCE_INLINE void probe_specific_action(const bool deploy) {
     DEBUG_EOL();
 
     TERN_(WAIT_FOR_NOZZLE_HEAT, if (hotend_temp > thermalManager.wholeDegHotend(0) + (TEMP_WINDOW)) thermalManager.wait_for_hotend(0));
-    TERN_(WAIT_FOR_BED_HEAT,    if (bed_temp > thermalManager.wholeDegBed() + (TEMP_BED_WINDOW))    thermalManager.wait_for_bed_heating());
+    TERN_(WAIT_FOR_BED_HEAT,    if (bed_temp    > thermalManager.wholeDegBed() + (TEMP_BED_WINDOW)) thermalManager.wait_for_bed_heating());
   }
 
 #endif
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index a5922cf5538..e7d4ece7219 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -3621,7 +3621,7 @@ void Temperature::isr() {
         #if G26_CLICK_CAN_CANCEL
           if (click_to_cancel && ui.use_click()) {
             wait_for_heatup = false;
-            ui.quick_feedback();
+            TERN_(HAS_LCD_MENU, ui.quick_feedback());
           }
         #endif
 
@@ -3755,7 +3755,7 @@ void Temperature::isr() {
         #if G26_CLICK_CAN_CANCEL
           if (click_to_cancel && ui.use_click()) {
             wait_for_heatup = false;
-            ui.quick_feedback();
+            TERN_(HAS_LCD_MENU, ui.quick_feedback());
           }
         #endif
 
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index e0dffc3f3aa..3a8c506a5db 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -174,7 +174,7 @@ enum ADCSensorState : char {
   #define unscalePID_d(d) ( float(d) * PID_dT )
 #endif
 
-#if BOTH(HAS_LCD_MENU, G26_MESH_VALIDATION)
+#if ENABLED(G26_MESH_VALIDATION) && EITHER(HAS_LCD_MENU, EXTENSIBLE_UI)
   #define G26_CLICK_CAN_CANCEL 1
 #endif