diff --git a/examples/basic_sprite.rs b/examples/basic_sprite.rs
index e01b4455bd6a84e7b915f29f4e1ebb6f57b6ed25..29b8b93c39573cb4d4fcdfb0b9c96e1571c5a4d9 100644
--- a/examples/basic_sprite.rs
+++ b/examples/basic_sprite.rs
@@ -1,7 +1,7 @@
 use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow};
 use bevy_cosmic_edit::{
-    AttrsOwned, CosmicAttrs, CosmicEditPlugin, CosmicEditSpriteBundle, CosmicFontConfig,
-    CosmicMetrics, CosmicText, CosmicTextPosition, Focus,
+    AttrsOwned, CosmicAttrs, CosmicEditBundle, CosmicEditPlugin, CosmicFontConfig, CosmicMetrics,
+    CosmicText, CosmicTextPosition, Focus,
 };
 
 fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
@@ -20,21 +20,26 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
 
     let scale_factor = primary_window.scale_factor() as f32;
 
-    let cosmic_edit = CosmicEditSpriteBundle {
-        sprite: Sprite {
-            custom_size: Some(Vec2::new(primary_window.width(), primary_window.height())),
+    let cosmic_edit = (
+        CosmicEditBundle {
+            metrics: CosmicMetrics {
+                font_size: 14.,
+                line_height: 18.,
+                scale_factor,
+            },
+            text_position: CosmicTextPosition::Center,
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
             ..default()
         },
-        cosmic_metrics: CosmicMetrics {
-            font_size: 14.,
-            line_height: 18.,
-            scale_factor,
+        SpriteBundle {
+            sprite: Sprite {
+                custom_size: Some(Vec2::new(primary_window.width(), primary_window.height())),
+                ..default()
+            },
+            ..default()
         },
-        text_position: CosmicTextPosition::Center,
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        ..default()
-    };
+    );
 
     let cosmic_edit = commands.spawn(cosmic_edit).id();
 
diff --git a/examples/basic_ui.rs b/examples/basic_ui.rs
index f02ab728750a7c1210da1cd9df62a2987d5c1e1c..663028375c25063e0ad588afff05714d6fb73282 100644
--- a/examples/basic_ui.rs
+++ b/examples/basic_ui.rs
@@ -1,7 +1,7 @@
 use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow};
 use bevy_cosmic_edit::{
-    AttrsOwned, CosmicAttrs, CosmicEditPlugin, CosmicEditUiBundle, CosmicEditor, CosmicFontConfig,
-    CosmicMetrics, CosmicText, CosmicTextPosition, Focus,
+    AttrsOwned, CosmicAttrs, CosmicEditBundle, CosmicEditPlugin, CosmicEditUiBundle, CosmicEditor,
+    CosmicFontConfig, CosmicMetrics, CosmicText, CosmicTextPosition, Focus,
 };
 
 fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
@@ -20,22 +20,31 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
 
     let scale_factor = primary_window.scale_factor() as f32;
 
-    let cosmic_edit = CosmicEditUiBundle {
-        style: Style {
-            width: Val::Percent(100.),
-            height: Val::Percent(100.),
+    let cosmic_edit = (
+        CosmicEditBundle {
+            metrics: CosmicMetrics {
+                font_size: 14.,
+                line_height: 18.,
+                scale_factor,
+            },
+            text_position: CosmicTextPosition::Center,
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
             ..default()
         },
-        cosmic_metrics: CosmicMetrics {
-            font_size: 14.,
-            line_height: 18.,
-            scale_factor,
+        CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                style: Style {
+                    width: Val::Percent(100.),
+                    height: Val::Percent(100.),
+                    ..default()
+                },
+                background_color: Color::WHITE.into(),
+                ..default()
+            },
+            ..default()
         },
-        text_position: CosmicTextPosition::Center,
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        ..default()
-    };
+    );
 
     let cosmic_edit = commands.spawn(cosmic_edit).id();
 
diff --git a/examples/bevy_api_testing.rs b/examples/bevy_api_testing.rs
index f51ff48c77107186d6925db5da1fa5e6cf9bc194..4d1b1a872000a8d5e7271094e2f09c8710c9fb51 100644
--- a/examples/bevy_api_testing.rs
+++ b/examples/bevy_api_testing.rs
@@ -5,37 +5,53 @@ fn setup(mut commands: Commands) {
     commands.spawn(Camera2dBundle::default());
 
     // spawn a new CosmicEditBundle
-    commands.spawn(CosmicEditUiBundle {
-        style: Style {
-            // Size and position of text box
-            width: Val::Px(300.),
-            height: Val::Px(50.),
-            left: Val::Px(100.),
-            top: Val::Px(100.),
+    let ui_editor = commands
+        .spawn(CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(
+                Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)),
+            )),
+            max_lines: CosmicMaxLines(1),
             ..default()
-        },
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(
-            Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)),
-        )),
-        max_lines: CosmicMaxLines(1),
-        placeholder_setter: PlaceholderText(CosmicText::OneStyle("Place held :)".into())),
-        ..default()
-    });
+        })
+        .insert(CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                style: Style {
+                    // Size and position of text box
+                    width: Val::Px(300.),
+                    height: Val::Px(50.),
+                    left: Val::Px(100.),
+                    top: Val::Px(100.),
+                    ..default()
+                },
+                // needs to be set to prevent a bug where nothing is displayed
+                background_color: BackgroundColor(Color::WHITE),
+                ..default()
+            },
+            ..default()
+        })
+        .insert(CosmicEditPlaceholderBundle {
+            text_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())),
+            attrs: PlaceholderAttrs(AttrsOwned::new(
+                Attrs::new().color(bevy_color_to_cosmic(Color::rgb_u8(128, 128, 128))),
+            )),
+        })
+        .id();
 
-    let sprite_editor = commands
-        .spawn(CosmicEditSpriteBundle {
+    commands.spawn((
+        CosmicEditBundle { ..default() },
+        SpriteBundle {
+            // Sets size of text box
             sprite: Sprite {
-                // Sets size of text box
                 custom_size: Some(Vec2::new(300., 100.)),
                 ..default()
             },
             // Position of text box
-            transform: Transform::from_xyz(100., 200., 0.),
+            transform: Transform::from_xyz(0., 100., 0.),
             ..default()
-        })
-        .id();
+        },
+    ));
 
-    commands.insert_resource(Focus(Some(sprite_editor)));
+    commands.insert_resource(Focus(Some(ui_editor)));
 }
 
 fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> CosmicColor {
diff --git a/examples/every_option.rs b/examples/every_option.rs
index c2330f32a43203c6436fb5c6316965fb489339dd..edc58f29331db5dfa00be72f9843e811b8eb3c18 100644
--- a/examples/every_option.rs
+++ b/examples/every_option.rs
@@ -1,4 +1,4 @@
-use bevy::{prelude::*, ui::FocusPolicy, window::PrimaryWindow};
+use bevy::{prelude::*, window::PrimaryWindow};
 use bevy_cosmic_edit::*;
 
 #[derive(Resource)]
@@ -12,33 +12,12 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
     let primary_window = windows.single();
 
     let editor = commands
-        .spawn(CosmicEditUiBundle {
-            node: Node::default(),
-            button: Button,
-            visibility: Visibility::Visible,
-            computed_visibility: ComputedVisibility::default(),
-            z_index: ZIndex::default(),
-            image: UiImage::default(),
-            transform: Transform::default(),
-            interaction: Interaction::default(),
-            focus_policy: FocusPolicy::default(),
+        .spawn(CosmicEditBundle {
             text_position: CosmicTextPosition::default(),
             fill_color: FillColor::default(),
-            background_color: BackgroundColor::default(),
-            global_transform: GlobalTransform::default(),
             background_image: CosmicBackground::default(),
-            border_color: Color::LIME_GREEN.into(),
-            style: Style {
-                // Size and position of text box
-                border: UiRect::all(Val::Px(4.)),
-                width: Val::Percent(20.),
-                height: Val::Px(50.),
-                left: Val::Percent(40.),
-                top: Val::Px(100.),
-                ..default()
-            },
-            cosmic_attrs: CosmicAttrs(attrs.clone()),
-            cosmic_metrics: CosmicMetrics {
+            attrs: CosmicAttrs(attrs.clone()),
+            metrics: CosmicMetrics {
                 font_size: 16.,
                 line_height: 16.,
                 scale_factor: primary_window.scale_factor() as f32,
@@ -47,8 +26,28 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
             max_lines: CosmicMaxLines(1),
             text_setter: CosmicText::OneStyle("BANANA IS THE CODEWORD!".into()),
             mode: CosmicMode::Wrap,
-            placeholder_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())),
-            placeholder_attrs: PlaceholderAttrs(AttrsOwned::new(
+            canvas: Default::default(),
+        })
+        .insert(CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                border_color: Color::LIME_GREEN.into(),
+                style: Style {
+                    // Size and position of text box
+                    border: UiRect::all(Val::Px(4.)),
+                    width: Val::Percent(20.),
+                    height: Val::Px(50.),
+                    left: Val::Percent(40.),
+                    top: Val::Px(100.),
+                    ..default()
+                },
+                background_color: Color::WHITE.into(),
+                ..default()
+            },
+            ..default()
+        })
+        .insert(CosmicEditPlaceholderBundle {
+            text_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())),
+            attrs: PlaceholderAttrs(AttrsOwned::new(
                 Attrs::new().color(CosmicColor::rgb(88, 88, 88)),
             )),
         })
diff --git a/examples/font_per_widget.rs b/examples/font_per_widget.rs
index 6a628051d9bd3f89226ffc19f3d5e1dfacee2969..fa74f1e11d09a4bec30607baa8d5831d92b6d900 100644
--- a/examples/font_per_widget.rs
+++ b/examples/font_per_widget.rs
@@ -207,45 +207,61 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
         )],
     ];
 
-    let cosmic_edit_1 = CosmicEditUiBundle {
-        text_position: bevy_cosmic_edit::CosmicTextPosition::Center,
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        cosmic_metrics: CosmicMetrics {
-            font_size: 18.,
-            line_height: 22.,
-            scale_factor: primary_window.scale_factor() as f32,
+    let cosmic_edit_1 = (
+        CosmicEditBundle {
+            text_position: bevy_cosmic_edit::CosmicTextPosition::Center,
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            metrics: CosmicMetrics {
+                font_size: 18.,
+                line_height: 22.,
+                scale_factor: primary_window.scale_factor() as f32,
+            },
+            text_setter: CosmicText::MultiStyle(lines),
+            ..default()
         },
-        style: Style {
-            width: Val::Percent(50.),
-            height: Val::Percent(100.),
+        CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                style: Style {
+                    width: Val::Percent(50.),
+                    height: Val::Percent(100.),
+                    ..default()
+                },
+                background_color: BackgroundColor(Color::WHITE),
+                ..default()
+            },
             ..default()
         },
-        background_color: BackgroundColor(Color::WHITE),
-        text_setter: CosmicText::MultiStyle(lines),
-        ..default()
-    };
+    );
 
     let mut attrs_2 = Attrs::new();
     attrs_2 = attrs_2.family(Family::Name("Times New Roman"));
     attrs_2.color_opt = Some(bevy_color_to_cosmic(Color::PURPLE));
 
-    let cosmic_edit_2 = CosmicEditUiBundle {
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs_2)),
-        cosmic_metrics: CosmicMetrics {
-            font_size: 28.,
-            line_height: 36.,
-            scale_factor: primary_window.scale_factor() as f32,
+    let cosmic_edit_2 = (
+        CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(attrs_2)),
+            metrics: CosmicMetrics {
+                font_size: 28.,
+                line_height: 36.,
+                scale_factor: primary_window.scale_factor() as f32,
+            },
+            text_position: CosmicTextPosition::Center,
+            text_setter: CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()),
+            ..default()
         },
-        text_position: CosmicTextPosition::Center,
-        background_color: BackgroundColor(Color::WHITE.with_a(0.8)),
-        style: Style {
-            width: Val::Percent(50.),
-            height: Val::Percent(100.),
+        CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                background_color: BackgroundColor(Color::WHITE.with_a(0.8)),
+                style: Style {
+                    width: Val::Percent(50.),
+                    height: Val::Percent(100.),
+                    ..default()
+                },
+                ..default()
+            },
             ..default()
         },
-        text_setter: CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()),
-        ..default()
-    };
+    );
 
     let mut id = None;
     // Spawn the CosmicEditUiBundles as children of root
diff --git a/examples/image_background.rs b/examples/image_background.rs
index cdc9d7d7e9de22dc87cd0a785e34ad108d51de14..8f2d994a75221744da1b6caf241d86a32bd76fd8 100644
--- a/examples/image_background.rs
+++ b/examples/image_background.rs
@@ -7,21 +7,28 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
     let bg_image_handle = asset_server.load("img/bevy_logo_light.png");
 
     let editor = commands
-        .spawn(CosmicEditUiBundle {
-            style: Style {
-                // Size and position of text box
-                width: Val::Px(300.),
-                height: Val::Px(50.),
-                left: Val::Px(100.),
-                top: Val::Px(100.),
-                ..default()
-            },
-            cosmic_attrs: CosmicAttrs(AttrsOwned::new(
+        .spawn(CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(
                 Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)),
             )),
             background_image: CosmicBackground(Some(bg_image_handle)),
             ..default()
         })
+        .insert(CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                style: Style {
+                    // Size and position of text box
+                    width: Val::Px(300.),
+                    height: Val::Px(50.),
+                    left: Val::Px(100.),
+                    top: Val::Px(100.),
+                    ..default()
+                },
+                background_color: Color::WHITE.into(),
+                ..default()
+            },
+            ..default()
+        })
         .id();
     commands.insert_resource(Focus(Some(editor)));
 }
diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs
index 1f1942be689b4538f580fd50bb1cd104fe5a8af1..dc2f06fce6b10f7554659058ba95541eb3957824 100644
--- a/examples/multiple_sprites.rs
+++ b/examples/multiple_sprites.rs
@@ -20,43 +20,53 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
         scale_factor: primary_window.scale_factor() as f32,
     };
 
-    let cosmic_edit_1 = CosmicEditSpriteBundle {
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        cosmic_metrics: metrics.clone(),
-        sprite: Sprite {
-            custom_size: Some(Vec2 {
-                x: primary_window.width() / 2.,
-                y: primary_window.height(),
-            }),
+    let cosmic_edit_1 = (
+        CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            metrics: metrics.clone(),
+            text_position: CosmicTextPosition::Center,
+            fill_color: FillColor(Color::ALICE_BLUE),
+            text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
             ..default()
         },
-        transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)),
-        text_position: CosmicTextPosition::Center,
-        fill_color: FillColor(Color::ALICE_BLUE),
-        text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        ..default()
-    };
+        SpriteBundle {
+            sprite: Sprite {
+                custom_size: Some(Vec2 {
+                    x: primary_window.width() / 2.,
+                    y: primary_window.height(),
+                }),
+                ..default()
+            },
+            transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)),
+            ..default()
+        },
+    );
 
-    let cosmic_edit_2 = CosmicEditSpriteBundle {
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        cosmic_metrics: metrics,
-        sprite: Sprite {
-            custom_size: Some(Vec2 {
-                x: primary_window.width() / 2.,
-                y: primary_window.height() / 2.,
-            }),
+    let cosmic_edit_2 = (
+        CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            metrics,
+            text_position: CosmicTextPosition::Center,
+            fill_color: FillColor(Color::GRAY.with_a(0.5)),
+            text_setter: CosmicText::OneStyle("Widget_2. Click on me".to_string()),
             ..default()
         },
-        transform: Transform::from_translation(Vec3::new(
-            primary_window.width() / 4.,
-            -primary_window.height() / 4.,
-            1.,
-        )),
-        text_position: CosmicTextPosition::Center,
-        fill_color: FillColor(Color::GRAY.with_a(0.5)),
-        text_setter: CosmicText::OneStyle("Widget_2. Click on me".to_string()),
-        ..default()
-    };
+        SpriteBundle {
+            sprite: Sprite {
+                custom_size: Some(Vec2 {
+                    x: primary_window.width() / 2.,
+                    y: primary_window.height() / 2.,
+                }),
+                ..default()
+            },
+            transform: Transform::from_translation(Vec3::new(
+                primary_window.width() / 4.,
+                -primary_window.height() / 4.,
+                1.,
+            )),
+            ..default()
+        },
+    );
 
     let id = commands.spawn(cosmic_edit_1).id();
 
diff --git a/examples/readonly.rs b/examples/readonly.rs
index 58035b7af7b16c5514a4f19aa06e21cceb450146..118cdfe6001ac0f984a162ac7c70edc7690d2dad 100644
--- a/examples/readonly.rs
+++ b/examples/readonly.rs
@@ -20,23 +20,31 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) {
     attrs = attrs.family(Family::Name("Victor Mono"));
     attrs = attrs.color(bevy_color_to_cosmic(Color::PURPLE));
 
-    let cosmic_edit = CosmicEditUiBundle {
-        style: Style {
-            width: Val::Percent(100.),
-            height: Val::Percent(100.),
+    let cosmic_edit = (
+        CosmicEditBundle {
+            attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+            text_position: CosmicTextPosition::Center,
+            metrics: CosmicMetrics {
+                font_size: 14.,
+                line_height: 18.,
+                scale_factor: primary_window.scale_factor() as f32,
+            },
+            text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y\nRead only widget".to_string()),
             ..default()
         },
-        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
-        text_position: CosmicTextPosition::Center,
-        background_color: BackgroundColor(Color::WHITE),
-        cosmic_metrics: CosmicMetrics {
-            font_size: 14.,
-            line_height: 18.,
-            scale_factor: primary_window.scale_factor() as f32,
+        CosmicEditUiBundle {
+            node_bundle: NodeBundle {
+                style: Style {
+                    width: Val::Percent(100.),
+                    height: Val::Percent(100.),
+                    ..default()
+                },
+                background_color: BackgroundColor(Color::WHITE),
+                ..default()
+            },
+            ..default()
         },
-        text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y\nRead only widget".to_string()),
-        ..default()
-    };
+    );
 
     let mut id = None;
     // Spawn the CosmicEditUiBundle as a child of root
diff --git a/examples/text_input.rs b/examples/text_input.rs
index f031b9816e67116894deab1d2bba2f70d2e9ccb8..0b0f45ec045683ece8da63a4e3839be8bbb28294 100644
--- a/examples/text_input.rs
+++ b/examples/text_input.rs
@@ -10,30 +10,41 @@ fn create_editable_widget(commands: &mut Commands, scale_factor: f32, text: Stri
     let placeholder_attrs =
         AttrsOwned::new(Attrs::new().color(bevy_color_to_cosmic(Color::hex("#e6e6e6").unwrap())));
     commands
-        .spawn(CosmicEditUiBundle {
-            border_color: Color::hex("#ededed").unwrap().into(),
-            style: Style {
-                border: UiRect::all(Val::Px(3.)),
-                width: Val::Percent(20.),
-                height: Val::Px(50.),
-                left: Val::Percent(40.),
-                top: Val::Px(100.),
+        .spawn((
+            CosmicEditBundle {
+                attrs: CosmicAttrs(attrs.clone()),
+                metrics: CosmicMetrics {
+                    font_size: 18.,
+                    line_height: 18. * 1.2,
+                    scale_factor,
+                },
+                max_lines: CosmicMaxLines(1),
+                text_setter: CosmicText::OneStyle(text),
+                text_position: CosmicTextPosition::Left { padding: 20 },
+                mode: CosmicMode::InfiniteLine,
                 ..default()
             },
-            cosmic_attrs: CosmicAttrs(attrs.clone()),
-            cosmic_metrics: CosmicMetrics {
-                font_size: 18.,
-                line_height: 18. * 1.2,
-                scale_factor,
+            CosmicEditUiBundle {
+                node_bundle: NodeBundle {
+                    border_color: Color::hex("#ededed").unwrap().into(),
+                    style: Style {
+                        border: UiRect::all(Val::Px(3.)),
+                        width: Val::Percent(20.),
+                        height: Val::Px(50.),
+                        left: Val::Percent(40.),
+                        top: Val::Px(100.),
+                        ..default()
+                    },
+                    background_color: Color::WHITE.into(),
+                    ..default()
+                },
+                ..default()
             },
-            max_lines: CosmicMaxLines(1),
-            text_setter: CosmicText::OneStyle(text),
-            text_position: CosmicTextPosition::Left { padding: 20 },
-            mode: CosmicMode::InfiniteLine,
-            placeholder_setter: PlaceholderText(CosmicText::OneStyle("Type something...".into())),
-            placeholder_attrs: PlaceholderAttrs(placeholder_attrs.clone()),
-            ..default()
-        })
+            CosmicEditPlaceholderBundle {
+                text_setter: PlaceholderText(CosmicText::OneStyle("Type something...".into())),
+                attrs: PlaceholderAttrs(placeholder_attrs.clone()),
+            },
+        ))
         .id()
 }
 
@@ -42,18 +53,9 @@ fn create_readonly_widget(commands: &mut Commands, scale_factor: f32, text: Stri
         AttrsOwned::new(Attrs::new().color(bevy_color_to_cosmic(Color::hex("4d4d4d").unwrap())));
     commands
         .spawn((
-            CosmicEditUiBundle {
-                border_color: Color::hex("#ededed").unwrap().into(),
-                style: Style {
-                    border: UiRect::all(Val::Px(3.)),
-                    width: Val::Percent(20.),
-                    height: Val::Px(50.),
-                    left: Val::Percent(40.),
-                    top: Val::Px(100.),
-                    ..default()
-                },
-                cosmic_attrs: CosmicAttrs(attrs.clone()),
-                cosmic_metrics: CosmicMetrics {
+            CosmicEditBundle {
+                attrs: CosmicAttrs(attrs.clone()),
+                metrics: CosmicMetrics {
                     font_size: 18.,
                     line_height: 18. * 1.2,
                     scale_factor,
@@ -63,6 +65,22 @@ fn create_readonly_widget(commands: &mut Commands, scale_factor: f32, text: Stri
                 mode: CosmicMode::AutoHeight,
                 ..default()
             },
+            CosmicEditUiBundle {
+                node_bundle: NodeBundle {
+                    border_color: Color::hex("#ededed").unwrap().into(),
+                    style: Style {
+                        border: UiRect::all(Val::Px(3.)),
+                        width: Val::Percent(20.),
+                        height: Val::Px(50.),
+                        left: Val::Percent(40.),
+                        top: Val::Px(100.),
+                        ..default()
+                    },
+                    background_color: Color::WHITE.into(),
+                    ..default()
+                },
+                ..default()
+            },
             ReadOnly,
         ))
         .id()
diff --git a/src/lib.rs b/src/lib.rs
index 20c7fe4d8d13dddea0e05b22432188ccd31131e8..2df1bc8c3498a3d96f506ab77a9bd9df5b923311 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,9 +6,7 @@ mod render;
 
 use std::{collections::VecDeque, path::PathBuf};
 
-use bevy::{
-    prelude::*, render::texture::DEFAULT_IMAGE_HANDLE, transform::TransformSystem, ui::FocusPolicy,
-};
+use bevy::{prelude::*, render::texture::DEFAULT_IMAGE_HANDLE, transform::TransformSystem};
 pub use cosmic_text::{
     Action, Attrs, AttrsOwned, Color as CosmicColor, Cursor, Edit, Family, Style as FontStyle,
     Weight as FontWeight,
@@ -209,156 +207,58 @@ impl Default for PlaceholderAttrs {
         Self(AttrsOwned::new(Attrs::new()))
     }
 }
-#[derive(Bundle)]
-pub struct CosmicEditUiBundle {
-    // Bevy UI bits
-    /// Describes the logical size of the node
-    pub node: Node,
-    /// Marker component that signals this node is a button
-    pub button: Button,
-    /// Styles which control the layout (size and position) of the node and it's children
-    /// In some cases these styles also affect how the node drawn/painted.
-    pub style: Style,
-    /// Describes whether and how the button has been interacted with by the input
-    pub interaction: Interaction,
-    /// Whether this node should block interaction with lower nodes
-    pub focus_policy: FocusPolicy,
-    /// UiNode Background Color, works as a tint.
-    pub background_color: BackgroundColor,
-    /// The background color, which serves as a "fill" for this node
-    pub fill_color: FillColor,
-    /// The color of the Node's border
-    pub border_color: BorderColor,
-    /// This is used as the cosmic text canvas
-    pub image: UiImage,
-    /// The transform of the node
-    ///
-    /// This field is automatically managed by the UI layout system.
-    /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
-    pub transform: Transform,
-    /// The global transform of the node
-    ///
-    /// This field is automatically managed by the UI layout system.
-    /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
-    pub global_transform: GlobalTransform,
-    /// Describes the visibility properties of the node
-    pub visibility: Visibility,
-    /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
-    pub computed_visibility: ComputedVisibility,
-    /// Indicates the depth at which the node should appear in the UI
-    pub z_index: ZIndex,
-    // cosmic bits
-    /// text positioning enum
-    pub text_position: CosmicTextPosition,
-    /// text metrics
-    pub cosmic_metrics: CosmicMetrics,
-    /// text attributes
-    pub cosmic_attrs: CosmicAttrs,
-    /// bg img
-    pub background_image: CosmicBackground,
-    /// How many lines are allowed in buffer, 0 for no limit
-    pub max_lines: CosmicMaxLines,
-    /// How many characters are allowed in buffer, 0 for no limit
-    pub max_chars: CosmicMaxChars,
-    /// Setting this will update the buffer's text
-    pub text_setter: CosmicText,
-    /// Text input mode
-    pub mode: CosmicMode,
-    /// Setting this will update the placeholder text
-    pub placeholder_setter: PlaceholderText,
-    pub placeholder_attrs: PlaceholderAttrs,
-}
 
-impl Default for CosmicEditUiBundle {
+#[derive(Component)]
+pub struct CosmicCanvas(pub Handle<Image>);
+
+impl Default for CosmicCanvas {
     fn default() -> Self {
-        Self {
-            focus_policy: FocusPolicy::Block,
-            node: Default::default(),
-            button: Default::default(),
-            style: Default::default(),
-            border_color: BorderColor(Color::NONE),
-            interaction: Default::default(),
-            fill_color: Default::default(),
-            image: Default::default(),
-            transform: Default::default(),
-            global_transform: Default::default(),
-            visibility: Default::default(),
-            computed_visibility: Default::default(),
-            z_index: Default::default(),
-            text_position: Default::default(),
-            cosmic_metrics: Default::default(),
-            cosmic_attrs: Default::default(),
-            background_image: Default::default(),
-            max_lines: Default::default(),
-            max_chars: Default::default(),
-            text_setter: Default::default(),
-            mode: Default::default(),
-            background_color: BackgroundColor(Color::WHITE),
-            placeholder_setter: Default::default(),
-            placeholder_attrs: Default::default(),
-        }
+        CosmicCanvas(DEFAULT_IMAGE_HANDLE.typed())
     }
 }
 
-#[derive(Bundle)]
-pub struct CosmicEditSpriteBundle {
-    // Bevy Sprite Bits
-    pub sprite: Sprite,
-    pub transform: Transform,
-    pub global_transform: GlobalTransform,
-    pub texture: Handle<Image>,
-    /// User indication of whether an entity is visible
-    pub visibility: Visibility,
-    /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
-    pub computed_visibility: ComputedVisibility,
-    /// Widget background color
-    pub fill_color: FillColor,
+#[derive(Bundle, Default)]
+pub struct CosmicEditBundle {
     // cosmic bits
-    /// text positioning enum
+    pub fill_color: FillColor,
     pub text_position: CosmicTextPosition,
-    /// text metrics
-    pub cosmic_metrics: CosmicMetrics,
-    /// text attributes
-    pub cosmic_attrs: CosmicAttrs,
-    /// bg img
+    pub metrics: CosmicMetrics,
+    pub attrs: CosmicAttrs,
     pub background_image: CosmicBackground,
-    /// How many lines are allowed in buffer, 0 for no limit
     pub max_lines: CosmicMaxLines,
-    /// How many characters are allowed in buffer, 0 for no limit
     pub max_chars: CosmicMaxChars,
-    /// Setting this will update the buffer's text
     pub text_setter: CosmicText,
-    /// Text input mode
     pub mode: CosmicMode,
-    /// Setting this will update the placeholder text
-    pub placeholder_setter: PlaceholderText,
-    pub placeholder_attrs: PlaceholderAttrs,
+    pub canvas: CosmicCanvas,
 }
 
-impl Default for CosmicEditSpriteBundle {
+#[derive(Bundle)]
+pub struct CosmicEditUiBundle {
+    pub node_bundle: NodeBundle,
+    pub image: UiImage,
+    pub interaction: Interaction,
+}
+
+impl Default for CosmicEditUiBundle {
     fn default() -> Self {
         Self {
-            sprite: Default::default(),
-            transform: Default::default(),
-            global_transform: Default::default(),
-            texture: DEFAULT_IMAGE_HANDLE.typed(),
-            visibility: Visibility::Visible,
-            computed_visibility: Default::default(),
-            fill_color: Default::default(),
-            text_position: Default::default(),
-            cosmic_metrics: Default::default(),
-            cosmic_attrs: Default::default(),
-            background_image: Default::default(),
-            max_lines: Default::default(),
-            max_chars: Default::default(),
-            text_setter: Default::default(),
-            mode: Default::default(),
-            placeholder_setter: Default::default(),
-            placeholder_attrs: Default::default(),
+            node_bundle: NodeBundle {
+                background_color: BackgroundColor(Color::WHITE),
+                ..default()
+            },
+            image: Default::default(),
+            interaction: Default::default(),
         }
     }
 }
 
+#[derive(Bundle)]
+pub struct CosmicEditPlaceholderBundle {
+    /// set this to update placeholder text
+    pub text_setter: PlaceholderText,
+    pub attrs: PlaceholderAttrs,
+}
+
 #[derive(Clone)]
 pub struct EditHistoryItem {
     pub cursor: Cursor,
@@ -411,6 +311,8 @@ impl Plugin for CosmicEditPlugin {
                 cosmic_editor_builder,
                 placeholder_builder,
                 on_scale_factor_change,
+                render::cosmic_ui_to_canvas,
+                render::cosmic_sprite_to_canvas,
             ),
         )
         .add_systems(PreUpdate, (update_buffer_text, update_placeholder_text))
@@ -425,6 +327,8 @@ impl Plugin for CosmicEditPlugin {
                 freeze_cursor_blink,
                 hide_inactive_or_readonly_cursor,
                 clear_inactive_selection,
+                render::update_handle_ui,
+                render::update_handle_sprite,
             ),
         )
         .add_systems(
@@ -802,7 +706,7 @@ mod tests {
     use crate::*;
 
     fn test_spawn_cosmic_edit_system(mut commands: Commands) {
-        commands.spawn(CosmicEditUiBundle {
+        commands.spawn(CosmicEditBundle {
             text_setter: CosmicText::OneStyle("Blah".into()),
             ..Default::default()
         });
diff --git a/src/render.rs b/src/render.rs
index e1ad1cd523029942dce961bbc7d762f027f43996..ee848914a285e5dc1b3683926cd62d6fd3b61864 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -11,8 +11,8 @@ use image::{imageops::FilterType, GenericImageView};
 
 use crate::{
     get_text_size, get_x_offset_center, get_y_offset_center, CosmicAttrs, CosmicBackground,
-    CosmicEditor, CosmicFontSystem, CosmicMetrics, CosmicMode, CosmicTextPosition, FillColor,
-    Focus, Placeholder, ReadOnly, XOffset,
+    CosmicCanvas, CosmicEditor, CosmicFontSystem, CosmicMetrics, CosmicMode, CosmicTextPosition,
+    FillColor, Focus, Placeholder, ReadOnly, XOffset,
 };
 
 #[derive(Resource)]
@@ -35,12 +35,11 @@ pub(crate) fn cosmic_edit_redraw_buffer(
         &CosmicAttrs,
         &CosmicBackground,
         &FillColor,
+        &mut CosmicCanvas,
         &CosmicTextPosition,
-        Option<&mut UiImage>,
         Option<&Node>,
         Option<&mut Style>,
         Option<&mut Sprite>,
-        Option<&mut Handle<Image>>,
         &mut XOffset,
         &CosmicMode,
         Option<&mut Placeholder>,
@@ -55,12 +54,11 @@ pub(crate) fn cosmic_edit_redraw_buffer(
         attrs,
         background_image,
         fill_color,
+        mut canvas,
         text_position,
-        ui_image_opt,
         node_opt,
         style_opt,
         sprite_opt,
-        handle_opt,
         mut x_offset,
         mode,
         mut placeholder_opt,
@@ -236,61 +234,37 @@ pub(crate) fn cosmic_edit_redraw_buffer(
             },
         );
 
-        // replace target image with modified pixel buffer
-        match handle_opt {
-            Some(mut handle) => replace_target_image(
-                &mut handle,
-                &mut images,
-                widget_width,
-                widget_height,
-                pixels,
-            ),
-            None => replace_target_image(
-                &mut ui_image_opt.unwrap().texture,
-                &mut images,
-                widget_width,
-                widget_height,
-                pixels,
-            ),
+        let canvas = &mut canvas.0;
+
+        if let Some(prev_image) = images.get_mut(canvas) {
+            if *canvas == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() {
+                let mut prev_image = prev_image.clone();
+                prev_image.data.clear();
+                prev_image.data.extend_from_slice(pixels.as_slice());
+                prev_image.resize(Extent3d {
+                    width: widget_width as u32,
+                    height: widget_height as u32,
+                    depth_or_array_layers: 1,
+                });
+                let handle_id: HandleId = HandleId::random::<Image>();
+                let new_handle: Handle<Image> = Handle::weak(handle_id);
+                let new_handle = images.set(new_handle, prev_image);
+                *canvas = new_handle;
+            } else {
+                prev_image.data.clear();
+                prev_image.data.extend_from_slice(pixels.as_slice());
+                prev_image.resize(Extent3d {
+                    width: widget_width as u32,
+                    height: widget_height as u32,
+                    depth_or_array_layers: 1,
+                });
+            }
         }
 
         editor.buffer_mut().set_redraw(false);
     }
 }
 
-fn replace_target_image(
-    cosmic_canvas_img_handle: &mut Handle<Image>,
-    images: &mut ResMut<Assets<Image>>,
-    width: f32,
-    height: f32,
-    pixels: Vec<u8>,
-) {
-    if let Some(prev_image) = images.get_mut(cosmic_canvas_img_handle) {
-        if *cosmic_canvas_img_handle == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() {
-            let mut prev_image = prev_image.clone();
-            prev_image.data.clear();
-            prev_image.data.extend_from_slice(pixels.as_slice());
-            prev_image.resize(Extent3d {
-                width: width as u32,
-                height: height as u32,
-                depth_or_array_layers: 1,
-            });
-            let handle_id: HandleId = HandleId::random::<Image>();
-            let new_handle: Handle<Image> = Handle::weak(handle_id);
-            let new_handle = images.set(new_handle, prev_image);
-            *cosmic_canvas_img_handle = new_handle;
-        } else {
-            prev_image.data.clear();
-            prev_image.data.extend_from_slice(pixels.as_slice());
-            prev_image.resize(Extent3d {
-                width: width as u32,
-                height: height as u32,
-                depth_or_array_layers: 1,
-            });
-        }
-    }
-}
-
 fn draw_pixel(
     buffer: &mut [u8],
     width: i32,
@@ -472,3 +446,35 @@ pub(crate) fn on_scale_factor_change(
         }
     }
 }
+
+pub(crate) fn cosmic_ui_to_canvas(
+    mut added_ui_images: Query<(&mut UiImage, &CosmicCanvas), Added<UiImage>>,
+) {
+    for (mut ui_image, canvas) in added_ui_images.iter_mut() {
+        ui_image.texture = canvas.0.clone_weak();
+    }
+}
+
+pub(crate) fn update_handle_ui(
+    mut changed_handles: Query<(&mut UiImage, &CosmicCanvas), Changed<CosmicCanvas>>,
+) {
+    for (mut ui_image, canvas) in changed_handles.iter_mut() {
+        ui_image.texture = canvas.0.clone_weak();
+    }
+}
+
+pub(crate) fn cosmic_sprite_to_canvas(
+    mut added_sprite_textures: Query<(&mut Handle<Image>, &CosmicCanvas), Added<Handle<Image>>>,
+) {
+    for (mut handle, canvas) in added_sprite_textures.iter_mut() {
+        *handle = canvas.0.clone_weak();
+    }
+}
+
+pub(crate) fn update_handle_sprite(
+    mut changed_handles: Query<(&mut Handle<Image>, &CosmicCanvas), Changed<CosmicCanvas>>,
+) {
+    for (mut handle, canvas) in changed_handles.iter_mut() {
+        *handle = canvas.0.clone_weak();
+    }
+}