diff --git a/src/canvas/widgets/cpu_basic.rs b/src/canvas/widgets/cpu_basic.rs
index 4296b967..1ca75a90 100644
--- a/src/canvas/widgets/cpu_basic.rs
+++ b/src/canvas/widgets/cpu_basic.rs
@@ -1,8 +1,9 @@
 use std::cmp::min;
 
 use crate::{
-    app::App,
-    canvas::{drawing_utils::*, Painter},
+    app::{data_harvester::cpu::CpuDataType, App},
+    canvas::Painter,
+    components::tui_widget::pipe_gauge::{LabelLimit, PipeGauge},
     constants::*,
     data_conversion::CpuWidgetData,
 };
@@ -11,11 +12,11 @@ use tui::{
     backend::Backend,
     layout::{Constraint, Direction, Layout, Rect},
     terminal::Frame,
-    text::{Span, Spans},
-    widgets::{Block, Paragraph},
+    widgets::Block,
 };
 
 impl Painter {
+    /// Inspired by htop.
     pub fn draw_basic_cpu<B: Backend>(
         &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
     ) {
@@ -42,148 +43,84 @@ impl Painter {
                 );
             }
 
-            let num_cpus = cpu_data.len();
-            let show_avg_cpu = app_state.app_config_fields.show_average_cpu;
-
             if draw_loc.height > 0 {
                 let remaining_height = usize::from(draw_loc.height);
                 const REQUIRED_COLUMNS: usize = 4;
 
-                let chunk_vec =
+                let col_constraints =
                     vec![Constraint::Percentage((100 / REQUIRED_COLUMNS) as u16); REQUIRED_COLUMNS];
-                let chunks = Layout::default()
-                    .constraints(chunk_vec)
+                let columns = Layout::default()
+                    .constraints(col_constraints)
                     .direction(Direction::Horizontal)
                     .split(draw_loc);
 
-                const CPU_NAME_SPACE: usize = 3;
-                const BAR_BOUND_SPACE: usize = 2;
-                const PERCENTAGE_SPACE: usize = 4;
-                const MARGIN_SPACE: usize = 2;
+                let mut gauge_info = cpu_data.iter().map(|cpu| match cpu {
+                    CpuWidgetData::All => unreachable!(),
+                    CpuWidgetData::Entry {
+                        data_type,
+                        data: _,
+                        last_entry,
+                    } => {
+                        let (outer, style) = match data_type {
+                            CpuDataType::Avg => ("AVG".to_string(), self.colours.avg_colour_style),
+                            CpuDataType::Cpu(index) => (
+                                format!("{index:<3}",),
+                                self.colours.cpu_colour_styles
+                                    [index % self.colours.cpu_colour_styles.len()],
+                            ),
+                        };
+                        let inner = format!("{:>3.0}%", last_entry.round());
+                        let ratio = last_entry / 100.0;
 
-                const COMBINED_SPACING: usize =
-                    CPU_NAME_SPACE + BAR_BOUND_SPACE + PERCENTAGE_SPACE + MARGIN_SPACE;
-                const REDUCED_SPACING: usize = CPU_NAME_SPACE + PERCENTAGE_SPACE + MARGIN_SPACE;
-                let chunk_width: usize = chunks[0].width.into();
+                        (outer, inner, ratio, style)
+                    }
+                });
 
-                // Inspired by htop.
-                // We do +4 as if it's too few bars in the bar length, it's kinda pointless.
-                let cpu_bars = if chunk_width >= COMBINED_SPACING + 4 {
-                    let bar_length = chunk_width - COMBINED_SPACING;
-                    cpu_data
-                        .iter()
-                        .enumerate()
-                        .filter_map(|(index, cpu)| match &cpu {
-                            CpuWidgetData::All => None,
-                            CpuWidgetData::Entry {
-                                data_type: _,
-                                data: _,
-                                last_entry,
-                            } => {
-                                let num_bars = calculate_basic_use_bars(*last_entry, bar_length);
-                                Some(format!(
-                                    "{:3}[{}{}{:3.0}%]",
-                                    if app_state.app_config_fields.show_average_cpu {
-                                        if index == 0 {
-                                            "AVG".to_string()
-                                        } else {
-                                            (index - 1).to_string()
-                                        }
-                                    } else {
-                                        index.to_string()
-                                    },
-                                    "|".repeat(num_bars),
-                                    " ".repeat(bar_length - num_bars),
-                                    last_entry.round(),
-                                ))
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                } else if chunk_width >= REDUCED_SPACING {
-                    cpu_data
-                        .iter()
-                        .enumerate()
-                        .filter_map(|(index, cpu)| match &cpu {
-                            CpuWidgetData::All => None,
-                            CpuWidgetData::Entry {
-                                data_type: _,
-                                data: _,
-                                last_entry,
-                            } => Some(format!(
-                                "{:3} {:3.0}%",
-                                if app_state.app_config_fields.show_average_cpu {
-                                    if index == 0 {
-                                        "AVG".to_string()
-                                    } else {
-                                        (index - 1).to_string()
-                                    }
-                                } else {
-                                    index.to_string()
-                                },
-                                last_entry.round(),
-                            )),
-                        })
-                        .collect::<Vec<_>>()
-                } else {
-                    cpu_data
-                        .iter()
-                        .filter_map(|cpu| match &cpu {
-                            CpuWidgetData::All => None,
-                            CpuWidgetData::Entry {
-                                data_type: _,
-                                data: _,
-                                last_entry,
-                            } => Some(format!("{:3.0}%", last_entry.round())),
-                        })
-                        .collect::<Vec<_>>()
-                };
+                // Very ugly way to sync the gauge limit across all gauges.
+                let hide_parts = columns
+                    .get(0)
+                    .map(|col| {
+                        if col.width >= 12 {
+                            LabelLimit::None
+                        } else if col.width >= 10 {
+                            LabelLimit::Bars
+                        } else {
+                            LabelLimit::StartLabel
+                        }
+                    })
+                    .unwrap_or_default();
 
-                let mut row_counter = num_cpus;
-                let mut start_index = 0;
-                for (itx, chunk) in chunks.iter().enumerate() {
-                    // Explicitly check... don't want an accidental DBZ or underflow, this ensures
-                    // to_divide is > 0
+                let num_entries = cpu_data.len();
+                let mut row_counter = num_entries;
+                for (itx, column) in columns.into_iter().enumerate() {
                     if REQUIRED_COLUMNS > itx {
                         let to_divide = REQUIRED_COLUMNS - itx;
-                        let how_many_cpus = min(
+                        let num_taken = min(
                             remaining_height,
                             (row_counter / to_divide)
                                 + (if row_counter % to_divide == 0 { 0 } else { 1 }),
                         );
-                        row_counter -= how_many_cpus;
-                        let end_index = min(start_index + how_many_cpus, num_cpus);
+                        row_counter -= num_taken;
+                        let chunk = (&mut gauge_info).take(num_taken);
 
-                        let cpu_column = (start_index..end_index)
-                            .map(|itx| {
-                                Spans::from(Span {
-                                    content: (&cpu_bars[itx]).into(),
-                                    style: if show_avg_cpu {
-                                        if itx == 0 {
-                                            self.colours.avg_colour_style
-                                        } else {
-                                            self.colours.cpu_colour_styles
-                                                [(itx - 1) % self.colours.cpu_colour_styles.len()]
-                                        }
-                                    } else {
-                                        self.colours.cpu_colour_styles
-                                            [itx % self.colours.cpu_colour_styles.len()]
-                                    },
-                                })
-                            })
-                            .collect::<Vec<_>>();
-
-                        start_index += how_many_cpus;
-
-                        let margined_loc = Layout::default()
-                            .direction(Direction::Horizontal)
-                            .constraints([Constraint::Percentage(100)])
+                        let rows = Layout::default()
+                            .direction(Direction::Vertical)
+                            .constraints(vec![Constraint::Length(1); remaining_height])
                             .horizontal_margin(1)
-                            .split(*chunk)[0];
+                            .split(column);
 
-                        f.render_widget(
-                            Paragraph::new(cpu_column).block(Block::default()),
-                            margined_loc,
-                        );
+                        for ((start_label, inner_label, ratio, style), row) in chunk.zip(rows) {
+                            f.render_widget(
+                                PipeGauge::default()
+                                    .gauge_style(style)
+                                    .label_style(style)
+                                    .inner_label(inner_label)
+                                    .start_label(start_label)
+                                    .ratio(ratio)
+                                    .hide_parts(hide_parts),
+                                row,
+                            );
+                        }
                     }
                 }
             }
diff --git a/src/canvas/widgets/mem_basic.rs b/src/canvas/widgets/mem_basic.rs
index 60f35f09..1d3c9969 100644
--- a/src/canvas/widgets/mem_basic.rs
+++ b/src/canvas/widgets/mem_basic.rs
@@ -1,16 +1,12 @@
 use crate::{
-    app::App,
-    canvas::{drawing_utils::*, Painter},
-    constants::*,
+    app::App, canvas::Painter, components::tui_widget::pipe_gauge::PipeGauge, constants::*,
 };
 
 use tui::{
     backend::Backend,
-    layout::{Constraint, Layout, Rect},
+    layout::{Constraint, Direction, Layout, Rect},
     terminal::Frame,
-    text::Span,
-    text::Spans,
-    widgets::{Block, Paragraph},
+    widgets::Block,
 };
 
 impl Painter {
@@ -21,7 +17,18 @@ impl Painter {
         let swap_data: &[(f64, f64)] = &app_state.converted_data.swap_data;
 
         let margined_loc = Layout::default()
-            .constraints([Constraint::Percentage(100)])
+            .constraints({
+                #[cfg(feature = "zfs")]
+                {
+                    [Constraint::Length(1); 3]
+                }
+
+                #[cfg(not(feature = "zfs"))]
+                {
+                    [Constraint::Length(1); 2]
+                }
+            })
+            .direction(Direction::Vertical)
             .horizontal_margin(1)
             .split(draw_loc);
 
@@ -34,118 +41,78 @@ impl Painter {
             );
         }
 
-        let ram_use_percentage = if let Some(mem) = mem_data.last() {
-            mem.1
+        let ram_ratio = if let Some(mem) = mem_data.last() {
+            mem.1 / 100.0
         } else {
             0.0
         };
-        let swap_use_percentage = if let Some(swap) = swap_data.last() {
-            swap.1
+        let swap_ratio = if let Some(swap) = swap_data.last() {
+            swap.1 / 100.0
         } else {
             0.0
         };
 
         const EMPTY_MEMORY_FRAC_STRING: &str = "0.0B/0.0B";
 
-        let trimmed_memory_frac =
-            if let Some((_label_percent, label_frac)) = &app_state.converted_data.mem_labels {
+        let memory_fraction_label =
+            if let Some((_, label_frac)) = &app_state.converted_data.mem_labels {
                 label_frac.trim()
             } else {
                 EMPTY_MEMORY_FRAC_STRING
             };
 
-        let trimmed_swap_frac =
-            if let Some((_label_percent, label_frac)) = &app_state.converted_data.swap_labels {
+        let swap_fraction_label =
+            if let Some((_, label_frac)) = &app_state.converted_data.swap_labels {
                 label_frac.trim()
             } else {
                 EMPTY_MEMORY_FRAC_STRING
             };
 
-        // +7 due to 3 + 2 + 2 columns for the name & space + bar bounds + margin spacing
-        // Then + length of fraction
-        let ram_bar_length =
-            usize::from(draw_loc.width.saturating_sub(7)).saturating_sub(trimmed_memory_frac.len());
-        let swap_bar_length =
-            usize::from(draw_loc.width.saturating_sub(7)).saturating_sub(trimmed_swap_frac.len());
+        f.render_widget(
+            PipeGauge::default()
+                .ratio(ram_ratio)
+                .start_label("RAM")
+                .inner_label(memory_fraction_label)
+                .label_style(self.colours.ram_style)
+                .gauge_style(self.colours.ram_style),
+            margined_loc[0],
+        );
 
-        let num_bars_ram = calculate_basic_use_bars(ram_use_percentage, ram_bar_length);
-        let num_bars_swap = calculate_basic_use_bars(swap_use_percentage, swap_bar_length);
-        // TODO: Use different styling for the frac.
-        let mem_label = if app_state.basic_mode_use_percent {
-            format!(
-                "RAM[{}{}{:3.0}%]\n",
-                "|".repeat(num_bars_ram),
-                " ".repeat(ram_bar_length - num_bars_ram + trimmed_memory_frac.len() - 4),
-                ram_use_percentage.round()
-            )
-        } else {
-            format!(
-                "RAM[{}{}{}]\n",
-                "|".repeat(num_bars_ram),
-                " ".repeat(ram_bar_length - num_bars_ram),
-                trimmed_memory_frac
-            )
-        };
-        let swap_label = if app_state.basic_mode_use_percent {
-            format!(
-                "SWP[{}{}{:3.0}%]",
-                "|".repeat(num_bars_swap),
-                " ".repeat(swap_bar_length - num_bars_swap + trimmed_swap_frac.len() - 4),
-                swap_use_percentage.round()
-            )
-        } else {
-            format!(
-                "SWP[{}{}{}]",
-                "|".repeat(num_bars_swap),
-                " ".repeat(swap_bar_length - num_bars_swap),
-                trimmed_swap_frac
-            )
-        };
+        f.render_widget(
+            PipeGauge::default()
+                .ratio(swap_ratio)
+                .start_label("SWP")
+                .inner_label(swap_fraction_label)
+                .label_style(self.colours.swap_style)
+                .gauge_style(self.colours.swap_style),
+            margined_loc[1],
+        );
 
-        let mem_text = vec![
-            Spans::from(Span::styled(mem_label, self.colours.ram_style)),
-            Spans::from(Span::styled(swap_label, self.colours.swap_style)),
-            #[cfg(feature = "zfs")]
-            {
-                let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data;
-                let arc_use_percentage = if let Some(arc) = arc_data.last() {
-                    arc.1
-                } else {
-                    0.0
-                };
-                let trimmed_arc_frac = if let Some((_label_percent, label_frac)) =
-                    &app_state.converted_data.arc_labels
-                {
+        #[cfg(feature = "zfs")]
+        {
+            let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data;
+            let arc_ratio = if let Some(arc) = arc_data.last() {
+                arc.1 / 100.0
+            } else {
+                0.0
+            };
+            let arc_fraction_label =
+                if let Some((_, label_frac)) = &app_state.converted_data.arc_labels {
                     label_frac.trim()
                 } else {
                     EMPTY_MEMORY_FRAC_STRING
                 };
-                let arc_bar_length = usize::from(draw_loc.width.saturating_sub(7))
-                    .saturating_sub(trimmed_arc_frac.len());
-                let num_bars_arc = calculate_basic_use_bars(arc_use_percentage, arc_bar_length);
-                let arc_label = if app_state.basic_mode_use_percent {
-                    format!(
-                        "ARC[{}{}{:3.0}%]",
-                        "|".repeat(num_bars_arc),
-                        " ".repeat(arc_bar_length - num_bars_arc + trimmed_arc_frac.len() - 4),
-                        arc_use_percentage.round()
-                    )
-                } else {
-                    format!(
-                        "ARC[{}{}{}]",
-                        "|".repeat(num_bars_arc),
-                        " ".repeat(arc_bar_length - num_bars_arc),
-                        trimmed_arc_frac
-                    )
-                };
-                Spans::from(Span::styled(arc_label, self.colours.arc_style))
-            },
-        ];
 
-        f.render_widget(
-            Paragraph::new(mem_text).block(Block::default()),
-            margined_loc[0],
-        );
+            f.render_widget(
+                PipeGauge::default()
+                    .ratio(arc_ratio)
+                    .start_label("ARC")
+                    .inner_label(arc_fraction_label)
+                    .label_style(self.colours.arc_style)
+                    .gauge_style(self.colours.arc_style),
+                margined_loc[2],
+            );
+        }
 
         // Update draw loc in widget map
         if app_state.should_get_widget_bounds() {
diff --git a/src/components.rs b/src/components.rs
index 1c4c453c..c2ee5aae 100644
--- a/src/components.rs
+++ b/src/components.rs
@@ -1,4 +1,3 @@
-mod tui_widget;
-
 pub mod data_table;
 pub mod time_graph;
+pub mod tui_widget;
diff --git a/src/components/tui_widget.rs b/src/components/tui_widget.rs
index a4e0978a..93c0509d 100644
--- a/src/components/tui_widget.rs
+++ b/src/components/tui_widget.rs
@@ -1 +1,2 @@
+pub mod pipe_gauge;
 pub mod time_chart;
diff --git a/src/components/tui_widget/pipe_gauge.rs b/src/components/tui_widget/pipe_gauge.rs
new file mode 100644
index 00000000..aa933185
--- /dev/null
+++ b/src/components/tui_widget/pipe_gauge.rs
@@ -0,0 +1,223 @@
+use tui::{
+    buffer::Buffer,
+    layout::Rect,
+    style::Style,
+    text::Spans,
+    widgets::{Block, Widget},
+};
+
+#[derive(Debug, Clone, Copy)]
+pub enum LabelLimit {
+    None,
+    Auto(u16),
+    Bars,
+    StartLabel,
+}
+
+impl Default for LabelLimit {
+    fn default() -> Self {
+        Self::None
+    }
+}
+
+/// A widget to measure something, using pipe characters ('|') as a unit.
+#[derive(Debug, Clone)]
+pub struct PipeGauge<'a> {
+    block: Option<Block<'a>>,
+    ratio: f64,
+    start_label: Option<Spans<'a>>,
+    inner_label: Option<Spans<'a>>,
+    label_style: Style,
+    gauge_style: Style,
+    hide_parts: LabelLimit,
+}
+
+impl<'a> Default for PipeGauge<'a> {
+    fn default() -> Self {
+        Self {
+            block: None,
+            ratio: 0.0,
+            start_label: None,
+            inner_label: None,
+            label_style: Style::default(),
+            gauge_style: Style::default(),
+            hide_parts: LabelLimit::default(),
+        }
+    }
+}
+
+impl<'a> PipeGauge<'a> {
+    /// The ratio, a value from 0.0 to 1.0 (any other greater or less will be clamped)
+    /// represents the portion of the pipe gauge to fill.
+    ///
+    /// Note: passing in NaN will potentially cause problems.
+    pub fn ratio(mut self, ratio: f64) -> Self {
+        self.ratio = ratio.clamp(0.0, 1.0);
+
+        self
+    }
+
+    /// The label displayed before the bar.
+    pub fn start_label<T>(mut self, start_label: T) -> Self
+    where
+        T: Into<Spans<'a>>,
+    {
+        self.start_label = Some(start_label.into());
+        self
+    }
+
+    /// The label displayed inside the bar.
+    pub fn inner_label<T>(mut self, inner_label: T) -> Self
+    where
+        T: Into<Spans<'a>>,
+    {
+        self.inner_label = Some(inner_label.into());
+        self
+    }
+
+    /// The style of the labels.
+    pub fn label_style(mut self, label_style: Style) -> Self {
+        self.label_style = label_style;
+        self
+    }
+
+    /// The style of the gauge itself.
+    pub fn gauge_style(mut self, style: Style) -> Self {
+        self.gauge_style = style;
+        self
+    }
+
+    /// Whether to hide parts of the gauge/label if the inner label wouldn't fit.
+    pub fn hide_parts(mut self, hide_parts: LabelLimit) -> Self {
+        self.hide_parts = hide_parts;
+        self
+    }
+}
+
+impl<'a> Widget for PipeGauge<'a> {
+    fn render(mut self, area: Rect, buf: &mut Buffer) {
+        buf.set_style(area, self.label_style);
+        let gauge_area = match self.block.take() {
+            Some(b) => {
+                let inner_area = b.inner(area);
+                b.render(area, buf);
+                inner_area
+            }
+            None => area,
+        };
+
+        if gauge_area.height < 1 {
+            return;
+        }
+
+        let (col, row) = {
+            let inner_label_width = self
+                .inner_label
+                .as_ref()
+                .map(|l| l.width())
+                .unwrap_or_default();
+
+            let start_label_width = self
+                .start_label
+                .as_ref()
+                .map(|l| l.width())
+                .unwrap_or_default();
+
+            match self.hide_parts {
+                LabelLimit::StartLabel => {
+                    let inner_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
+                    let _ = buf.set_spans(
+                        gauge_area.left(),
+                        gauge_area.top(),
+                        &inner_label,
+                        inner_label.width() as u16,
+                    );
+
+                    // Short circuit.
+                    return;
+                }
+                LabelLimit::Auto(_)
+                    if gauge_area.width < (inner_label_width + start_label_width + 1) as u16 =>
+                {
+                    let inner_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
+                    let _ = buf.set_spans(
+                        gauge_area.left(),
+                        gauge_area.top(),
+                        &inner_label,
+                        inner_label.width() as u16,
+                    );
+
+                    // Short circuit.
+                    return;
+                }
+                _ => {
+                    let start_label = self.start_label.unwrap_or_else(|| Spans::from(""));
+                    buf.set_spans(
+                        gauge_area.left(),
+                        gauge_area.top(),
+                        &start_label,
+                        start_label.width() as u16,
+                    )
+                }
+            }
+        };
+
+        let end_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
+        match self.hide_parts {
+            LabelLimit::Bars => {
+                let _ = buf.set_spans(
+                    gauge_area
+                        .right()
+                        .saturating_sub(end_label.width() as u16 + 1),
+                    row,
+                    &end_label,
+                    end_label.width() as u16,
+                );
+            }
+            LabelLimit::Auto(width_limit)
+                if gauge_area.right().saturating_sub(col) < width_limit =>
+            {
+                let _ = buf.set_spans(
+                    gauge_area
+                        .right()
+                        .saturating_sub(end_label.width() as u16 + 1),
+                    row,
+                    &end_label,
+                    1,
+                );
+            }
+            LabelLimit::Auto(_) | LabelLimit::None => {
+                let (start, _) = buf.set_spans(col, row, &Spans::from("["), gauge_area.width);
+                if start >= gauge_area.right() {
+                    return;
+                }
+
+                let (end, _) = buf.set_spans(
+                    (gauge_area.x + gauge_area.width).saturating_sub(1),
+                    row,
+                    &Spans::from("]"),
+                    gauge_area.width,
+                );
+
+                let pipe_end =
+                    start + (f64::from(end.saturating_sub(start)) * self.ratio).floor() as u16;
+                for col in start..pipe_end {
+                    buf.get_mut(col, row).set_symbol("|").set_style(Style {
+                        fg: self.gauge_style.fg,
+                        bg: None,
+                        add_modifier: self.gauge_style.add_modifier,
+                        sub_modifier: self.gauge_style.sub_modifier,
+                    });
+                }
+
+                if (end_label.width() as u16) < end.saturating_sub(start) {
+                    let gauge_end = gauge_area
+                        .right()
+                        .saturating_sub(end_label.width() as u16 + 1);
+                    buf.set_spans(gauge_end, row, &end_label, end_label.width() as u16);
+                }
+            }
+            LabelLimit::StartLabel => unreachable!(),
+        }
+    }
+}