diff --git a/examples/basic_sprite.rs b/examples/basic_sprite.rs
index 35d46cda28aad9cc1d9ebfc8c79b9498ebe8196a..e01b4455bd6a84e7b915f29f4e1ebb6f57b6ed25 100644
--- a/examples/basic_sprite.rs
+++ b/examples/basic_sprite.rs
@@ -51,7 +51,10 @@ fn main() {
 
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin { font_config })
+        .add_plugins(CosmicEditPlugin {
+            font_config,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .run();
 }
diff --git a/examples/basic_ui.rs b/examples/basic_ui.rs
index 777030f763b770ab44874a28dd001f36970ac29a..f02ab728750a7c1210da1cd9df62a2987d5c1e1c 100644
--- a/examples/basic_ui.rs
+++ b/examples/basic_ui.rs
@@ -66,7 +66,10 @@ fn main() {
 
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin { font_config })
+        .add_plugins(CosmicEditPlugin {
+            font_config,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .add_systems(Update, print_text)
         .run();
diff --git a/examples/bevy_api_testing.rs b/examples/bevy_api_testing.rs
index 0b98f531e8da785167ebae92b822a4aab1ce7c80..6f1e9ae672cc5af9d5352daee3172c8301bced69 100644
--- a/examples/bevy_api_testing.rs
+++ b/examples/bevy_api_testing.rs
@@ -17,6 +17,7 @@ fn setup(mut commands: Commands) {
         cosmic_attrs: CosmicAttrs(AttrsOwned::new(
             Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)),
         )),
+        max_lines: CosmicMaxLines(1),
         ..default()
     });
 
@@ -92,12 +93,32 @@ fn change_active_editor_sprite(
     }
 }
 
+fn ev_test(
+    mut evr_on: EventReader<TextHoverIn>,
+    mut evr_out: EventReader<TextHoverOut>,
+    mut evr_type: EventReader<CosmicTextChanged>,
+) {
+    for _ev in evr_on.iter() {
+        println!("IN");
+    }
+    for _ev in evr_out.iter() {
+        println!("OUT");
+    }
+    for _ev in evr_type.iter() {
+        println!("TYPE");
+    }
+}
+
 fn main() {
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin::default())
+        .add_plugins(CosmicEditPlugin {
+            change_cursor: CursorConfig::Default,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .add_systems(Update, change_active_editor_ui)
         .add_systems(Update, change_active_editor_sprite)
+        .add_systems(Update, ev_test)
         .run();
 }
diff --git a/examples/font_per_widget.rs b/examples/font_per_widget.rs
index 303862ebc33e74a835cb18f98d9ed9a3a9afbd69..6a628051d9bd3f89226ffc19f3d5e1dfacee2969 100644
--- a/examples/font_per_widget.rs
+++ b/examples/font_per_widget.rs
@@ -293,7 +293,10 @@ fn main() {
 
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin { font_config })
+        .add_plugins(CosmicEditPlugin {
+            font_config,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .add_systems(Update, change_active_editor_ui)
         .run();
diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs
index ad24adf121e8d9eb7b7a2c5cbfd34874b260acd5..1f1942be689b4538f580fd50bb1cd104fe5a8af1 100644
--- a/examples/multiple_sprites.rs
+++ b/examples/multiple_sprites.rs
@@ -114,7 +114,10 @@ fn main() {
 
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin { font_config })
+        .add_plugins(CosmicEditPlugin {
+            font_config,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .add_systems(Update, change_active_editor_sprite)
         .run();
diff --git a/examples/readonly.rs b/examples/readonly.rs
index 5247f030528b0cb76f59f5fd7389b4acaca1c966..58035b7af7b16c5514a4f19aa06e21cceb450146 100644
--- a/examples/readonly.rs
+++ b/examples/readonly.rs
@@ -66,7 +66,10 @@ fn main() {
 
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin { font_config })
+        .add_plugins(CosmicEditPlugin {
+            font_config,
+            ..default()
+        })
         .add_systems(Startup, setup)
         .run();
 }
diff --git a/src/cursor.rs b/src/cursor.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d1a8530b38f643e2d752c8ceba172858be3cbf63
--- /dev/null
+++ b/src/cursor.rs
@@ -0,0 +1,100 @@
+use bevy::{input::mouse::MouseMotion, prelude::*, window::PrimaryWindow};
+
+use crate::{CosmicEditor, CosmicTextChanged, ReadOnly};
+
+/// For use with custom cursor control; Event is emitted when cursor enters a text widget
+#[derive(Event)]
+pub struct TextHoverIn;
+
+/// For use with custom cursor control; Event is emitted when cursor leaves a text widget
+#[derive(Event)]
+pub struct TextHoverOut;
+
+pub fn change_cursor(
+    evr_hover_in: EventReader<TextHoverIn>,
+    evr_hover_out: EventReader<TextHoverOut>,
+    evr_text_changed: EventReader<CosmicTextChanged>,
+    evr_mouse_motion: EventReader<MouseMotion>,
+    mouse_buttons: Res<Input<MouseButton>>,
+    mut windows: Query<&mut Window, With<PrimaryWindow>>,
+) {
+    let mut window = windows.single_mut();
+    if !evr_hover_in.is_empty() {
+        window.cursor.icon = CursorIcon::Text;
+    }
+    if !evr_hover_out.is_empty() {
+        window.cursor.icon = CursorIcon::Default;
+    }
+    if !evr_text_changed.is_empty() {
+        window.cursor.visible = false;
+    }
+    if mouse_buttons.get_just_pressed().len() != 0 || !evr_mouse_motion.is_empty() {
+        window.cursor.visible = true;
+    }
+}
+
+// TODO: Only emit events; If configured to, have a fn to act on the events
+pub fn hover_sprites(
+    windows: Query<&Window, With<PrimaryWindow>>,
+    mut cosmic_edit_query: Query<
+        (&mut Sprite, &GlobalTransform),
+        (With<CosmicEditor>, Without<ReadOnly>),
+    >,
+    camera_q: Query<(&Camera, &GlobalTransform)>,
+    mut hovered: Local<bool>,
+    mut last_hovered: Local<bool>,
+    mut evw_hover_in: EventWriter<TextHoverIn>,
+    mut evw_hover_out: EventWriter<TextHoverOut>,
+) {
+    *hovered = false;
+    let window = windows.single();
+    let (camera, camera_transform) = camera_q.single();
+    for (sprite, node_transform) in &mut cosmic_edit_query.iter_mut() {
+        let size = sprite.custom_size.unwrap_or(Vec2::new(1., 1.));
+        let x_min = node_transform.affine().translation.x - size.x / 2.;
+        let y_min = node_transform.affine().translation.y - size.y / 2.;
+        let x_max = node_transform.affine().translation.x + size.x / 2.;
+        let y_max = node_transform.affine().translation.y + size.y / 2.;
+        if let Some(pos) = window.cursor_position() {
+            if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) {
+                if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max {
+                    *hovered = true;
+                }
+            }
+        }
+    }
+
+    if *last_hovered != *hovered {
+        if *hovered {
+            evw_hover_in.send(TextHoverIn);
+        } else {
+            evw_hover_out.send(TextHoverOut);
+        }
+    }
+
+    *last_hovered = *hovered;
+}
+
+pub fn hover_ui(
+    mut interaction_query: Query<
+        &Interaction,
+        (
+            Changed<Interaction>,
+            (With<CosmicEditor>, Without<ReadOnly>),
+        ),
+    >,
+    mut evw_hover_in: EventWriter<TextHoverIn>,
+    mut evw_hover_out: EventWriter<TextHoverOut>,
+) {
+    for interaction in interaction_query.iter_mut() {
+        match interaction {
+            Interaction::None => {
+                evw_hover_out.send(TextHoverOut);
+            }
+            Interaction::Hovered => {
+                evw_hover_in.send(TextHoverIn);
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 535de10399965680796fba7705fefcfcf7e66d79..d04000f6745be0a1190cb17dd30ea5367d57bcc4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,7 @@
 #![allow(clippy::type_complexity)]
 
+mod cursor;
+
 use std::{collections::VecDeque, path::PathBuf, time::Duration};
 
 use bevy::{
@@ -18,6 +20,8 @@ pub use cosmic_text::{
 use cosmic_text::{
     Affinity, AttrsList, Buffer, BufferLine, Editor, FontSystem, Metrics, Shaping, SwashCache,
 };
+use cursor::{change_cursor, hover_sprites, hover_ui};
+pub use cursor::{TextHoverIn, TextHoverOut};
 use image::{imageops::FilterType, GenericImageView};
 
 #[derive(Clone, Component, PartialEq, Debug)]
@@ -369,10 +373,19 @@ pub struct CosmicEditHistory {
     pub current_edit: usize,
 }
 
+#[derive(Default)]
+pub enum CursorConfig {
+    #[default]
+    Default,
+    Events,
+    None,
+}
+
 /// Plugin struct that adds systems and initializes resources related to cosmic edit functionality.
 #[derive(Default)]
 pub struct CosmicEditPlugin {
     pub font_config: CosmicFontConfig,
+    pub change_cursor: CursorConfig,
 }
 
 impl Plugin for CosmicEditPlugin {
@@ -408,6 +421,20 @@ impl Plugin for CosmicEditPlugin {
             })
             .insert_resource(CosmicFontSystem(font_system))
             .add_event::<CosmicTextChanged>();
+
+        match self.change_cursor {
+            CursorConfig::Default => {
+                app.add_systems(Update, (hover_sprites, hover_ui, change_cursor))
+                    .add_event::<TextHoverIn>()
+                    .add_event::<TextHoverOut>();
+            }
+            CursorConfig::Events => {
+                app.add_systems(Update, (hover_sprites, hover_ui))
+                    .add_event::<TextHoverIn>()
+                    .add_event::<TextHoverOut>();
+            }
+            CursorConfig::None => {}
+        }
     }
 }