diff --git a/kayak_render_macros/src/widget_props.rs b/kayak_render_macros/src/widget_props.rs
index 7f64f6e653ab0e19e8c7643166bbe453870a3cfe..90ff6e4cc68e1e5c1c8f78d7fbcff8a3aa8c2e50 100644
--- a/kayak_render_macros/src/widget_props.rs
+++ b/kayak_render_macros/src/widget_props.rs
@@ -13,6 +13,7 @@ const PROPS_HELPER_IDENT: &str = "prop_field";
 const PROP_CHILDREN: &str = "Children";
 const PROP_STYLE: &str = "Styles";
 const PROP_ON_EVENT: &str = "OnEvent";
+const PROP_ON_LAYOUT: &str = "OnLayout";
 const PROP_FOCUSABLE: &str = "Focusable";
 
 #[derive(Default)]
@@ -20,6 +21,7 @@ struct PropsHelpers {
     children_ident: Option<Ident>,
     styles_ident: Option<Ident>,
     on_event_ident: Option<Ident>,
+    on_layout_ident: Option<Ident>,
     focusable_ident: Option<Ident>,
 }
 
@@ -43,6 +45,7 @@ pub(crate) fn impl_widget_props(input: TokenStream) -> TokenStream {
     let children_return = quote_clone_field(helpers.children_ident);
     let styles_return = quote_clone_field(helpers.styles_ident);
     let on_event_return = quote_clone_field(helpers.on_event_ident);
+    let on_layout_return = quote_clone_field(helpers.on_layout_ident);
     let focusable_return = quote_clone_field(helpers.focusable_ident);
 
     let kayak_core = get_core_crate();
@@ -65,6 +68,10 @@ pub(crate) fn impl_widget_props(input: TokenStream) -> TokenStream {
                 #on_event_return
             }
 
+            fn get_on_layout(&self) -> Option<#kayak_core::OnLayout> {
+                #on_layout_return
+            }
+
             fn get_focusable(&self) -> Option<bool> {
                 #focusable_return
             }
@@ -125,6 +132,7 @@ fn process_field(field: Field, props: &mut PropsHelpers) {
                             PROP_CHILDREN => props.children_ident = field.ident.clone(),
                             PROP_STYLE => props.styles_ident = field.ident.clone(),
                             PROP_ON_EVENT => props.on_event_ident = field.ident.clone(),
+                            PROP_ON_LAYOUT => props.on_layout_ident = field.ident.clone(),
                             PROP_FOCUSABLE => props.focusable_ident = field.ident.clone(),
                             err => emit_error!(err.span(), "Invalid attribute: {}", err),
                         }
diff --git a/src/widgets/button.rs b/src/widgets/button.rs
index e1c738f0c4894f4a6fba4e3db69d331b8471584e..d2373676d5364635670fbc2a80f1cc2fae8ec32d 100644
--- a/src/widgets/button.rs
+++ b/src/widgets/button.rs
@@ -2,7 +2,7 @@ use crate::core::{
     render_command::RenderCommand,
     rsx,
     styles::{Corner, Style, StyleProp, Units},
-    widget, Children, Color, Fragment, OnEvent, WidgetProps,
+    widget, Children, Color, Fragment, OnEvent, OnLayout, WidgetProps,
 };
 use kayak_core::CursorIcon;
 
@@ -17,6 +17,7 @@ pub struct ButtonProps {
     pub styles: Option<Style>,
     pub children: Option<Children>,
     pub on_event: Option<OnEvent>,
+    pub on_layout: Option<OnLayout>,
     pub focusable: Option<bool>,
 }
 
@@ -37,6 +38,10 @@ impl WidgetProps for ButtonProps {
         self.on_event.clone()
     }
 
+    fn get_on_layout(&self) -> Option<OnLayout> {
+        self.on_layout.clone()
+    }
+
     fn get_focusable(&self) -> Option<bool> {
         Some(!self.disabled)
     }
diff --git a/src/widgets/text_box.rs b/src/widgets/text_box.rs
index 34934c984510175922682330412f0f83c19afc22..321b1860ad0c64b366fc4a4b6be9fa4231041022 100644
--- a/src/widgets/text_box.rs
+++ b/src/widgets/text_box.rs
@@ -4,7 +4,7 @@ use crate::core::{
     styles::{Corner, Style, Units},
     widget, Bound, Children, Color, EventType, MutableBound, OnEvent, WidgetProps,
 };
-use kayak_core::CursorIcon;
+use kayak_core::{CursorIcon, OnLayout};
 use std::sync::{Arc, RwLock};
 
 use crate::widgets::{Background, Clip, Text};
@@ -26,6 +26,7 @@ pub struct TextBoxProps {
     pub styles: Option<Style>,
     pub children: Option<Children>,
     pub on_event: Option<OnEvent>,
+    pub on_layout: Option<OnLayout>,
     pub focusable: Option<bool>,
 }
 
@@ -46,6 +47,10 @@ impl WidgetProps for TextBoxProps {
         self.on_event.clone()
     }
 
+    fn get_on_layout(&self) -> Option<OnLayout> {
+        self.on_layout.clone()
+    }
+    
     fn get_focusable(&self) -> Option<bool> {
         Some(!self.disabled)
     }