diff --git a/examples/text_box.rs b/examples/text_box.rs
index 1cf61d279c5bffa72954da398a1e9a2bc56ac757..0c2efca20de855e65edf3915e280884b5cdca1f5 100644
--- a/examples/text_box.rs
+++ b/examples/text_box.rs
@@ -25,12 +25,12 @@ fn TextBoxExample(context: &mut KayakContext) {
     };
 
     let cloned_value = value.clone();
-    let on_change = OnChange::new(move |event| {
+    let on_change = OnChange::new_handler(move |event| {
         cloned_value.set(event.value);
     });
 
     let cloned_value2 = value2.clone();
-    let on_change2 = OnChange::new(move |event| {
+    let on_change2 = OnChange::new_handler(move |event| {
         cloned_value2.set(event.value);
     });
 
diff --git a/kayak_core/src/event.rs b/kayak_core/src/event.rs
index daf64a3b406742b288019e1daae368f42ed0e7d4..cf0bcf502873f246f2520734cc8f203ca97edc2f 100644
--- a/kayak_core/src/event.rs
+++ b/kayak_core/src/event.rs
@@ -49,9 +49,17 @@ pub struct ChangeEvent<T> {
 pub struct OnChange<T>(pub Arc<RwLock<dyn FnMut(ChangeEvent<T>) + Send + Sync + 'static>>);
 
 impl<T> OnChange<T> {
+    /// Create a new handler for a [ChangeEvent]
     pub fn new<F: FnMut(ChangeEvent<T>) + Send + Sync + 'static>(f: F) -> Self {
         Self(Arc::new(RwLock::new(f)))
     }
+
+    /// Send the given event to be handled by the current handler
+    pub fn send(&self, event: ChangeEvent<T>) {
+        if let Ok(mut on_change) = self.0.write() {
+            on_change(event);
+        }
+    }
 }
 
 impl<T> PartialEq for OnChange<T> {
diff --git a/kayak_widgets/src/text_box.rs b/kayak_widgets/src/text_box.rs
index 6a878f4146650590466c4b0f0f21a35210466186..41a090356f26ea7c01cb58c7f65becb2e4f352d5 100644
--- a/kayak_widgets/src/text_box.rs
+++ b/kayak_widgets/src/text_box.rs
@@ -47,11 +47,9 @@ pub fn TextBox(value: String, on_change: Option<OnChange<String>>) {
                 current_value.push(c);
             }
             if let Some(on_change) = cloned_on_change.as_ref() {
-                if let Ok(mut on_change) = on_change.0.write() {
-                    on_change(ChangeEvent {
-                        value: current_value.clone(),
-                    });
-                }
+                on_change.send(ChangeEvent {
+                    value: current_value.clone(),
+                });
             }
         }
         EventType::Focus => cloned_has_focus.set(Focus(true)),