diff --git a/completions.go b/completions.go
index fd30e76c..5f555b6e 100644
--- a/completions.go
+++ b/completions.go
@@ -115,6 +115,9 @@ type CompletionOptions struct {
 	DisableDescriptions bool
 	// HiddenDefaultCmd makes the default 'completion' command hidden
 	HiddenDefaultCmd bool
+	// DefaultShellCompDirective sets the ShellCompDirective that is returned
+	// if no special directive can be determined
+	DefaultShellCompDirective ShellCompDirective
 }
 
 // Completion is a string that can be used for completions
@@ -480,6 +483,12 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo
 		}
 	} else {
 		directive = ShellCompDirectiveDefault
+
+		customShellCompDirective := finalCmd.CompletionOptions.DefaultShellCompDirective
+		if customShellCompDirective != ShellCompDirectiveDefault {
+			directive = customShellCompDirective
+		}
+
 		if flag == nil {
 			foundLocalNonPersistentFlag := false
 			// If TraverseChildren is true on the root command we don't check for
diff --git a/completions_test.go b/completions_test.go
index 62c203e1..44fbd367 100644
--- a/completions_test.go
+++ b/completions_test.go
@@ -3792,3 +3792,45 @@ func TestDisableDescriptions(t *testing.T) {
 		})
 	}
 }
+
+func TestCustomDefaultShellCompDirective(t *testing.T) {
+	rootCmd := &Command{Use: "root", Run: emptyRun}
+	rootCmd.Flags().String("string", "", "test string flag")
+	// use ShellCompDirectiveNoFileComp instead of the default, which is ShellCompDirectiveDefault
+	rootCmd.CompletionOptions.DefaultShellCompDirective = ShellCompDirectiveNoFileComp
+
+	testCases := []struct {
+		desc string
+		args []string
+	}{
+		{
+			"args completion with custom ShellCompDirective",
+			[]string{""},
+		},
+		{
+			"flag completion with custom ShellCompDirective",
+			[]string{"--string", ""},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.desc, func(t *testing.T) {
+			args := []string{ShellCompNoDescRequestCmd}
+			args = append(args, tc.args...)
+
+			output, err := executeCommand(rootCmd, args...)
+
+			if err != nil {
+				t.Errorf("Unexpected error: %v", err)
+			}
+
+			expected := strings.Join([]string{
+				":4",
+				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
+
+			if output != expected {
+				t.Errorf("expected: %q, got: %q", expected, output)
+			}
+		})
+	}
+}
diff --git a/site/content/completions/_index.md b/site/content/completions/_index.md
index fbe78014..a72306ba 100644
--- a/site/content/completions/_index.md
+++ b/site/content/completions/_index.md
@@ -304,6 +304,29 @@ $ helm status --output [tab][tab]
 json table yaml
 ```
 
+#### Change the default ShellCompDirective
+
+If Cobra cannot determine a special `ShellCompDirective` during flag parsing,
+it will return `ShellCompDirectiveDefault`, which will invoke the shell's filename completion.
+This is handy for flags that accept filenames, as they do not require a `FlagCompletionFunc`.
+
+For other flags where no meaningful completion can be provided, this requires extra work:
+You have to register a `FlagCompletionFunc` just to get rid of file completion.
+
+If you find yourself registering lots of handlers like
+
+```go
+cmd.RegisterFlagCompletionFunc("flag-name", cobra.NoFileCompletions)
+```
+
+you can change the default `ShellCompDirective` to `ShellCompDirectiveNoFileComp`:
+
+```go
+cmd.CompletionOptions.DefaultShellCompDirective = ShellCompDirectiveNoFileComp
+```
+
+Keep in mind that from now on you have to register handlers for every filename flag.
+
 #### Debugging
 
 You can also easily debug your Go completion code for flags: