diff --git a/loader/include/Geode/ui/InputNode.hpp b/loader/include/Geode/ui/InputNode.hpp
index a1d0e72e..9d18056f 100644
--- a/loader/include/Geode/ui/InputNode.hpp
+++ b/loader/include/Geode/ui/InputNode.hpp
@@ -5,7 +5,7 @@
 #include <cocos2d.h>
 
 namespace geode {
-    class GEODE_DLL [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]] InputNode : public cocos2d::CCMenuItem {
+    class GEODE_DLL InputNode : public cocos2d::CCMenuItem {
     protected:
         cocos2d::extension::CCScale9Sprite* m_bgSprite;
         CCTextInputNode* m_input;
@@ -14,15 +14,20 @@ namespace geode {
         bool init(float, char const*, char const*, std::string const&, int);
 
     public:
+        [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
         static InputNode* create(
             float width, char const* placeholder, char const* fontFile, std::string const& filter,
             int limit
         );
+        [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
         static InputNode* create(
             float width, char const* placeholder, std::string const& filter, int limit
         );
+        [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
         static InputNode* create(float width, char const* placeholder, std::string const& filter);
+        [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
         static InputNode* create(float width, char const* placeholder, char const* fontFile);
+        [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]]
         static InputNode* create(float width, char const* placeholder);
 
         void activate() override;
diff --git a/loader/include/Geode/ui/TextInput.hpp b/loader/include/Geode/ui/TextInput.hpp
index 86b59c18..aae8dc1d 100644
--- a/loader/include/Geode/ui/TextInput.hpp
+++ b/loader/include/Geode/ui/TextInput.hpp
@@ -99,6 +99,10 @@ namespace geode {
          * the text input
          */
         void setCallback(std::function<void(std::string const&)> onInput);
+        /**
+         * Enable/disable the input
+         */
+        void setEnabled(bool enabled);
 
         /**
          * Hides the background of this input. Shorthand for 
diff --git a/loader/src/ui/nodes/InputNode.cpp b/loader/src/ui/nodes/InputNode.cpp
index cc800623..08d49ca7 100644
--- a/loader/src/ui/nodes/InputNode.cpp
+++ b/loader/src/ui/nodes/InputNode.cpp
@@ -1,49 +1,10 @@
 #include <Geode/binding/CCTextInputNode.hpp>
 #include <Geode/binding/TextInputDelegate.hpp>
 #include <Geode/ui/InputNode.hpp>
+#include <Geode/ui/TextInput.hpp>
 
 using namespace geode::prelude;
 
-// rob only uses `CCTextInputNode`s in mostly-flat hierarchies, which still
-// happen to work with the weird vanilla code. this fix makes it work even in
-// deep hierarchies, because the vanilla code uses `getParent` and manually
-// calculates the child location in the world space based on that rather than
-// using `convertToNodeSpace`.
-static constexpr int INPUT_TAG = 0x80082;
-
-#include <Geode/modify/CCTextInputNode.hpp>
-
-struct TextInputNodeFix : Modify<TextInputNodeFix, CCTextInputNode> {
-    GEODE_FORWARD_COMPAT_DISABLE_HOOKS("TextInputNode fix")
-
-    bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) {
-        if (this->getTag() != INPUT_TAG) return CCTextInputNode::ccTouchBegan(touch, event);
-
-        if (!this->isVisible()) {
-            this->onClickTrackNode(false);
-            return false;
-        }
-
-        auto const touchPos = touch->getLocation();
-        auto const size = this->getContentSize();
-        auto const pos = this->convertToNodeSpace(touchPos) + m_textField->getAnchorPoint() * size;
-
-        if (pos.x < 0 || pos.x > size.width || pos.y < 0 || pos.y > size.height) {
-            this->onClickTrackNode(false);
-            return false;
-        }
-        if (m_delegate && !m_delegate->allowTextInput(this)) {
-            this->onClickTrackNode(false);
-            return false;
-        }
-
-        this->onClickTrackNode(true);
-        this->updateCursorPosition(touchPos, {{0, 0}, size});
-
-        return true;
-    }
-};
-
 std::string InputNode::getString() {
     return m_input->getString();
 }
@@ -94,7 +55,7 @@ bool InputNode::init(
     m_input->setMaxLabelScale(.85f);
     m_input->setMaxLabelLength(maxCharCount);
     m_input->setPosition(width / 2, height / 2);
-    m_input->setTag(INPUT_TAG);
+    m_input->setAttribute("fix-text-input", true);
     if (filter.length()) {
         m_input->setAllowedChars(filter);
     }
diff --git a/loader/src/ui/nodes/TextInput.cpp b/loader/src/ui/nodes/TextInput.cpp
index 582e5278..7672a047 100644
--- a/loader/src/ui/nodes/TextInput.cpp
+++ b/loader/src/ui/nodes/TextInput.cpp
@@ -1,9 +1,43 @@
 #include <Geode/binding/CCTextInputNode.hpp>
 #include <Geode/binding/TextInputDelegate.hpp>
+#include <Geode/modify/CCTextInputNode.hpp>
 #include <Geode/ui/TextInput.hpp>
 
 using namespace geode::prelude;
 
+struct TextInputNodeFix : Modify<TextInputNodeFix, CCTextInputNode> {
+    GEODE_FORWARD_COMPAT_DISABLE_HOOKS("TextInputNode fix")
+
+    bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) {
+        if (!this->template getAttribute<bool>("fix-text-input").value_or(false)) {
+            return CCTextInputNode::ccTouchBegan(touch, event);
+        }
+
+        if (!this->isVisible()) {
+            this->onClickTrackNode(false);
+            return false;
+        }
+
+        auto const touchPos = touch->getLocation();
+        auto const size = this->getContentSize();
+        auto const pos = this->convertToNodeSpace(touchPos) + m_textField->getAnchorPoint() * size;
+
+        if (pos.x < 0 || pos.x > size.width || pos.y < 0 || pos.y > size.height) {
+            this->onClickTrackNode(false);
+            return false;
+        }
+        if (m_delegate && !m_delegate->allowTextInput(this)) {
+            this->onClickTrackNode(false);
+            return false;
+        }
+
+        this->onClickTrackNode(true);
+        this->updateCursorPosition(touchPos, {{0, 0}, size});
+
+        return true;
+    }
+};
+
 const char* geode::getCommonFilterAllowedChars(CommonFilter filter) {
     switch (filter) {
         default:
@@ -35,14 +69,13 @@ bool TextInput::init(float width, std::string const& placeholder, std::string co
     m_bgSprite->setContentSize({ width * 2, HEIGHT * 2 });
     this->addChildAtPosition(m_bgSprite, cocos2d::Anchor::Center);
 
-    m_input = CCTextInputNode::create(width - 10.f, HEIGHT, placeholder.c_str(), "Thonburi", 24, font.c_str());
+    m_input = CCTextInputNode::create(width, HEIGHT, placeholder.c_str(), 24, font.c_str());
     m_input->setLabelPlaceholderColor({ 150, 150, 150 });
     m_input->setLabelPlaceholderScale(.6f);
     m_input->setMaxLabelScale(.6f);
+    m_input->setAttribute("fix-text-input", true);
     this->addChildAtPosition(m_input, cocos2d::Anchor::Center);
 
-    handleTouchPriority(this);
-
     return true;
 }
 
@@ -80,12 +113,12 @@ void TextInput::setPasswordMode(bool enable) {
     m_input->refreshLabel();
 }
 void TextInput::setWidth(float width) {
-    m_input->m_maxLabelWidth = width - 10;
+    m_input->m_maxLabelWidth = width;
     m_input->setContentWidth(width * 2);
     m_bgSprite->setContentWidth(width * 2);
 }
 void TextInput::setDelegate(TextInputDelegate* delegate, std::optional<int> tag) {
-    m_input->setDelegate(delegate);
+    m_input->m_delegate = delegate;
     m_onInput = nullptr;
     if (tag.has_value()) {
         m_input->setTag(tag.value());
@@ -95,6 +128,11 @@ void TextInput::setCallback(std::function<void(std::string const&)> onInput) {
     this->setDelegate(this);
     m_onInput = onInput;
 }
+void TextInput::setEnabled(bool enabled) {
+    m_input->setMouseEnabled(enabled);
+    m_input->setTouchEnabled(enabled);
+    m_input->m_placeholderLabel->setOpacity(enabled ? 255 : 150);
+}
 
 void TextInput::hideBG() {
     m_bgSprite->setVisible(false);