diff --git a/examples/spinner-prompts.rs b/examples/spinner-prompts.rs
new file mode 100644
index 0000000..b78b1c8
--- /dev/null
+++ b/examples/spinner-prompts.rs
@@ -0,0 +1,44 @@
+use demand::{Confirm, DemandOption, Input, MultiSelect, Select, Spinner, Theme};
+
+fn main() {
+    let spinner = Spinner::new("im out here");
+    spinner
+        .run(|| {
+            Confirm::new("confirm")
+                .description("it says confirm")
+                .run()
+                .unwrap();
+            Input::new("input ")
+                .description("go on say something")
+                .suggestions(vec!["hello there"])
+                .validation(|s| match !s.contains('j') {
+                    true => Ok(()),
+                    false => Err("ew stinky 'j' not welcome here"),
+                })
+                .theme(&Theme::catppuccin())
+                .placeholder("Words go here")
+                .run()
+                .unwrap();
+            Select::new("select")
+                .description("hi")
+                .options(vec![
+                    DemandOption::new("hi"),
+                    DemandOption::new("hello"),
+                    DemandOption::new("how are you"),
+                ])
+                .run()
+                .unwrap();
+            MultiSelect::new("more select")
+                .description("hewo")
+                .options(vec![
+                    DemandOption::new("hi"),
+                    DemandOption::new("hello"),
+                    DemandOption::new("how are you"),
+                ])
+                .run()
+                .unwrap();
+            // Spinner::new("spinnerception")
+            //     .run(|| std::thread::sleep(std::time::Duration::from_secs(1)))
+        })
+        .unwrap();
+}
diff --git a/src/confirm.rs b/src/confirm.rs
index 805b330..6aa4389 100644
--- a/src/confirm.rs
+++ b/src/confirm.rs
@@ -173,6 +173,7 @@ impl<'a> Confirm<'a> {
             out.set_color(&self.theme.help_desc)?;
             write!(out, " {}", desc)?;
         }
+        writeln!(out)?;
 
         out.reset()?;
         Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string())
@@ -220,7 +221,8 @@ mod tests {
 
                  Yes!     No.  
 
-              ←/→ toggle • y/n/enter submit"
+              ←/→ toggle • y/n/enter submit
+              "
             },
             without_ansi(confirm.render().unwrap().as_str())
         );
diff --git a/src/input.rs b/src/input.rs
index b300bf0..f5bf96e 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -110,7 +110,7 @@ impl<'a> Input<'a> {
         self
     }
 
-    // Sets the suggestions of the input
+    /// Sets the suggestions of the input
     pub fn suggestions(mut self, suggestions: Vec<&'static str>) -> Self {
         self.suggestions = suggestions;
         self
@@ -140,7 +140,7 @@ impl<'a> Input<'a> {
 
     /// Displays the input to the user and returns the response
     pub fn run(mut self) -> io::Result<String> {
-        self.term.show_cursor()?;
+        self.term.hide_cursor()?;
         loop {
             self.clear()?;
             let output = self.render()?;
@@ -297,19 +297,7 @@ impl<'a> Input<'a> {
         }
         out.reset()?;
 
-        if !self.placeholder.is_empty() && self.input.is_empty() {
-            out.set_color(&self.theme.input_placeholder)?;
-            write!(out, "{}", &self.placeholder)?;
-            out.reset()?;
-        }
-
-        write!(out, "{}", &self.render_input()?)?;
-
-        if self.suggestion.is_some() {
-            out.set_color(&self.theme.input_placeholder)?;
-            write!(out, "{}", self.suggestion.as_ref().unwrap())?;
-            out.reset()?;
-        }
+        self.render_input(&mut out)?;
 
         if self.err.is_some() {
             out.set_color(&self.theme.error_indicator)?;
@@ -319,14 +307,75 @@ impl<'a> Input<'a> {
             out.reset()?;
         }
 
+        writeln!(out)?;
+        out.reset()?;
+
         Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string())
     }
 
-    fn render_input(&mut self) -> io::Result<String> {
+    fn render_input(&mut self, out: &mut Buffer) -> io::Result<String> {
         let input = match self.password {
             true => self.input.chars().map(|_| '*').collect::<String>(),
             false => self.input.to_string(),
         };
+
+        if !self.placeholder.is_empty() && self.input.is_empty() {
+            out.set_color(
+                &self
+                    .theme
+                    .real_cursor_color(Some(&self.theme.input_placeholder)),
+            )?;
+            write!(out, "{}", &self.placeholder[..1])?;
+            if self.placeholder.len() > 1 {
+                out.set_color(&self.theme.input_placeholder)?;
+                write!(out, "{}", &self.placeholder[1..])?;
+                out.reset()?;
+            }
+            return Ok(input);
+        }
+
+        let cursor_idx = self.get_char_idx(&input, self.cursor);
+        write!(out, "{}", &input[..cursor_idx])?;
+
+        if cursor_idx < input.len() {
+            out.set_color(&self.theme.real_cursor_color(None))?;
+            write!(out, "{}", &input[cursor_idx..cursor_idx + 1])?;
+            out.reset()?;
+        }
+        if cursor_idx + 1 < input.len() {
+            out.reset()?;
+            write!(out, "{}", &input[cursor_idx + 1..])?;
+        }
+
+        if let Some(suggestion) = &self.suggestion {
+            if !suggestion.is_empty() {
+                if cursor_idx >= input.len() {
+                    out.set_color(
+                        &self
+                            .theme
+                            .real_cursor_color(Some(&self.theme.input_placeholder)),
+                    )?;
+                    write!(out, "{}", &suggestion[..1])?;
+                    if suggestion.len() > 1 {
+                        out.set_color(&self.theme.input_placeholder)?;
+                        write!(out, "{}", &suggestion[1..])?;
+                    }
+                } else {
+                    out.set_color(&self.theme.input_placeholder)?;
+                    write!(out, "{suggestion}")?;
+                }
+                out.reset()?;
+            } else if cursor_idx >= input.len() {
+                out.set_color(&self.theme.real_cursor_color(None))?;
+                write!(out, " ")?;
+                out.reset()?;
+            }
+        } else if cursor_idx >= input.len() {
+            out.set_color(&self.theme.real_cursor_color(None))?;
+            write!(out, " ")?;
+            out.reset()?;
+        }
+
         Ok(input)
     }
 
@@ -335,7 +384,7 @@ impl<'a> Input<'a> {
         out.set_color(&self.theme.title)?;
         write!(out, " {}", self.title)?;
         out.set_color(&self.theme.selected_option)?;
-        writeln!(out, " {}", &self.render_input()?.to_string())?;
+        writeln!(out, " {}", self.input)?;
         out.reset()?;
         Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string())
     }
@@ -377,7 +426,7 @@ impl<'a> Input<'a> {
     }
 
     fn set_cursor(&mut self) -> io::Result<()> {
-        // if we have a placeholer, move the cursor left to beginning of the input
+        // if we have a placeholder, move the cursor left to beginning of the input
         if !self.placeholder.is_empty() && self.input.is_empty() {
             self.term
                 .move_cursor_left(self.placeholder.chars().count())?;
@@ -450,7 +499,7 @@ mod tests {
             .placeholder("Placeholder");
 
         assert_eq!(
-            " Title\n Description\n $ Placeholder",
+            " Title\n Description\n $ Placeholder\n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -460,7 +509,7 @@ mod tests {
         let mut input = Input::new("Title");
 
         assert_eq!(
-            " Title\n > ",
+            " Title\n >  \n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -470,7 +519,7 @@ mod tests {
         let mut input = Input::new("Title").description("Description");
 
         assert_eq!(
-            " Title\n Description\n > ",
+            " Title\n Description\n >  \n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -480,7 +529,7 @@ mod tests {
         let mut input = Input::new("Title").prompt("$ ");
 
         assert_eq!(
-            " Title\n $ ",
+            " Title\n $  \n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -490,7 +539,7 @@ mod tests {
         let mut input = Input::new("Title").placeholder("Placeholder");
 
         assert_eq!(
-            " Title\n > Placeholder",
+            " Title\n > Placeholder\n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -504,7 +553,7 @@ mod tests {
             .inline(true);
 
         assert_eq!(
-            " Title?Description.Prompt:Placeholder",
+            " Title?Description.Prompt:Placeholder\n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -518,14 +567,14 @@ mod tests {
         input.input = "".to_string();
         input.validate().unwrap();
         assert_eq!(
-            " Title\n Description\n > \n\n * Name cannot be empty",
+            " Title\n Description\n >  \n\n * Name cannot be empty\n",
             without_ansi(input.render().unwrap().as_str())
         );
 
         input.input = "non empty".to_string();
         input.validate().unwrap();
         assert_eq!(
-            " Title\n Description\n > non empty",
+            " Title\n Description\n > non empty\n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
@@ -540,14 +589,14 @@ mod tests {
         input.input = "".to_string();
         input.validate().unwrap();
         assert_eq!(
-            " Title?Description.> \n\n * Name cannot be empty",
+            " Title?Description.>  \n\n * Name cannot be empty\n",
             without_ansi(input.render().unwrap().as_str())
         );
 
         input.input = "non empty".to_string();
         input.validate().unwrap();
         assert_eq!(
-            " Title?Description.> non empty",
+            " Title?Description.> non empty\n",
             without_ansi(input.render().unwrap().as_str())
         );
     }
diff --git a/src/multiselect.rs b/src/multiselect.rs
index 6919d4c..2709510 100644
--- a/src/multiselect.rs
+++ b/src/multiselect.rs
@@ -414,6 +414,7 @@ impl<'a, T> MultiSelect<'a, T> {
                 write!(out, " {}", desc)?;
             }
         }
+        writeln!(out)?;
 
         out.reset()?;
         Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string())
@@ -468,7 +469,8 @@ mod tests {
               [ ] Vegan Cheese
               [ ] Nutella
 
-            ↑/↓/k/j up/down • x/space toggle • a toggle all • enter confirm"
+            ↑/↓/k/j up/down • x/space toggle • a toggle all • enter confirm
+            "
             },
             without_ansi(select.render().unwrap().as_str())
         );
@@ -517,7 +519,8 @@ mod tests {
               [•] 2
               [•] 3
 
-            ↑/↓/k/j up/down • x/space toggle • a toggle all • enter confirm"
+            ↑/↓/k/j up/down • x/space toggle • a toggle all • enter confirm
+            "
             },
             without_ansi(select.render().unwrap().as_str())
         );
diff --git a/src/select.rs b/src/select.rs
index f07f456..e2eb270 100644
--- a/src/select.rs
+++ b/src/select.rs
@@ -303,6 +303,7 @@ impl<'a, T> Select<'a, T> {
                 write!(out, " {}", desc)?;
             }
         }
+        writeln!(out)?;
 
         out.reset()?;
         Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string())
@@ -353,7 +354,8 @@ mod tests {
                  Canada
                  Mexico
 
-              ↑/↓/k/j up/down • enter confirm"
+              ↑/↓/k/j up/down • enter confirm
+              "
             },
             without_ansi(select.render().unwrap().as_str())
         );
@@ -395,7 +397,8 @@ mod tests {
                > First
                  2
 
-              ↑/↓/k/j up/down • enter confirm"
+              ↑/↓/k/j up/down • enter confirm
+              "
             },
             without_ansi(select.render().unwrap().as_str())
         );
diff --git a/src/spinner.rs b/src/spinner.rs
index b762a8c..6a92749 100644
--- a/src/spinner.rs
+++ b/src/spinner.rs
@@ -75,7 +75,7 @@ impl<'a> Spinner<'a> {
             loop {
                 self.clear()?;
                 let output = self.render()?;
-                self.height = output.lines().count();
+                self.height = output.lines().count() - 1;
                 self.term.write_all(output.as_bytes())?;
                 sleep(self.style.fps);
                 if handle.is_finished() {
@@ -110,8 +110,11 @@ impl<'a> Spinner<'a> {
     }
 
     fn clear(&mut self) -> io::Result<()> {
-        self.term.clear_to_end_of_screen()?;
-        self.term.clear_last_lines(self.height)?;
+        if self.height == 0 {
+            self.term.clear_line()?;
+        } else {
+            self.term.clear_last_lines(self.height)?;
+        }
         self.height = 0;
         Ok(())
     }
diff --git a/src/theme.rs b/src/theme.rs
index 42289d0..17e48bf 100644
--- a/src/theme.rs
+++ b/src/theme.rs
@@ -3,6 +3,12 @@ use termcolor::{Color, ColorSpec};
 
 pub(crate) static DEFAULT: Lazy<Theme> = Lazy::new(Theme::default);
 
+#[derive(Clone, Debug)]
+pub enum CursorShape {
+    Block,
+    Underline,
+}
+
 /// Theme for styling the UI.
 ///
 /// # Example
@@ -38,6 +44,13 @@ pub struct Theme {
     /// Unselected prefix foreground color
     pub unselected_prefix_fg: ColorSpec,
 
+    /// Char to use for the cursor
+    pub cursor_shape: CursorShape,
+    /// the color when there isnt text to get color from
+    pub cursor_style: ColorSpec,
+    /// use cusor_style even when there is text to get color from
+    pub force_style: bool,
+
     /// Input cursor color
     pub input_cursor: ColorSpec,
     /// Input placeholder color
@@ -72,6 +85,12 @@ impl Theme {
         let mut blurred_button = make_color(Color::Ansi256(7));
         blurred_button.set_bg(Some(Color::Ansi256(0)));
 
+        // TODO: theme them
+        let mut cursor_style = ColorSpec::new();
+        cursor_style
+            .set_fg(Some(Color::White))
+            .set_bg(Some(Color::Black));
+
         Self {
             title: ColorSpec::new(),
             error_indicator: ColorSpec::new(),
@@ -91,7 +110,37 @@ impl Theme {
             help_sep: ColorSpec::new(),
             focused_button,
             blurred_button,
+
+            // TODO: theme these
+            cursor_shape: CursorShape::Block,
+            cursor_style,
+            force_style: true,
+        }
+    }
+
+    pub fn real_cursor_color(&self, other: Option<&ColorSpec>) -> ColorSpec {
+        // let mut c = self.input_cursor.clone();
+        let other = if self.force_style {
+            &self.cursor_style
+        } else {
+            other.unwrap_or(&self.cursor_style)
+        };
+
+        let mut c = ColorSpec::new();
+        match self.cursor_shape {
+            CursorShape::Block => {
+                c.set_bg(other.fg().copied());
+                c.set_fg(other.bg().copied());
+            }
+            CursorShape::Underline => {
+                c.set_bg(other.bg().copied());
+                c.set_fg(other.fg().copied());
+                c.set_underline(true);
+            }
         }
+        // c.set_fg(self.input_cursor.bg().copied())
+        //     .set_bg(self.input_cursor.bg().copied());
+        c
     }
 
     /// Create a new theme with the charm color scheme
@@ -112,6 +161,12 @@ impl Theme {
         let mut blurred_button = make_color(normal);
         blurred_button.set_bg(Some(Color::Ansi256(238)));
 
+        // TODO: theme them
+        let mut cursor_style = ColorSpec::new();
+        cursor_style
+            .set_fg(Some(Color::White))
+            .set_bg(Some(Color::Black));
+
         Self {
             title,
             error_indicator: make_color(red),
@@ -135,6 +190,11 @@ impl Theme {
 
             focused_button,
             blurred_button,
+
+            // TODO: theme these
+            cursor_shape: CursorShape::Block,
+            cursor_style,
+            force_style: true,
         }
     }
 
@@ -157,6 +217,12 @@ impl Theme {
         let mut blurred_button = make_color(foreground);
         blurred_button.set_bg(Some(background));
 
+        // TODO: theme them
+        let mut cursor_style = ColorSpec::new();
+        cursor_style
+            .set_fg(Some(Color::White))
+            .set_bg(Some(Color::Black));
+
         Self {
             title,
             error_indicator: make_color(red),
@@ -180,6 +246,11 @@ impl Theme {
 
             focused_button,
             blurred_button,
+
+            // TODO: theme these
+            cursor_shape: CursorShape::Block,
+            cursor_style,
+            force_style: true,
         }
     }
 
@@ -194,6 +265,12 @@ impl Theme {
         let mut blurred_button = make_color(Color::Ansi256(7));
         blurred_button.set_bg(Some(Color::Ansi256(0)));
 
+        // TODO: theme them
+        let mut cursor_style = ColorSpec::new();
+        cursor_style
+            .set_fg(Some(Color::White))
+            .set_bg(Some(Color::Black));
+
         Self {
             title,
             error_indicator: make_color(Color::Ansi256(9)),
@@ -217,6 +294,11 @@ impl Theme {
 
             focused_button,
             blurred_button,
+
+            // TODO: theme these
+            cursor_shape: CursorShape::Block,
+            cursor_style,
+            force_style: true,
         }
     }
 
@@ -242,6 +324,12 @@ impl Theme {
         let mut blurred_button = make_color(text);
         blurred_button.set_bg(Some(base));
 
+        // TODO: theme them
+        let mut cursor_style = ColorSpec::new();
+        cursor_style
+            .set_fg(Some(Color::White))
+            .set_bg(Some(Color::Black));
+
         Self {
             title,
             error_indicator: make_color(red),
@@ -265,6 +353,11 @@ impl Theme {
 
             focused_button,
             blurred_button,
+
+            // TODO: theme these
+            cursor_shape: CursorShape::Block,
+            cursor_style,
+            force_style: true,
         }
     }