diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 8af5c8c23..b95c9762b 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -18,6 +18,7 @@ Interactive improvements
   when typing a command and :kbd:`enter` while the previous one is still running, the new one will no longer execute immediately. Similarly, keys that are bound to shell commands will be ignored.
   This mitigates a security issue where a command like ``cat malicious-file.txt`` could write terminal escape codes prompting the terminal to write arbitrary text to fish's standard input.
   Such a malicious file can still potentially insert arbitrary text into the command line but can no longer execute it directly (:issue:`10987`).
+- Left mouse click now can select pager items.
 
 New or improved bindings
 ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/pager.rs b/src/pager.rs
index 430182ace..e529cf5d5 100644
--- a/src/pager.rs
+++ b/src/pager.rs
@@ -13,7 +13,7 @@ use crate::future::IsSomeAnd;
 use crate::highlight::{highlight_shell, HighlightRole, HighlightSpec};
 use crate::libc::MB_CUR_MAX;
 use crate::operation_context::OperationContext;
-use crate::screen::{wcswidth_rendered, wcwidth_rendered, Line, ScreenData};
+use crate::screen::{wcswidth_rendered, wcwidth_rendered, CharOffset, Line, ScreenData};
 use crate::termsize::Termsize;
 use crate::wchar::prelude::*;
 use crate::wcstringutil::string_fuzzy_match_string;
@@ -253,9 +253,7 @@ impl Pager {
         assert!(stop_row <= row_count);
         assert!(stop_row - start_row <= term_height);
         // This always printed at the end of the command line.
-        let offset_in_cmdline = usize::MAX;
         self.completion_print(
-            offset_in_cmdline,
             cols,
             &width_by_column,
             start_row,
@@ -300,7 +298,7 @@ impl Pager {
                 HighlightRole::pager_progress,
             );
             print_max(
-                offset_in_cmdline,
+                CharOffset::None,
                 &progress_text,
                 spec,
                 term_width,
@@ -329,7 +327,7 @@ impl Pager {
 
         let mut search_field_remaining = term_width - 1;
         search_field_remaining -= print_max(
-            offset_in_cmdline,
+            CharOffset::None,
             wgettext!(SEARCH_FIELD_PROMPT),
             HighlightSpec::new(),
             search_field_remaining,
@@ -337,7 +335,7 @@ impl Pager {
             search_field,
         );
         search_field_remaining -= print_max(
-            offset_in_cmdline,
+            CharOffset::None,
             &search_field_text,
             underline,
             search_field_remaining,
@@ -407,7 +405,6 @@ impl Pager {
     /// \param lst The list of completions to print
     fn completion_print(
         &self,
-        offset_in_cmdline: usize,
         cols: usize,
         width_by_column: &[usize; PAGER_MAX_COLS],
         row_start: usize,
@@ -437,7 +434,7 @@ impl Pager {
 
                 // Print this completion on its own "line".
                 let mut line = self.completion_print_item(
-                    offset_in_cmdline,
+                    CharOffset::Pager(idx),
                     prefix,
                     el,
                     col_width,
@@ -447,7 +444,7 @@ impl Pager {
 
                 // If there's more to come, append two spaces.
                 if col + 1 < cols {
-                    line.append_str(PAGER_SPACER_STRING, HighlightSpec::new(), offset_in_cmdline);
+                    line.append_str(PAGER_SPACER_STRING, HighlightSpec::new(), CharOffset::None);
                 }
 
                 // Append this to the real line.
@@ -462,7 +459,7 @@ impl Pager {
     /// Print the specified item using at the specified amount of space.
     fn completion_print_item(
         &self,
-        offset_in_cmdline: usize,
+        offset_in_cmdline: CharOffset,
         prefix: &wstr,
         c: &PagerComp,
         width: usize,
@@ -1100,7 +1097,7 @@ fn divide_round_up(numer: usize, denom: usize) -> usize {
 /// \param has_more if this flag is true, this is not the entire string, and the string should be
 /// ellipsized even if the string fits but takes up the whole space.
 fn print_max_impl(
-    offset_in_cmdline: usize,
+    offset_in_cmdline: CharOffset,
     s: &wstr,
     color: impl Fn(usize) -> HighlightSpec,
     max: usize,
@@ -1136,7 +1133,7 @@ fn print_max_impl(
 }
 
 fn print_max(
-    offset_in_cmdline: usize,
+    offset_in_cmdline: CharOffset,
     s: &wstr,
     color: HighlightSpec,
     max: usize,
diff --git a/src/reader.rs b/src/reader.rs
index 33604113a..03a8cbc78 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -120,7 +120,7 @@ use crate::proc::{
     print_exit_warning_for_jobs, proc_update_jiffies,
 };
 use crate::reader_history_search::{smartcase_flags, ReaderHistorySearch, SearchMode};
-use crate::screen::{screen_clear, screen_force_clear_to_end, Screen};
+use crate::screen::{screen_clear, screen_force_clear_to_end, CharOffset, Screen};
 use crate::signal::{
     signal_check_cancel, signal_clear_cancel, signal_reset_handlers, signal_set_handlers,
     signal_set_handlers_once,
@@ -1403,11 +1403,20 @@ impl ReaderData {
             "; received left mouse click at",
             click_position
         );
-        let new_pos = self
+        match self
             .screen
-            .offset_in_cmdline_given_cursor(click_position, cursor);
-        let (elt, _el) = self.active_edit_line();
-        self.update_buff_pos(elt, Some(new_pos));
+            .offset_in_cmdline_given_cursor(click_position, cursor)
+        {
+            CharOffset::Cmd(new_pos) | CharOffset::Pointer(new_pos) => {
+                let (elt, _el) = self.active_edit_line();
+                self.update_buff_pos(elt, Some(new_pos));
+            }
+            CharOffset::Pager(idx) if self.pager.selected_completion_idx != Some(idx) => {
+                self.pager.selected_completion_idx = Some(idx);
+                self.pager_selection_changed();
+            }
+            _ => {}
+        }
     }
 }
 
diff --git a/src/screen.rs b/src/screen.rs
index 03adf13cd..d94dbde7b 100644
--- a/src/screen.rs
+++ b/src/screen.rs
@@ -42,12 +42,21 @@ use crate::wchar::prelude::*;
 use crate::wcstringutil::string_prefixes_string;
 use crate::wutil::fstat;
 
+#[derive(Copy, Clone, Default)]
+pub enum CharOffset {
+    #[default]
+    None,
+    Cmd(usize),
+    Pointer(usize),
+    Pager(usize),
+}
+
 #[derive(Clone, Default)]
 pub struct HighlightedChar {
     highlight: HighlightSpec,
     character: char,
     // Logical offset within the command line.
-    offset_in_cmdline: usize,
+    offset_in_cmdline: CharOffset,
 }
 
 /// A class representing a single line of a screen.
@@ -70,7 +79,12 @@ impl Line {
     }
 
     /// Append a single character `txt` to the line with color `c`.
-    pub fn append(&mut self, character: char, highlight: HighlightSpec, offset_in_cmdline: usize) {
+    pub fn append(
+        &mut self,
+        character: char,
+        highlight: HighlightSpec,
+        offset_in_cmdline: CharOffset,
+    ) {
         self.text.push(HighlightedChar {
             highlight,
             character: rendered_character(character),
@@ -79,7 +93,12 @@ impl Line {
     }
 
     /// Append a nul-terminated string `txt` to the line, giving each character `color`.
-    pub fn append_str(&mut self, txt: &wstr, highlight: HighlightSpec, offset_in_cmdline: usize) {
+    pub fn append_str(
+        &mut self,
+        txt: &wstr,
+        highlight: HighlightSpec,
+        offset_in_cmdline: CharOffset,
+    ) {
         for c in txt.chars() {
             self.append(c, highlight, offset_in_cmdline);
         }
@@ -101,7 +120,7 @@ impl Line {
     }
 
     /// Return the logical offset corresponding to this cell
-    pub fn offset_in_cmdline_at(&self, idx: usize) -> usize {
+    pub fn offset_in_cmdline_at(&self, idx: usize) -> CharOffset {
         self.text[idx].offset_in_cmdline
     }
 
@@ -338,9 +357,14 @@ impl Screen {
         self.desired.cursor.y = 0;
 
         // Append spaces for the left prompt.
+        let prompt_offset = if pager.search_field_shown {
+            CharOffset::None
+        } else {
+            CharOffset::Pointer(0)
+        };
         for _ in 0..layout.left_prompt_space {
             let _ = self.desired_append_char(
-                /*offset_in_cmdline=*/ 0,
+                prompt_offset,
                 usize::MAX,
                 ' ',
                 HighlightSpec::new(),
@@ -386,11 +410,14 @@ impl Screen {
                 break scrolled_cursor.unwrap();
             }
             if !self.desired_append_char(
-                /*offset_in_cmdline=*/
-                if i <= explicit_before_suggestion.len() + layout.autosuggestion.len() {
-                    i.min(explicit_before_suggestion.len())
+                if pager.search_field_shown {
+                    CharOffset::None
+                } else if i < explicit_before_suggestion.len() {
+                    CharOffset::Cmd(i)
+                } else if i < explicit_before_suggestion.len() + layout.autosuggestion.len() {
+                    CharOffset::Pointer(explicit_before_suggestion.len())
                 } else {
-                    i - layout.autosuggestion.len()
+                    CharOffset::Cmd(i - layout.autosuggestion.len())
                 },
                 if is_final_rendering {
                     usize::MAX
@@ -553,7 +580,7 @@ impl Screen {
         &mut self,
         viewport_position: ViewportPosition,
         viewport_cursor: ViewportPosition,
-    ) -> usize {
+    ) -> CharOffset {
         let viewport_prompt_y = self.command_line_y_given_cursor_y(viewport_cursor.y);
         let y = viewport_position
             .y
@@ -574,14 +601,11 @@ impl Screen {
         let x = viewport_position.x - viewport_prompt_x;
         let line = self.actual.line(y);
         let x = x.max(line.indentation);
-        if x >= line.len() {
-            if self.actual.line_count() == 1 {
-                0
-            } else {
-                line.text.last().unwrap().offset_in_cmdline + 1
-            }
-        } else {
-            line.offset_in_cmdline_at(x)
+        let char = line.text.get(x).or(line.text.last()).unwrap();
+        match char.offset_in_cmdline {
+            CharOffset::Cmd(value) if x >= line.len() => CharOffset::Cmd(value + 1),
+            CharOffset::Pager(_) if x >= line.len() => CharOffset::None,
+            offset => offset,
         }
     }
 
@@ -706,7 +730,7 @@ impl Screen {
     /// automatically handles linebreaks and lines longer than the screen width.
     fn desired_append_char(
         &mut self,
-        offset_in_cmdline: usize,
+        offset_in_cmdline: CharOffset,
         max_y: usize,
         b: char,
         c: HighlightSpec,