diff --git a/Cargo.lock b/Cargo.lock
index bbc321989e403b2db5d02c5661c6fbc247849184..e5d1b535b609e3667d57dad11da0f95362dba76c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1483,7 +1483,7 @@ checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e"
 [[package]]
 name = "flo_binding"
 version = "2.0.2"
-source = "git+https://github.com/StarArawn/flo_binding.git?rev=609883068c43dc897da2b277e91320a41892643d#609883068c43dc897da2b277e91320a41892643d"
+source = "git+https://github.com/StarArawn/flo_binding.git?rev=c78431a56df5ec082b7e1c271871e6c0ac75e81e#c78431a56df5ec082b7e1c271871e6c0ac75e81e"
 dependencies = [
  "desync",
  "flo_rope",
diff --git a/examples/counter.rs b/examples/counter.rs
index 08c0a73122f5f6021f92cac637bc2dc4224c8ed3..3bfe4dfc6c2f2b82bba241e37066464fe9ab15a6 100644
--- a/examples/counter.rs
+++ b/examples/counter.rs
@@ -5,13 +5,13 @@ use bevy::{
     PipelinedDefaultPlugins,
 };
 use bevy_kayak_ui::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle};
-use kayak_widgets::{Button, Text, Window};
 use kayak_core::{
     styles::{Style, StyleProp, Units},
     Bound, EventType, Index, MutableBound, OnEvent,
 };
 use kayak_ui::components::App;
 use kayak_ui::core::{rsx, widget};
+use kayak_widgets::{Button, Text, Window};
 
 #[widget]
 fn Counter(context: &mut KayakContext) {
diff --git a/kayak_core/Cargo.toml b/kayak_core/Cargo.toml
index 4a5cc1ad9f7a2e01fa272959713fe725777d0cb3..ff686156c313382ac0fae3ea31acd6802b30b6f9 100644
--- a/kayak_core/Cargo.toml
+++ b/kayak_core/Cargo.toml
@@ -10,7 +10,7 @@ as-any = "0.2"
 dashmap = "4.0"
 diff-struct = "0.3"
 derivative = "2.2"
-flo_binding = { git = "https://github.com/StarArawn/flo_binding.git", rev = "609883068c43dc897da2b277e91320a41892643d" }
+flo_binding = { git = "https://github.com/StarArawn/flo_binding.git", rev = "c78431a56df5ec082b7e1c271871e6c0ac75e81e" }
 fontdue = "0.6"
 kayak_render_macros = { path = "../kayak_render_macros" }
 morphorm = { git = "https://github.com/geom3trik/morphorm" }
diff --git a/kayak_core/src/context.rs b/kayak_core/src/context.rs
index b2a60ca9a7db86cf80f701c7e02266b3473c8c10..a5cd1c4c6f6c3b0af68a75e579e4340450c82136 100644
--- a/kayak_core/src/context.rs
+++ b/kayak_core/src/context.rs
@@ -4,9 +4,10 @@ use std::collections::HashMap;
 use crate::{node::NodeIndex, widget_manager::WidgetManager, Event, EventType, Index, InputEvent};
 
 pub struct KayakContext {
-    component_states: HashMap<crate::Index, resources::Resources>,
+    widget_states: HashMap<crate::Index, resources::Resources>,
     global_bindings: HashMap<crate::Index, Vec<flo_binding::Uuid>>,
-    // component_state_lifetimes: DashMap<crate::Index, Vec<Box<dyn crate::Releasable>>>,
+    widget_state_lifetimes:
+        HashMap<crate::Index, HashMap<flo_binding::Uuid, Box<dyn crate::Releasable>>>,
     current_id: Index,
     pub widget_manager: WidgetManager,
     last_mouse_position: (f32, f32),
@@ -25,9 +26,9 @@ impl std::fmt::Debug for KayakContext {
 impl KayakContext {
     pub fn new() -> Self {
         Self {
-            component_states: HashMap::new(),
+            widget_states: HashMap::new(),
             global_bindings: HashMap::new(),
-            // component_state_lifetimes: DashMap::new(),
+            widget_state_lifetimes: HashMap::new(),
             current_id: crate::Index::default(),
             widget_manager: WidgetManager::new(),
             last_mouse_position: (0.0, 0.0),
@@ -37,7 +38,7 @@ impl KayakContext {
     }
 
     /// Binds some global state to the current widget.
-    pub fn bind<T: Clone + PartialEq + Send + 'static>(
+    pub fn bind<T: Clone + PartialEq + Send + Sync + 'static>(
         &mut self,
         global_state: &crate::Binding<T>,
     ) {
@@ -50,18 +51,22 @@ impl KayakContext {
         if !global_binding_ids.contains(&global_state.id) {
             let cloned_id = self.current_id;
             let dirty_nodes = self.widget_manager.dirty_nodes.clone();
-            let mut lifetime = global_state.when_changed(crate::notify(move || {
+            let lifetime = global_state.when_changed(crate::notify(move || {
                 if let Ok(mut dirty_nodes) = dirty_nodes.lock() {
                     dirty_nodes.insert(cloned_id);
                 }
             }));
-            // TODO: Figure out how to store this so we can drop the lifetime on unbind.
-            lifetime.keep_alive();
+            Self::insert_state_lifetime(
+                &mut self.widget_state_lifetimes,
+                self.current_id,
+                global_state.id,
+                lifetime,
+            );
             global_binding_ids.push(global_state.id);
         }
     }
 
-    pub fn unbind<T: Clone + PartialEq + Send + 'static>(
+    pub fn unbind<T: Clone + PartialEq + Send + Sync + 'static>(
         &mut self,
         global_state: &crate::Binding<T>,
     ) {
@@ -72,6 +77,12 @@ impl KayakContext {
                 .position(|id| *id == global_state.id)
             {
                 global_binding_ids.remove(index);
+
+                Self::remove_state_lifetime(
+                    &mut self.widget_state_lifetimes,
+                    self.current_id,
+                    global_state.id,
+                );
             }
         }
     }
@@ -84,23 +95,23 @@ impl KayakContext {
         &mut self,
         initial_state: T,
     ) -> Option<crate::Binding<T>> {
-        if self.component_states.contains_key(&self.current_id) {
-            let states = self.component_states.get_mut(&self.current_id).unwrap();
+        if self.widget_states.contains_key(&self.current_id) {
+            let states = self.widget_states.get_mut(&self.current_id).unwrap();
             if !states.contains::<crate::Binding<T>>() {
                 let state = crate::bind(initial_state);
                 let dirty_nodes = self.widget_manager.dirty_nodes.clone();
                 let cloned_id = self.current_id;
-                let mut lifetime = state.when_changed(crate::notify(move || {
+                let lifetime = state.when_changed(crate::notify(move || {
                     if let Ok(mut dirty_nodes) = dirty_nodes.lock() {
                         dirty_nodes.insert(cloned_id);
                     }
                 }));
-                lifetime.keep_alive();
-                // Self::insert_state_lifetime(
-                //     &mut self.component_state_lifetimes,
-                //     self.current_id,
-                //     lifetime,
-                // );
+                Self::insert_state_lifetime(
+                    &mut self.widget_state_lifetimes,
+                    self.current_id,
+                    state.id,
+                    lifetime,
+                );
                 states.insert(state);
             }
         } else {
@@ -108,40 +119,66 @@ impl KayakContext {
             let state = crate::bind(initial_state);
             let dirty_nodes = self.widget_manager.dirty_nodes.clone();
             let cloned_id = self.current_id;
-            let mut lifetime = state.when_changed(crate::notify(move || {
+            let lifetime = state.when_changed(crate::notify(move || {
                 if let Ok(mut dirty_nodes) = dirty_nodes.lock() {
                     dirty_nodes.insert(cloned_id);
                 }
             }));
-            lifetime.keep_alive();
-            // Self::insert_state_lifetime(
-            //     &mut self.component_state_lifetimes,
-            //     self.current_id,
-            //     lifetime,
-            // );
+            Self::insert_state_lifetime(
+                &mut self.widget_state_lifetimes,
+                self.current_id,
+                state.id,
+                lifetime,
+            );
             states.insert(state);
-            self.component_states.insert(self.current_id, states);
+            self.widget_states.insert(self.current_id, states);
         }
         return self.get_state();
     }
 
-    // fn insert_state_lifetime(
-    //     lifetimes: &mut DashMap<crate::Index, Vec<Box<dyn crate::Releasable>>>,
-    //     id: Index,
-    //     lifetime: Box<dyn crate::Releasable>,
-    // ) {
-    //     if lifetimes.contains_key(&id) {
-    //         if let Some(mut lifetimes) = lifetimes.get_mut(&id) {
-    //             lifetimes.push(lifetime);
-    //         }
-    //     } else {
-    //         lifetimes.insert(id, vec![lifetime]);
-    //     }
-    // }
+    fn insert_state_lifetime(
+        lifetimes: &mut HashMap<
+            crate::Index,
+            HashMap<flo_binding::Uuid, Box<dyn crate::Releasable>>,
+        >,
+        id: Index,
+        binding_id: flo_binding::Uuid,
+        lifetime: Box<dyn crate::Releasable>,
+    ) {
+        if lifetimes.contains_key(&id) {
+            if let Some(lifetimes) = lifetimes.get_mut(&id) {
+                if !lifetimes.contains_key(&binding_id) {
+                    lifetimes.insert(binding_id, lifetime);
+                }
+            }
+        } else {
+            let mut new_hashmap = HashMap::new();
+            new_hashmap.insert(binding_id, lifetime);
+            lifetimes.insert(id, new_hashmap);
+        }
+    }
+
+    fn remove_state_lifetime(
+        lifetimes: &mut HashMap<
+            crate::Index,
+            HashMap<flo_binding::Uuid, Box<dyn crate::Releasable>>,
+        >,
+        id: Index,
+        binding_id: flo_binding::Uuid,
+    ) {
+        if lifetimes.contains_key(&id) {
+            if let Some(lifetimes) = lifetimes.get_mut(&id) {
+                if lifetimes.contains_key(&binding_id) {
+                    let mut binding_lifetime = lifetimes.remove(&binding_id).unwrap();
+                    binding_lifetime.done();
+                }
+            }
+        }
+    }
 
     fn get_state<T: resources::Resource + Clone + PartialEq>(&self) -> Option<T> {
-        if self.component_states.contains_key(&self.current_id) {
-            let states = self.component_states.get(&self.current_id).unwrap();
+        if self.widget_states.contains_key(&self.current_id) {
+            let states = self.widget_states.get(&self.current_id).unwrap();
             if let Ok(state) = states.get::<T>() {
                 return Some(state.clone());
             }