diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3a77cb4..7eb3019 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -166,6 +166,7 @@ set (SOURCES
     ${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/ui_launcher.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/ui_config.cpp
+    ${CMAKE_SOURCE_DIR}/src/ui/ui_config_sub_menu.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/ui_color_hack.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/ui_rml_hacks.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/ui_elements.cpp
@@ -186,11 +187,14 @@ set (SOURCES
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ElementOptionTypeTextField.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/presets.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_button.cpp
+    ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_clickable.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_container.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_element.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_image.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_label.cpp
+    ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_radio.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_scroll_container.cpp
+    ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_slider.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_style.cpp
     ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_toggle.cpp
 
diff --git a/assets/config_menu.rml b/assets/config_menu.rml
index d18d254..1059216 100644
--- a/assets/config_menu.rml
+++ b/assets/config_menu.rml
@@ -20,14 +20,14 @@
 		}
 		.col {
 			flex: 1;
-    		text-align: center;
+			text-align: center;
 		}
 	
 	
 	
 	
-  
-  
+	
+	
 	
 	
 	
@@ -104,6 +104,7 @@
 							
 						
 					
+					
 				
 				
     
         
     
 
diff --git a/lib/RmlUi b/lib/RmlUi
index b5bf23d..a893ea6 160000
--- a/lib/RmlUi
+++ b/lib/RmlUi
@@ -1 +1 @@
-Subproject commit b5bf23ddde92dc5bdbf3ab949cbab512fe866b31
+Subproject commit a893ea6386e0c842f90a726a53c9b9e888797519
diff --git a/src/ui/elements/ui_clickable.cpp b/src/ui/elements/ui_clickable.cpp
new file mode 100644
index 0000000..a1facc6
--- /dev/null
+++ b/src/ui/elements/ui_clickable.cpp
@@ -0,0 +1,45 @@
+#include "ui_clickable.h"
+
+namespace recompui {
+
+    static const std::string_view hover_state = "hover";
+    static const std::string_view disabled_state = "disabled";
+
+    Clickable::Clickable(Element *parent, bool draggable) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable, draggable ? EventType::Drag : EventType::None)) {
+        if (draggable) {
+            set_drag(Drag::Drag);
+        }
+    }
+
+    void Clickable::process_event(const Event &e) {
+        switch (e.type) {
+        case EventType::Click:
+            for (const auto &function : pressed_callbacks) {
+                function(e.click.mouse.x, e.click.mouse.y);
+            }
+            break;
+        case EventType::Hover:
+            set_style_enabled(hover_state, e.hover.active);
+            break;
+        case EventType::Enable:
+            set_style_enabled(disabled_state, !e.enable.enable);
+            break;
+        case EventType::Drag:
+            for (const auto &function : dragged_callbacks) {
+                function(e.drag.mouse.x, e.drag.mouse.y, e.drag.phase);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    void Clickable::add_pressed_callback(std::function callback) {
+        pressed_callbacks.emplace_back(callback);
+    }
+
+    void Clickable::add_dragged_callback(std::function callback) {
+        dragged_callbacks.emplace_back(callback);
+    }
+
+};
\ No newline at end of file
diff --git a/src/ui/elements/ui_clickable.h b/src/ui/elements/ui_clickable.h
new file mode 100644
index 0000000..2c8eb04
--- /dev/null
+++ b/src/ui/elements/ui_clickable.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "ui_element.h"
+
+namespace recompui {
+
+    class Clickable : public Element {
+    protected:
+        std::vector> pressed_callbacks;
+        std::vector> dragged_callbacks;
+
+        // Element overrides.
+        virtual void process_event(const Event &e) override;
+    public:
+        Clickable(Element *parent, bool draggable = false);
+        void add_pressed_callback(std::function callback);
+        void add_dragged_callback(std::function callback);
+    };
+
+} // namespace recompui
\ No newline at end of file
diff --git a/src/ui/elements/ui_element.cpp b/src/ui/elements/ui_element.cpp
index bd8ffc8..3d7fc97 100644
--- a/src/ui/elements/ui_element.cpp
+++ b/src/ui/elements/ui_element.cpp
@@ -16,6 +16,7 @@ Element::Element(Rml::Element *base) {
 Element::Element(Element* parent, uint32_t events_enabled, Rml::String base_class) {
     ContextId context = get_current_context();
     base_owning = context.get_document()->CreateElement(base_class);
+
     if (parent != nullptr) {
         base = parent->base->AppendChild(std::move(base_owning));
         parent->add_child(this);
@@ -82,6 +83,12 @@ void Element::register_event_listeners(uint32_t events_enabled) {
         base->AddEventListener(Rml::EventId::Mouseover, this);
         base->AddEventListener(Rml::EventId::Mouseout, this);
     }
+
+    if (events_enabled & Events(EventType::Drag)) {
+        base->AddEventListener(Rml::EventId::Drag, this);
+        base->AddEventListener(Rml::EventId::Dragstart, this);
+        base->AddEventListener(Rml::EventId::Dragend, this);
+    }
 }
 
 void Element::apply_style(Style *style) {
@@ -135,6 +142,9 @@ void Element::ProcessEvent(Rml::Event &event) {
     case Rml::EventId::Mousedown:
         process_event(Event::click_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f)));
         break;
+    case Rml::EventId::Drag:
+        process_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::Move));
+        break;
     default:
         break;
     }
@@ -154,6 +164,12 @@ void Element::ProcessEvent(Rml::Event &event) {
         case Rml::EventId::Blur:
             process_event(Event::focus_event(false));
             break;
+        case Rml::EventId::Dragstart:
+            process_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::Start));
+            break;
+        case Rml::EventId::Dragend:
+            process_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::End));
+            break;
         default:
             break;
         }
@@ -212,10 +228,10 @@ bool Element::is_enabled() const {
 }
 
 void Element::set_text(const std::string &text) {
-    base->SetInnerRML(text);
+    base->SetInnerRML(std::string(text));
 }
 
-void Element::set_style_enabled(const std::string_view &style_name, bool enable) {
+void Element::set_style_enabled(std::string_view style_name, bool enable) {
     if (enable && style_active_set.find(style_name) == style_active_set.end()) {
         // Style was disabled and will be enabled.
         style_active_set.emplace(style_name);
@@ -243,4 +259,28 @@ void Element::set_style_enabled(const std::string_view &style_name, bool enable)
     apply_styles();
 }
 
-};
\ No newline at end of file
+float Element::get_absolute_left() {
+    return base->GetAbsoluteLeft();
+}
+
+float Element::get_absolute_top() {
+    return base->GetAbsoluteTop();
+}
+
+float Element::get_client_left() {
+    return base->GetClientLeft();
+}
+
+float Element::get_client_top() {
+    return base->GetClientTop();
+}
+
+float Element::get_client_width() {
+    return base->GetClientWidth();
+}
+
+float Element::get_client_height() {
+    return base->GetClientHeight();
+}
+
+}
\ No newline at end of file
diff --git a/src/ui/elements/ui_element.h b/src/ui/elements/ui_element.h
index 396b350..07eef78 100644
--- a/src/ui/elements/ui_element.h
+++ b/src/ui/elements/ui_element.h
@@ -43,14 +43,19 @@ public:
     Element(Element* parent, uint32_t events_enabled = 0, Rml::String base_class = "div");
     virtual ~Element();
     void clear_children();
-    void add_style(Style *style, const std::string_view style_name);
+    void add_style(Style *style, std::string_view style_name);
     void add_style(Style *style, const std::initializer_list &style_names);
     void set_enabled(bool enabled);
     bool is_enabled() const;
     void set_text(const std::string &text);
-    void set_style_enabled(const std::string_view &style_name, bool enabled);
-
+    void set_style_enabled(std::string_view style_name, bool enabled);
     bool is_element() override { return true; }
+    float get_absolute_left();
+    float get_absolute_top();
+    float get_client_left();
+    float get_client_top();
+    float get_client_width();
+    float get_client_height();
 };
 
 } // namespace recompui
\ No newline at end of file
diff --git a/src/ui/elements/ui_radio.cpp b/src/ui/elements/ui_radio.cpp
new file mode 100644
index 0000000..dae8f37
--- /dev/null
+++ b/src/ui/elements/ui_radio.cpp
@@ -0,0 +1,5 @@
+#include "ui_radio.h"
+
+namespace recompui {
+
+};
\ No newline at end of file
diff --git a/src/ui/elements/ui_radio.h b/src/ui/elements/ui_radio.h
new file mode 100644
index 0000000..f8a50cb
--- /dev/null
+++ b/src/ui/elements/ui_radio.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "ui_element.h"
+
+namespace recompui {
+
+} // namespace recompui
\ No newline at end of file
diff --git a/src/ui/elements/ui_slider.cpp b/src/ui/elements/ui_slider.cpp
new file mode 100644
index 0000000..9915f20
--- /dev/null
+++ b/src/ui/elements/ui_slider.cpp
@@ -0,0 +1,142 @@
+#include "ui_slider.h"
+
+#include 
+
+namespace recompui {
+
+    void Slider::set_value_internal(double v, bool setup, bool trigger_callbacks) {
+        if (step_value != 0.0) {
+            v = std::lround(v / step_value) * step_value;
+        }
+
+        if (value != v || setup) {
+            value = v;
+            update_circle_position();
+            update_label_text();
+
+            if (trigger_callbacks) {
+                for (auto callback : value_changed_callbacks) {
+                    callback(v);
+                }
+            }
+        }
+    }
+
+    void Slider::bar_clicked(float x, float) {
+        update_value_from_mouse(x);
+    }
+
+    void Slider::bar_dragged(float x, float, DragPhase) {
+        update_value_from_mouse(x);
+    }
+
+    void Slider::circle_dragged(float x, float, DragPhase) {
+        update_value_from_mouse(x);
+    }
+
+    void Slider::update_value_from_mouse(float x) {
+        double left = slider_element->get_absolute_left();
+        double width = slider_element->get_client_width();
+        double ratio = std::clamp((x - left) / width, 0.0, 1.0);
+        set_value_internal(min_value + ratio * (max_value - min_value), false, true);
+    }
+
+    void Slider::update_circle_position() {
+        double ratio = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0);
+        circle_element->set_left(slider_width_dp * ratio);
+    }
+
+    void Slider::update_label_text() {
+        char text_buffer[32];
+        int precision = type == SliderType::Double ? 1 : 0;
+        auto result = std::to_chars(text_buffer, text_buffer + sizeof(text_buffer) - 1, value, std::chars_format::fixed, precision);
+        if (result.ec == std::errc()) {
+            if (type == SliderType::Percent) {
+                *result.ptr = '%';
+                result.ptr++;
+            }
+
+            value_label->set_text(std::string(text_buffer, result.ptr));
+        }
+    }
+
+    Slider::Slider(SliderType type, Element *parent) : Element(parent) {
+        this->type = type;
+
+        set_display(Display::Flex);
+        set_flex(1.0f, 1.0f, 100.0f, Unit::Percent);
+        set_flex_direction(FlexDirection::Row);
+
+        value_label = new Label("0", LabelStyle::Small, this);
+        value_label->set_margin_right(20.0f);
+        value_label->set_min_width(60.0f);
+        value_label->set_max_width(60.0f);
+
+        slider_element = new Element(this);
+        slider_element->set_width(slider_width_dp);
+
+        {
+            bar_element = new Clickable(slider_element, true);
+            bar_element->set_width(100.0f, Unit::Percent);
+            bar_element->set_height(2.0f);
+            bar_element->set_margin_top(8.0f);
+            bar_element->set_background_color(Color{ 255, 255, 255, 50 });
+            bar_element->add_pressed_callback(std::bind(&Slider::bar_clicked, this, std::placeholders::_1, std::placeholders::_2));
+            bar_element->add_dragged_callback(std::bind(&Slider::bar_dragged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+            
+            circle_element = new Clickable(slider_element, true);
+            circle_element->set_position(Position::Relative);
+            circle_element->set_width(16.0f);
+            circle_element->set_height(16.0f);
+            circle_element->set_margin_top(-8.0f);
+            circle_element->set_margin_right(-8.0f);
+            circle_element->set_margin_left(-8.0f);
+            circle_element->set_background_color(Color{ 204, 204, 204, 255 });
+            circle_element->set_border_radius(8.0f);
+            circle_element->add_dragged_callback(std::bind(&Slider::circle_dragged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+            circle_element->set_cursor(Cursor::Pointer);
+        }
+
+        set_value_internal(value, true, false);
+    }
+
+    Slider::~Slider() {
+
+    }
+
+    void Slider::set_value(double v) {
+        set_value_internal(v, false, false);
+    }
+
+    double Slider::get_value() const {
+        return value;
+    }
+    void Slider::set_min_value(double v) {
+        min_value = v;
+    }
+
+    double Slider::get_min_value() const {
+        return min_value;
+    }
+
+    void Slider::set_max_value(double v) {
+        max_value = v;
+    }
+
+    double Slider::get_max_value() const {
+        return max_value;
+    }
+
+    void Slider::set_step_value(double v) {
+        step_value = v;
+    }
+
+    double Slider::get_step_value() const {
+        return step_value;
+    }
+
+    void Slider::add_value_changed_callback(std::function callback) {
+        value_changed_callbacks.emplace_back(callback);
+    }
+
+} // namespace recompui
\ No newline at end of file
diff --git a/src/ui/elements/ui_slider.h b/src/ui/elements/ui_slider.h
new file mode 100644
index 0000000..74fb3b7
--- /dev/null
+++ b/src/ui/elements/ui_slider.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "ui_clickable.h"
+#include "ui_label.h"
+
+namespace recompui {
+    
+    enum SliderType {
+        Double,
+        Percent,
+        Integer
+    };
+
+    class Slider : public Element {
+    private:
+        SliderType type = SliderType::Percent;
+        Label *value_label = nullptr;
+        Element *slider_element = nullptr;
+        Clickable *bar_element = nullptr;
+        Clickable *circle_element = nullptr;
+        double value = 50.0;
+        double min_value = 0.0;
+        double max_value = 100.0;
+        double step_value = 1.0;
+        float slider_width_dp = 300.0;
+        std::vector> value_changed_callbacks;
+
+        void set_value_internal(double v, bool setup, bool trigger_callbacks);
+        void bar_clicked(float x, float y);
+        void bar_dragged(float x, float y, DragPhase phase);
+        void circle_dragged(float x, float y, DragPhase phase);
+        void update_value_from_mouse(float x);
+        void update_circle_position();
+        void update_label_text();
+
+    public:
+        Slider(SliderType type, Element *parent);
+        virtual ~Slider();
+        void set_value(double v);
+        double get_value() const;
+        void set_min_value(double v);
+        double get_min_value() const;
+        void set_max_value(double v);
+        double get_max_value() const;
+        void set_step_value(double v);
+        double get_step_value() const;
+        void add_value_changed_callback(std::function callback);
+    };
+
+} // namespace recompui
diff --git a/src/ui/elements/ui_style.cpp b/src/ui/elements/ui_style.cpp
index 1736501..57e5566 100644
--- a/src/ui/elements/ui_style.cpp
+++ b/src/ui/elements/ui_style.cpp
@@ -67,6 +67,24 @@ namespace recompui {
         }
     }
 
+    static Rml::Style::Drag to_rml(Drag drag) {
+        switch (drag) {
+        case Drag::None:
+            return Rml::Style::Drag::None;
+        case Drag::Drag:
+            return Rml::Style::Drag::Drag;
+        case Drag::DragDrop:
+            return Rml::Style::Drag::DragDrop;
+        case Drag::Block:
+            return Rml::Style::Drag::Block;
+        case Drag::Clone:
+            return Rml::Style::Drag::Clone;
+        default:
+            assert(false && "Unknown drag.");
+            return Rml::Style::Drag::None;
+        }
+    }
+
     void Style::set_property(Rml::PropertyId property_id, const Rml::Property &property, Animation) {
         property_map[property_id] = property;
     }
@@ -437,4 +455,8 @@ namespace recompui {
         set_property(Rml::PropertyId::ColumnGap, Rml::Property(size, to_rml(unit)), animation);
     }
 
+    void Style::set_drag(Drag drag) {
+        set_property(Rml::PropertyId::Drag, to_rml(drag), Animation());
+    }
+
 } // namespace recompui
\ No newline at end of file
diff --git a/src/ui/elements/ui_style.h b/src/ui/elements/ui_style.h
index 69f71a8..163a539 100644
--- a/src/ui/elements/ui_style.h
+++ b/src/ui/elements/ui_style.h
@@ -82,7 +82,7 @@ namespace recompui {
         void set_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
         void set_row_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
         void set_column_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
-
+        void set_drag(Drag drag);
         virtual bool is_element() { return false; }
         ResourceId get_resource_id() { return resource_id; }
     };
diff --git a/src/ui/elements/ui_toggle.cpp b/src/ui/elements/ui_toggle.cpp
index 5a4bcec..af26844 100644
--- a/src/ui/elements/ui_toggle.cpp
+++ b/src/ui/elements/ui_toggle.cpp
@@ -46,16 +46,16 @@ namespace recompui {
         floater->add_style(&floater_disabled_style, disabled_state);
         floater->add_style(&floater_disabled_checked_style, { checked_state, disabled_state });
 
-        set_checked_internal(false, false, true);
+        set_checked_internal(false, false, true, false);
     }
 
-    void Toggle::set_checked_internal(bool checked, bool animate, bool setup) {
+    void Toggle::set_checked_internal(bool checked, bool animate, bool setup, bool trigger_callbacks) {
         if (this->checked != checked || setup) {
             this->checked = checked;
 
             floater->set_left(floater_left_target(), Unit::Dp, animate ? Animation::tween(0.1f) : Animation::set());
 
-            if (!setup) {
+            if (trigger_callbacks) {
                 for (const auto &function : checked_callbacks) {
                     function(checked);
                 }
@@ -74,7 +74,7 @@ namespace recompui {
         switch (e.type) {
         case EventType::Click:
             if (is_enabled()) {
-                set_checked_internal(!checked, true, false);
+                set_checked_internal(!checked, true, false, true);
             }
 
             break;
@@ -93,7 +93,7 @@ namespace recompui {
     }
 
     void Toggle::set_checked(bool checked) {
-        set_checked_internal(checked, false, false);
+        set_checked_internal(checked, false, false, false);
     }
 
     bool Toggle::is_checked() const {
diff --git a/src/ui/elements/ui_toggle.h b/src/ui/elements/ui_toggle.h
index 2afcd9b..0f3eab5 100644
--- a/src/ui/elements/ui_toggle.h
+++ b/src/ui/elements/ui_toggle.h
@@ -18,7 +18,7 @@ namespace recompui {
         Style floater_disabled_checked_style;
         bool checked = false;
 
-        void set_checked_internal(bool checked, bool animate, bool setup);
+        void set_checked_internal(bool checked, bool animate, bool setup, bool trigger_callbacks);
         float floater_left_target() const;
 
         // Element overrides.
diff --git a/src/ui/elements/ui_types.h b/src/ui/elements/ui_types.h
index 36813fa..2726fe8 100644
--- a/src/ui/elements/ui_types.h
+++ b/src/ui/elements/ui_types.h
@@ -22,9 +22,17 @@ namespace recompui {
         Focus,
         Hover,
         Enable,
+        Drag,
         Count
     };
 
+    enum class DragPhase {
+        None,
+        Start,
+        Move,
+        End
+    };
+
     template >>
     constexpr uint32_t Events(Enum first) {
         return 1u << static_cast(first);
@@ -44,6 +52,8 @@ namespace recompui {
         EventType type;
 
         union {
+            uint64_t raw;
+
             struct {
                 Mouse mouse;
             } click;
@@ -59,6 +69,11 @@ namespace recompui {
             struct {
                 bool enable;
             } enable;
+
+            struct {
+                Mouse mouse;
+                DragPhase phase;
+            } drag;
         };
 
         static Event click_event(float x, float y) {
@@ -89,6 +104,15 @@ namespace recompui {
             e.enable.enable = enable;
             return e;
         }
+
+        static Event drag_event(float x, float y, DragPhase phase) {
+            Event e = {};
+            e.type = EventType::Drag;
+            e.drag.mouse.x = x;
+            e.drag.mouse.y = y;
+            e.drag.phase = phase;
+            return e;
+        }
     };
 
     enum class Display {
@@ -154,6 +178,14 @@ namespace recompui {
         Justify
     };
 
+    enum class Drag {
+        None,
+        Drag,
+        DragDrop,
+        Block,
+        Clone
+    };
+
     struct Animation {
         AnimationType type = AnimationType::None;
         float duration = 0.0f;
diff --git a/src/ui/ui_config_sub_menu.cpp b/src/ui/ui_config_sub_menu.cpp
new file mode 100644
index 0000000..735e569
--- /dev/null
+++ b/src/ui/ui_config_sub_menu.cpp
@@ -0,0 +1,200 @@
+#include "ui_config_sub_menu.h"
+
+#include 
+
+namespace recompui {
+
+// ConfigOptionElement
+
+
+void ConfigOptionElement::process_event(const Event &e) {
+    switch (e.type) {
+    case EventType::Hover:
+        hover_callback(this, e.hover.active);
+        break;
+    default:
+        assert(false && "Unknown event type.");
+        break;
+    }
+}
+
+ConfigOptionElement::ConfigOptionElement(Element *parent) : Element(parent, Events(EventType::Hover)) {
+    set_min_height(100.0f);
+
+    name_label = new Label(LabelStyle::Normal, this);
+}
+
+ConfigOptionElement::~ConfigOptionElement() {
+
+}
+
+void ConfigOptionElement::set_name(std::string_view name) {
+    this->name = name;
+    name_label->set_text(name);
+}
+
+void ConfigOptionElement::set_description(std::string_view description) {
+    this->description = description;
+}
+
+void ConfigOptionElement::set_hover_callback(std::function callback) {
+    hover_callback = callback;
+}
+
+const std::string &ConfigOptionElement::get_description() const {
+    return description;
+}
+
+// ConfigOptionSlider
+
+void ConfigOptionSlider::slider_value_changed(double v) {
+    // TODO: Hook up to whatever API Recomp exposes to set the value of the persisent configuration in mods.
+    printf("%s changed to %f.\n", name.c_str(), v);
+}
+
+ConfigOptionSlider::ConfigOptionSlider(Element *parent) : ConfigOptionElement(parent) {
+    slider = new Slider(SliderType::Percent, this);
+    slider->add_value_changed_callback(std::bind(&ConfigOptionSlider::slider_value_changed, this, std::placeholders::_1));
+}
+
+ConfigOptionSlider::~ConfigOptionSlider() {
+
+}
+
+void ConfigOptionSlider::set_value(double v) {
+    slider->set_value(v);
+}
+
+void ConfigOptionSlider::set_min_value(double v) {
+    slider->set_min_value(v);
+}
+
+void ConfigOptionSlider::set_max_value(double v) {
+    slider->set_max_value(v);
+}
+
+// ConfigSubMenu
+
+void ConfigSubMenu::back_button_pressed() {
+    if (quit_sub_menu_callback != nullptr) {
+        quit_sub_menu_callback();
+    }
+}
+
+void ConfigSubMenu::option_hovered(ConfigOptionElement *option, bool active) {
+    if (active) {
+        hover_option_elements.emplace(option);
+    }
+    else {
+        hover_option_elements.erase(option);
+    }
+
+    if (hover_option_elements.empty()) {
+        description_label->set_text("");
+    }
+    else {
+        description_label->set_text((*hover_option_elements.begin())->get_description());
+    }
+}
+
+ConfigSubMenu::ConfigSubMenu(Element *parent) : Element(parent) {
+    set_display(Display::Flex);
+    set_flex(1, 1, 100.0f, Unit::Percent);
+    set_flex_direction(FlexDirection::Column);
+    set_height(100.0f, Unit::Percent);
+
+    header_container = new Container(FlexDirection::Row, JustifyContent::FlexStart, this);
+
+    {
+        back_button = new Button("Back", ButtonStyle::Secondary, header_container);
+        back_button->add_pressed_callback(std::bind(&ConfigSubMenu::back_button_pressed, this));
+        title_label = new Label("Title", LabelStyle::Large, header_container);
+    }
+
+    body_container = new Container(FlexDirection::Row, JustifyContent::SpaceEvenly, this);
+    {
+        config_container = new Container(FlexDirection::Column, JustifyContent::Center, body_container);
+        config_container->set_display(Display::Block);
+        config_container->set_flex_basis(100.0f);
+        config_container->set_align_items(AlignItems::Center);
+        {
+            config_scroll_container = new ScrollContainer(ScrollDirection::Vertical, config_container);
+        }
+
+        description_label = new Label("Description", LabelStyle::Small, body_container);
+        description_label->set_min_width(800.0f);
+    }
+}
+
+ConfigSubMenu::~ConfigSubMenu() {
+
+}
+
+void ConfigSubMenu::enter(std::string_view title) {
+    title_label->set_text(title);
+
+    if (enter_sub_menu_callback != nullptr) {
+        enter_sub_menu_callback();
+    }
+}
+
+void ConfigSubMenu::clear_options() {
+    config_scroll_container->clear_children();
+    config_option_elements.clear();
+    hover_option_elements.clear();
+}
+
+void ConfigSubMenu::add_option(ConfigOptionElement *option, std::string_view name, std::string_view description) {
+    option->set_name(name);
+    option->set_description(description);
+    option->set_hover_callback(std::bind(&ConfigSubMenu::option_hovered, this, std::placeholders::_1, std::placeholders::_2));
+    config_option_elements.emplace_back(option);
+}
+
+void ConfigSubMenu::add_slider_option(std::string_view name, std::string_view description, double min, double max) {
+    ConfigOptionSlider *option_slider = new ConfigOptionSlider(config_scroll_container);
+    option_slider->set_min_value(min);
+    option_slider->set_max_value(max);
+    add_option(option_slider, name, description);
+}
+
+void ConfigSubMenu::set_enter_sub_menu_callback(std::function callback) {
+    enter_sub_menu_callback = callback;
+}
+
+void ConfigSubMenu::set_quit_sub_menu_callback(std::function callback) {
+    quit_sub_menu_callback = callback;
+}
+
+// ElementConfigSubMenu
+
+ElementConfigSubMenu::ElementConfigSubMenu(const Rml::String &tag) : Rml::Element(tag) {
+    SetProperty(Rml::PropertyId::Display, Rml::Style::Display::None);
+    SetProperty("width", "100%");
+    SetProperty("height", "100%");
+
+    recompui::Element this_compat(this);
+    config_sub_menu = std::make_unique(&this_compat);
+}
+
+ElementConfigSubMenu::~ElementConfigSubMenu() {
+
+}
+
+void ElementConfigSubMenu::set_display(bool display) {
+    SetProperty(Rml::PropertyId::Display, display ? Rml::Style::Display::Block : Rml::Style::Display::None);
+}
+
+void ElementConfigSubMenu::set_enter_sub_menu_callback(std::function callback) {
+    config_sub_menu->set_enter_sub_menu_callback(callback);
+}
+
+void ElementConfigSubMenu::set_quit_sub_menu_callback(std::function callback) {
+    config_sub_menu->set_quit_sub_menu_callback(callback);
+}
+
+ConfigSubMenu *ElementConfigSubMenu::get_config_sub_menu_element() const {
+    return config_sub_menu.get();
+}
+
+}
\ No newline at end of file
diff --git a/src/ui/ui_config_sub_menu.h b/src/ui/ui_config_sub_menu.h
new file mode 100644
index 0000000..627b915
--- /dev/null
+++ b/src/ui/ui_config_sub_menu.h
@@ -0,0 +1,85 @@
+#ifndef RECOMPUI_CONFIG_SUB_MENU_H
+#define RECOMPUI_CONFIG_SUB_MENU_H
+
+#include 
+
+#include "elements/ui_button.h"
+#include "elements/ui_container.h"
+#include "elements/ui_label.h"
+#include "elements/ui_scroll_container.h"
+#include "elements/ui_slider.h"
+
+namespace recompui {
+
+class ConfigOptionElement : public Element {
+protected:
+    Label *name_label = nullptr;
+    std::string name;
+    std::string description;
+    std::function hover_callback = nullptr;
+
+    virtual void process_event(const Event &e) override;
+public:
+    ConfigOptionElement(Element *parent);
+    virtual ~ConfigOptionElement();
+    void set_name(std::string_view name);
+    void set_description(std::string_view description);
+    void set_hover_callback(std::function callback);
+    const std::string &get_description() const;
+};
+
+class ConfigOptionSlider : public ConfigOptionElement {
+protected:
+    Slider *slider = nullptr;
+
+    void slider_value_changed(double v);
+public:
+    ConfigOptionSlider(Element *parent);
+    virtual ~ConfigOptionSlider();
+    void set_value(double v);
+    void set_min_value(double v);
+    void set_max_value(double v);
+};
+
+class ConfigSubMenu : public Element {
+private:
+    Container *header_container = nullptr;
+    Button *back_button = nullptr;
+    Label *title_label = nullptr;
+    Container *body_container = nullptr;
+    Label *description_label = nullptr;
+    Container *config_container = nullptr;
+    ScrollContainer *config_scroll_container = nullptr;
+    std::function enter_sub_menu_callback = nullptr;
+    std::function quit_sub_menu_callback = nullptr;
+    std::vector config_option_elements;
+    std::unordered_set hover_option_elements;
+
+    void back_button_pressed();
+    void option_hovered(ConfigOptionElement *option, bool active);
+    void add_option(ConfigOptionElement *option, std::string_view name, std::string_view description);
+
+public:
+    ConfigSubMenu(Element *parent);
+    virtual ~ConfigSubMenu();
+    void enter(std::string_view title);
+    void clear_options();
+    void add_slider_option(std::string_view name, std::string_view description, double min, double max);
+    void set_enter_sub_menu_callback(std::function callback);
+    void set_quit_sub_menu_callback(std::function callback);
+};
+
+class ElementConfigSubMenu : public Rml::Element {
+public:
+    ElementConfigSubMenu(const Rml::String &tag);
+    virtual ~ElementConfigSubMenu();
+    void set_display(bool display);
+    void set_enter_sub_menu_callback(std::function callback);
+    void set_quit_sub_menu_callback(std::function callback);
+    ConfigSubMenu *get_config_sub_menu_element() const;
+private:
+    std::unique_ptr config_sub_menu;
+};
+
+}
+#endif
\ No newline at end of file
diff --git a/src/ui/ui_elements.cpp b/src/ui/ui_elements.cpp
index da37998..1201e30 100644
--- a/src/ui/ui_elements.cpp
+++ b/src/ui/ui_elements.cpp
@@ -20,6 +20,7 @@ static RecompElementConfig custom_elements[] = {
     CUSTOM_ELEMENT("recomp-option-type-radio-tabs", recompui::ElementOptionTypeRadioTabs),
     CUSTOM_ELEMENT("recomp-option-type-range", recompui::ElementOptionTypeRange),
     CUSTOM_ELEMENT("recomp-mod-menu", recompui::ElementModMenu),
+    CUSTOM_ELEMENT("recomp-config-sub-menu", recompui::ElementConfigSubMenu),
 };
 
 void recompui::register_custom_elements() {
diff --git a/src/ui/ui_elements.h b/src/ui/ui_elements.h
index 854a0ff..6a9bfb4 100644
--- a/src/ui/ui_elements.h
+++ b/src/ui/ui_elements.h
@@ -15,6 +15,7 @@
 #include "elements/ElementOptionTypeTextField.h"
 #include "elements/ElementDescription.h"
 #include "ui_mod_menu.h"
+#include "ui_config_sub_menu.h"
 
 namespace recompui {
     void register_custom_elements();
diff --git a/src/ui/ui_mod_details_panel.cpp b/src/ui/ui_mod_details_panel.cpp
index 308da7a..87a9d68 100644
--- a/src/ui/ui_mod_details_panel.cpp
+++ b/src/ui/ui_mod_details_panel.cpp
@@ -59,6 +59,7 @@ ModDetailsPanel::ModDetailsPanel(Element *parent) : Element(parent) {
         enable_toggle = context.create_element(buttons_container);
         enable_toggle->add_checked_callback(std::bind(&ModDetailsPanel::enable_toggle_checked, this, std::placeholders::_1));
         configure_button = context.create_element