diff --git a/command.go b/command.go
index 4794e5eb..33ce5e83 100644
--- a/command.go
+++ b/command.go
@@ -184,6 +184,8 @@ type Command struct {
 	helpCommand *Command
 	// helpCommandGroupID is the group id for the helpCommand
 	helpCommandGroupID string
+	// suggestOutputFunc is user's override for the suggestion output.
+	suggestOutputFunc func([]string) string
 
 	// completionCommandGroupID is the group id for the completion command
 	completionCommandGroupID string
@@ -348,6 +350,10 @@ func (c *Command) SetHelpCommandGroupID(groupID string) {
 	c.helpCommandGroupID = groupID
 }
 
+func (c *Command) SetSuggestOutputFunc(f func([]string) string) {
+	c.suggestOutputFunc = f
+}
+
 // SetCompletionCommandGroupID sets the group id of the completion command.
 func (c *Command) SetCompletionCommandGroupID(groupID string) {
 	// completionCommandGroupID is used if no completion command is defined by the user
@@ -778,15 +784,41 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
 	return commandFound, a, nil
 }
 
-func (c *Command) findSuggestions(arg string) string {
+// findSuggestions returns suggestions for the provided typedName if suggestions aren't disabled.
+// The output building function can be overridden by setting it with the SetSuggestOutputFunc.
+// If the output override is, instead, set on a parent, it uses the first one found.
+// If none is set, a default is used.
+func (c *Command) findSuggestions(typedName string) string {
 	if c.DisableSuggestions {
 		return ""
 	}
 	if c.SuggestionsMinimumDistance <= 0 {
 		c.SuggestionsMinimumDistance = 2
 	}
+
+	suggestions := c.SuggestionsFor(typedName)
+
+	if c.suggestOutputFunc != nil {
+		return c.suggestOutputFunc(suggestions)
+	}
+	if c.HasParent() {
+		var getParentFunc func(*Command) func([]string) string
+		getParentFunc = func(parent *Command) func([]string) string {
+			if parent.suggestOutputFunc != nil {
+				return parent.suggestOutputFunc
+			}
+			if !parent.HasParent() {
+				return nil
+			}
+			return getParentFunc(parent.Parent())
+		}
+		if parentFunc := getParentFunc(c.Parent()); parentFunc != nil {
+			return parentFunc(suggestions)
+		}
+	}
+
 	var sb strings.Builder
-	if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
+	if len(suggestions) > 0 {
 		sb.WriteString("\n\nDid you mean this?\n")
 		for _, s := range suggestions {
 			_, _ = fmt.Fprintf(&sb, "\t%v\n", s)
diff --git a/command_test.go b/command_test.go
index 156df9eb..ef6ac1dd 100644
--- a/command_test.go
+++ b/command_test.go
@@ -1475,6 +1475,128 @@ func TestSuggestions(t *testing.T) {
 	}
 }
 
+func TestCustomSuggestions(t *testing.T) {
+	rootCmd := &Command{Use: "root", Run: emptyRun}
+	timesCmd := &Command{Use: "times", Run: emptyRun}
+	rootCmd.AddCommand(timesCmd)
+
+	var expected, output string
+	suggestion := "times"
+	typo := "time"
+
+	expected = ""
+	output, _ = executeCommand(rootCmd, "times")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	expected = fmt.Sprintf("Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n", typo, suggestion)
+	output, _ = executeCommand(rootCmd, typo)
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	rootCmd.DisableSuggestions = true
+
+	expected = fmt.Sprintf("Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n", typo)
+	output, _ = executeCommand(rootCmd, typo)
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	rootCmd.DisableSuggestions = false
+	rootCmd.SetSuggestOutputFunc(func(suggestions []string) string {
+		return fmt.Sprintf("\nSuggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
+	})
+
+	expected = fmt.Sprintf("Error: unknown command \"%s\" for \"root\"\nSuggestions:\n\t%s\n\nRun 'root --help' for usage.\n", typo, suggestion)
+	output, _ = executeCommand(rootCmd, typo)
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+}
+
+func TestCustomSuggestions_OnlyValidArgs(t *testing.T) {
+	validArgs := []string{"a"}
+	rootCmd := &Command{Use: "root", Args: OnlyValidArgs, Run: emptyRun, ValidArgs: validArgs}
+	grandparentCmd := &Command{Use: "grandparent", Args: OnlyValidArgs, Run: emptyRun, ValidArgs: validArgs}
+	parentCmd := &Command{Use: "parent", Args: OnlyValidArgs, Run: emptyRun, ValidArgs: validArgs}
+	timesCmd := &Command{Use: "times", Run: emptyRun}
+	parentCmd.AddCommand(timesCmd)
+	grandparentCmd.AddCommand(parentCmd)
+	rootCmd.AddCommand(grandparentCmd)
+
+	var expected, output string
+
+	// No typos.
+	expected = ""
+	output, _ = executeCommand(rootCmd, "grandparent")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	expected = ""
+	output, _ = executeCommand(rootCmd, "grandparent", "parent")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	expected = ""
+	output, _ = executeCommand(rootCmd, "grandparent", "parent", "times")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	// 1st level typo.
+	expected = "Error: invalid argument \"grandparen\" for \"root\"\n\nDid you mean this?\n\tgrandparent\n\nUsage:\n  root [flags]\n  root [command]\n\nAvailable Commands:\n  completion  Generate the autocompletion script for the specified shell\n  grandparent \n  help        Help about any command\n\nFlags:\n  -h, --help   help for root\n\nUse \"root [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparen")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	// 2nd level typo.
+	expected = "Error: invalid argument \"paren\" for \"root grandparent\"\n\nDid you mean this?\n\tparent\n\nUsage:\n  root grandparent [flags]\n  root grandparent [command]\n\nAvailable Commands:\n  parent      \n\nFlags:\n  -h, --help   help for grandparent\n\nUse \"root grandparent [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparent", "paren")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	// 3rd level typo.
+	expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\n\nDid you mean this?\n\ttimes\n\nUsage:\n  root grandparent parent [flags]\n  root grandparent parent [command]\n\nAvailable Commands:\n  times       \n\nFlags:\n  -h, --help   help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	// Custom suggestion on root function.
+	rootCmd.SetSuggestOutputFunc(func(suggestions []string) string {
+		return fmt.Sprintf("\nRoot Suggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
+	})
+
+	expected = "Error: invalid argument \"grandparen\" for \"root\"\nRoot Suggestions:\n\tgrandparent\n\nUsage:\n  root [flags]\n  root [command]\n\nAvailable Commands:\n  completion  Generate the autocompletion script for the specified shell\n  grandparent \n  help        Help about any command\n\nFlags:\n  -h, --help   help for root\n\nUse \"root [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparen")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nRoot Suggestions:\n\ttimes\n\nUsage:\n  root grandparent parent [flags]\n  root grandparent parent [command]\n\nAvailable Commands:\n  times       \n\nFlags:\n  -h, --help   help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+
+	// Custom suggestion on parent function (kept root's to make sure this one is prioritised).
+	parentCmd.SetSuggestOutputFunc(func(suggestions []string) string {
+		return fmt.Sprintf("\nParent Suggestions:\n\t%s\n", strings.Join(suggestions, "\n"))
+	})
+
+	expected = "Error: invalid argument \"time\" for \"root grandparent parent\"\nParent Suggestions:\n\ttimes\n\nUsage:\n  root grandparent parent [flags]\n  root grandparent parent [command]\n\nAvailable Commands:\n  times       \n\nFlags:\n  -h, --help   help for parent\n\nUse \"root grandparent parent [command] --help\" for more information about a command.\n\n"
+	output, _ = executeCommand(rootCmd, "grandparent", "parent", "time")
+	if output != expected {
+		t.Errorf("\nExpected:\n %q\nGot:\n %q", expected, output)
+	}
+}
+
 func TestCaseInsensitive(t *testing.T) {
 	rootCmd := &Command{Use: "root", Run: emptyRun}
 	childCmd := &Command{Use: "child", Run: emptyRun, Aliases: []string{"alternative"}}