diff --git a/docs/content/rules/sort-array-includes.mdx b/docs/content/rules/sort-array-includes.mdx
index c0a3f1679..57ae2d215 100644
--- a/docs/content/rules/sort-array-includes.mdx
+++ b/docs/content/rules/sort-array-includes.mdx
@@ -177,10 +177,12 @@ Specifies the sorting locales. See [String.prototype.localeCompare() - locales](
 - `string` — A BCP 47 language tag (e.g. `'en'`, `'en-US'`, `'zh-CN'`).
 - `string[]` — An array of BCP 47 language tags.
 
-### groupKind
+### [DEPRECATED] groupKind
 
 <sub>default: `'literals-first'`</sub>
 
+Use the [groups](#groups) option with the `literal` and `spread` selectors instead. Make sure to set this option to `mixed`.
+
 Allows you to group array elements by their kind, determining whether spread values should come before or after literal values.
 
 - `mixed` — Do not group array elements by their kind; spread values are sorted together with literal values.
@@ -228,6 +230,129 @@ if ([
 
 Each group of elements (separated by empty lines) is treated independently, and the order within each group is preserved.
 
+### useConfigurationIf
+
+<sub>
+  type: `{ allNamesMatchPattern?: string }`
+</sub>
+<sub>default: `{}`</sub>
+
+Allows you to specify filters to match a particular options configuration for a given object.
+
+The first matching options configuration will be used. If no configuration matches, the default options configuration will be used.
+
+- `allNamesMatchPattern` — A regexp pattern that all object keys must match.
+
+Example configuration:
+```ts
+{
+  'perfectionist/sort-array-includes': [
+    'error',
+    {
+      groups: ['r', 'g', 'b'], // Sort colors by RGB
+      customGroups: [
+        {
+          elementNamePattern: '^r$',
+          groupName: 'r',
+        },
+        {
+          elementNamePattern: '^g$',
+          groupName: 'g',
+        },
+        {
+          elementNamePattern: '^b$',
+          groupName: 'b',
+        },
+      ],
+      useConfigurationIf: {
+        allNamesMatchPattern: '^r|g|b$',
+      },
+    },
+    {
+      type: 'alphabetical' // Fallback configuration
+    }
+  ],
+}
+```
+
+### groups
+
+<sub>
+  type: `Array<string | string[]>`
+</sub>
+<sub>default: `[]`</sub>
+
+Allows you to specify a list of groups for sorting. Groups help organize elements into categories.
+
+Each element will be assigned a single group specified in the `groups` option (or the `unknown` group if no match is found).
+The order of items in the `groups` option determines how groups are ordered.
+
+Within a given group, members will be sorted according to the `type`, `order`, `ignoreCase`, etc. options.
+
+Individual groups can be combined together by placing them in an array. The order of groups in that array does not matter.
+All members of the groups in the array will be sorted together as if they were part of a single group.
+
+Predefined groups are characterized by a selector.
+
+##### List of selectors
+
+- `literal`: Array elements that are not spread values.
+- `spread`: Array elements that are spread values.
+
+### customGroups
+
+<sub>
+  type: `Array<CustomGroupDefinition | CustomGroupAnyOfDefinition>`
+</sub>
+<sub>default: `{}`</sub>
+
+You can define your own groups and use regexp pattern to match specific object type members.
+
+A custom group definition may follow one of the two following interfaces:
+
+```ts
+interface CustomGroupDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  selector?: string
+  elementNamePattern?: string
+}
+
+```
+An array element will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
+
+or:
+
+```ts
+interface CustomGroupAnyOfDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  anyOf: Array<{
+      selector?: string
+      elementNamePattern?: string
+  }>
+}
+```
+
+An array element will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
+
+#### Attributes
+
+- `groupName`: The group's name, which needs to be put in the `groups` option.
+- `selector`: Filter on the `selector` of the element.
+- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
+- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
+- `order`: Overrides the sort order for that custom group
+
+#### Match importance
+
+The `customGroups` list is ordered:
+The first custom group definition that matches an element will be used.
+
+Custom groups have a higher priority than any predefined group.
+
 ## Usage
 
 <CodeTabs
@@ -252,6 +377,9 @@ Each group of elements (separated by empty lines) is treated independently, and
                   specialCharacters: 'keep',
                   groupKind: 'literals-first',
                   partitionByNewLine: false,
+                  useConfigurationIf: {},
+                  groups: [],
+                  customGroups: [],
                 },
               ],
             },
@@ -278,6 +406,9 @@ Each group of elements (separated by empty lines) is treated independently, and
                 specialCharacters: 'keep',
                 groupKind: 'literals-first',
                 partitionByNewLine: false,
+                useConfigurationIf: {},
+                groups: [],
+                customGroups: [],
               },
             ],
           },
diff --git a/docs/content/rules/sort-interfaces.mdx b/docs/content/rules/sort-interfaces.mdx
index 2778809bb..4947477ec 100644
--- a/docs/content/rules/sort-interfaces.mdx
+++ b/docs/content/rules/sort-interfaces.mdx
@@ -410,12 +410,53 @@ Current API:
 
 You can define your own groups and use regexp patterns to match specific interface members.
 
-Each key of `customGroups` represents a group name which you can then use in the `groups` option. The value for each key can either be of type:
-- `string` — An interface member's name matching the value will be marked as part of the group referenced by the key.
-- `string[]` — An interface member's name matching any of the values of the array will be marked as part of the group referenced by the key.
-The order of values in the array does not matter.
+A custom group definition may follow one of the two following interfaces:
 
-Custom group matching takes precedence over predefined group matching.
+```ts
+interface CustomGroupDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  selector?: string
+  modifiers?: string[]
+  elementNamePattern?: string
+}
+
+```
+An interface member will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
+
+or:
+
+```ts
+interface CustomGroupAnyOfDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  anyOf: Array<{
+      selector?: string
+      modifiers?: string[]
+      elementNamePattern?: string
+  }>
+}
+```
+
+An interface member will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
+
+#### Attributes
+
+- `groupName`: The group's name, which needs to be put in the `groups` option.
+- `selector`: Filter on the `selector` of the element.
+- `modifiers`: Filter on the `modifiers` of the element. (All the modifiers of the element must be present in that list)
+- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
+- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
+- `order`: Overrides the sort order for that custom group
+
+#### Match importance
+
+The `customGroups` list is ordered:
+The first custom group definition that matches an element will be used.
+
+Custom groups have a higher priority than any predefined group.
 
 #### Example
 
diff --git a/docs/content/rules/sort-object-types.mdx b/docs/content/rules/sort-object-types.mdx
index 6502ba459..4ee7dbcf6 100644
--- a/docs/content/rules/sort-object-types.mdx
+++ b/docs/content/rules/sort-object-types.mdx
@@ -375,12 +375,53 @@ Current API:
 
 You can define your own groups and use regexp pattern to match specific object type members.
 
-Each key of `customGroups` represents a group name which you can then use in the `groups` option. The value for each key can either be of type:
-- `string` — A type member's name matching the value will be marked as part of the group referenced by the key.
-- `string[]` — A type member's name matching any of the values of the array will be marked as part of the group referenced by the key.
-The order of values in the array does not matter.
+A custom group definition may follow one of the two following interfaces:
 
-Custom group matching takes precedence over predefined group matching.
+```ts
+interface CustomGroupDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  selector?: string
+  modifiers?: string[]
+  elementNamePattern?: string
+}
+
+```
+An object type will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
+
+or:
+
+```ts
+interface CustomGroupAnyOfDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  anyOf: Array<{
+      selector?: string
+      modifiers?: string[]
+      elementNamePattern?: string
+  }>
+}
+```
+
+An object type will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
+
+#### Attributes
+
+- `groupName`: The group's name, which needs to be put in the `groups` option.
+- `selector`: Filter on the `selector` of the element.
+- `modifiers`: Filter on the `modifiers` of the element. (All the modifiers of the element must be present in that list)
+- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
+- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
+- `order`: Overrides the sort order for that custom group
+
+#### Match importance
+
+The `customGroups` list is ordered:
+The first custom group definition that matches an element will be used.
+
+Custom groups have a higher priority than any predefined group.
 
 #### Example
 
diff --git a/docs/content/rules/sort-objects.mdx b/docs/content/rules/sort-objects.mdx
index 2a8248460..80048322b 100644
--- a/docs/content/rules/sort-objects.mdx
+++ b/docs/content/rules/sort-objects.mdx
@@ -320,9 +320,9 @@ Example configuration:
     {
       groups: ['r', 'g', 'b'], // Sort colors by RGB
       customGroups: {
-        r: 'r',
-        g: 'g',
-        b: 'b',
+        r: '^r$',
+        g: '^g$',
+        b: '^b$',
       },
       useConfigurationIf: {
         allNamesMatchPattern: '^r|g|b$',
diff --git a/docs/content/rules/sort-sets.mdx b/docs/content/rules/sort-sets.mdx
index 99bc8d876..a986afa70 100644
--- a/docs/content/rules/sort-sets.mdx
+++ b/docs/content/rules/sort-sets.mdx
@@ -183,10 +183,12 @@ Specifies the sorting locales. See [String.prototype.localeCompare() - locales](
 - `string` — A BCP 47 language tag (e.g. `'en'`, `'en-US'`, `'zh-CN'`).
 - `string[]` — An array of BCP 47 language tags.
 
-### groupKind
+### [DEPRECATED] groupKind
 
 <sub>default: `'literals-first'`</sub>
 
+Use the [groups](#groups) option with the `literal` and `spread` selectors instead. Make sure to set this option to `mixed`.
+
 Allows you to group set elements by their kind, determining whether spread values should come before or after literal values.
 
 - `mixed` — Do not group set elements by their kind; spread values are sorted together with literal values.
@@ -232,6 +234,84 @@ let items = new Set([
 
 Each group of elements (separated by empty lines) is treated independently, and the order within each group is preserved.
 
+### groups
+
+<sub>
+  type: `Array<string | string[]>`
+</sub>
+<sub>default: `[]`</sub>
+
+Allows you to specify a list of groups for sorting. Groups help organize elements into categories.
+
+Each element will be assigned a single group specified in the `groups` option (or the `unknown` group if no match is found).
+The order of items in the `groups` option determines how groups are ordered.
+
+Within a given group, members will be sorted according to the `type`, `order`, `ignoreCase`, etc. options.
+
+Individual groups can be combined together by placing them in an array. The order of groups in that array does not matter.
+All members of the groups in the array will be sorted together as if they were part of a single group.
+
+Predefined groups are characterized by a selector.
+
+##### List of selectors
+
+- `literal`: Array elements that are not spread values.
+- `spread`: Array elements that are spread values.
+
+### customGroups
+
+<sub>
+  type: `Array<CustomGroupDefinition | CustomGroupAnyOfDefinition>`
+</sub>
+<sub>default: `{}`</sub>
+
+You can define your own groups and use regexp pattern to match specific object type members.
+
+A custom group definition may follow one of the two following interfaces:
+
+```ts
+interface CustomGroupDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  selector?: string
+  elementNamePattern?: string
+}
+
+```
+A set element will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
+
+or:
+
+```ts
+interface CustomGroupAnyOfDefinition {
+  groupName: string
+  type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
+  order?: 'asc' | 'desc'
+  anyOf: Array<{
+      selector?: string
+      elementNamePattern?: string
+  }>
+}
+```
+
+A set element will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
+
+#### Attributes
+
+- `groupName`: The group's name, which needs to be put in the `groups` option.
+- `selector`: Filter on the `selector` of the element.
+- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
+- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
+- `order`: Overrides the sort order for that custom group
+
+#### Match importance
+
+The `customGroups` list is ordered:
+The first custom group definition that matches an element will be used.
+
+Custom groups have a higher priority than any predefined group.
+
 ## Usage
 
 <CodeTabs
@@ -256,6 +336,9 @@ Each group of elements (separated by empty lines) is treated independently, and
                   specialCharacters: 'keep',
                   groupKind: 'literals-first',
                   partitionByNewLine: false,
+                  useConfigurationIf: {},
+                  groups: [],
+                  customGroups: [],
                 },
               ],
             },
@@ -282,6 +365,9 @@ Each group of elements (separated by empty lines) is treated independently, and
                 specialCharacters: 'keep',
                 groupKind: 'literals-first',
                 partitionByNewLine: false,
+                useConfigurationIf: {},
+                groups: [],
+                customGroups: [],
               },
             ],
           },
diff --git a/rules/sort-array-includes-utils.ts b/rules/sort-array-includes-utils.ts
new file mode 100644
index 000000000..349e517de
--- /dev/null
+++ b/rules/sort-array-includes-utils.ts
@@ -0,0 +1,50 @@
+import type {
+  SingleCustomGroup,
+  AnyOfCustomGroup,
+  Selector,
+} from './sort-array-includes.types'
+
+import { matches } from '../utils/matches'
+
+interface CustomGroupMatchesProps {
+  customGroup: SingleCustomGroup | AnyOfCustomGroup
+  selectors: Selector[]
+  elementName: string
+}
+
+/**
+ * Determines whether a custom group matches the given properties.
+ * @param {CustomGroupMatchesProps} props - The properties to compare with the
+ * custom group, including selectors, modifiers, and element name.
+ * @returns {boolean} `true` if the custom group matches the properties;
+ * otherwise, `false`.
+ */
+export let customGroupMatches = (props: CustomGroupMatchesProps): boolean => {
+  if ('anyOf' in props.customGroup) {
+    // At least one subgroup must match
+    return props.customGroup.anyOf.some(subgroup =>
+      customGroupMatches({ ...props, customGroup: subgroup }),
+    )
+  }
+  if (
+    props.customGroup.selector &&
+    !props.selectors.includes(props.customGroup.selector)
+  ) {
+    return false
+  }
+
+  if (
+    'elementNamePattern' in props.customGroup &&
+    props.customGroup.elementNamePattern
+  ) {
+    let matchesElementNamePattern: boolean = matches(
+      props.elementName,
+      props.customGroup.elementNamePattern,
+    )
+    if (!matchesElementNamePattern) {
+      return false
+    }
+  }
+
+  return true
+}
diff --git a/rules/sort-array-includes.ts b/rules/sort-array-includes.ts
index b7dbb5751..0463ef419 100644
--- a/rules/sort-array-includes.ts
+++ b/rules/sort-array-includes.ts
@@ -1,93 +1,109 @@
 import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'
 import type { RuleContext } from '@typescript-eslint/utils/ts-eslint'
 import type { TSESTree } from '@typescript-eslint/types'
+import type { TSESLint } from '@typescript-eslint/utils'
 
+import type { Selector, Options } from './sort-array-includes.types'
 import type { SortingNode } from '../typings'
 
 import {
+  buildCustomGroupsArrayJsonSchema,
   partitionByCommentJsonSchema,
+  useConfigurationIfJsonSchema,
+  partitionByNewLineJsonSchema,
   specialCharactersJsonSchema,
   ignoreCaseJsonSchema,
   alphabetJsonSchema,
   localesJsonSchema,
+  groupsJsonSchema,
   orderJsonSchema,
   typeJsonSchema,
 } from '../utils/common-json-schemas'
+import { validateGeneratedGroupsConfiguration } from '../utils/validate-generated-groups-configuration'
+import { getCustomGroupsCompareOptions } from '../utils/get-custom-groups-compare-options'
+import { getMatchingContextOptions } from '../utils/get-matching-context-options'
+import { generatePredefinedGroups } from '../utils/generate-predefined-groups'
 import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines'
+import { singleCustomGroupJsonSchema } from './sort-array-includes.types'
 import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled'
 import { hasPartitionComment } from '../utils/is-partition-comment'
+import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
 import { getCommentsBefore } from '../utils/get-comments-before'
+import { customGroupMatches } from './sort-array-includes-utils'
 import { createEslintRule } from '../utils/create-eslint-rule'
 import { getLinesBetween } from '../utils/get-lines-between'
+import { allSelectors } from './sort-array-includes.types'
+import { getGroupNumber } from '../utils/get-group-number'
 import { getSourceCode } from '../utils/get-source-code'
 import { toSingleLine } from '../utils/to-single-line'
 import { rangeToDiff } from '../utils/range-to-diff'
 import { getSettings } from '../utils/get-settings'
 import { isSortable } from '../utils/is-sortable'
-import { sortNodes } from '../utils/sort-nodes'
 import { makeFixes } from '../utils/make-fixes'
+import { useGroups } from '../utils/use-groups'
 import { complete } from '../utils/complete'
 import { pairwise } from '../utils/pairwise'
 
-export type Options = [
-  Partial<{
-    type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
-    groupKind: 'literals-first' | 'spreads-first' | 'mixed'
-    partitionByComment: string[] | boolean | string
-    specialCharacters: 'remove' | 'trim' | 'keep'
-    locales: NonNullable<Intl.LocalesArgument>
-    partitionByNewLine: boolean
-    order: 'desc' | 'asc'
-    ignoreCase: boolean
-    alphabet: string
-  }>,
-]
+/**
+ * Cache computed groups by modifiers and selectors for performance
+ */
+let cachedGroupsByModifiersAndSelectors = new Map<string, string[]>()
 
 interface SortArrayIncludesSortingNode
   extends SortingNode<TSESTree.SpreadElement | TSESTree.Expression> {
   groupKind: 'literal' | 'spread'
 }
 
-type MESSAGE_ID = 'unexpectedArrayIncludesOrder'
+type MESSAGE_ID =
+  | 'unexpectedArrayIncludesGroupOrder'
+  | 'unexpectedArrayIncludesOrder'
 
 export let defaultOptions: Required<Options[0]> = {
   groupKind: 'literals-first',
   specialCharacters: 'keep',
   partitionByComment: false,
   partitionByNewLine: false,
+  useConfigurationIf: {},
   type: 'alphabetical',
   ignoreCase: true,
   locales: 'en-US',
+  customGroups: [],
   alphabet: '',
   order: 'asc',
+  groups: [],
 }
 
 export let jsonSchema: JSONSchema4 = {
-  properties: {
-    partitionByComment: {
-      ...partitionByCommentJsonSchema,
-      description:
-        'Allows you to use comments to separate the array members into logical groups.',
+  items: {
+    properties: {
+      partitionByComment: {
+        ...partitionByCommentJsonSchema,
+        description:
+          'Allows you to use comments to separate the array members into logical groups.',
+      },
+      groupKind: {
+        enum: ['mixed', 'literals-first', 'spreads-first'],
+        description: 'Specifies top-level groups.',
+        type: 'string',
+      },
+      customGroups: buildCustomGroupsArrayJsonSchema({
+        singleCustomGroupJsonSchema,
+      }),
+      partitionByNewLine: partitionByNewLineJsonSchema,
+      useConfigurationIf: useConfigurationIfJsonSchema,
+      specialCharacters: specialCharactersJsonSchema,
+      ignoreCase: ignoreCaseJsonSchema,
+      alphabet: alphabetJsonSchema,
+      locales: localesJsonSchema,
+      groups: groupsJsonSchema,
+      order: orderJsonSchema,
+      type: typeJsonSchema,
     },
-    groupKind: {
-      enum: ['mixed', 'literals-first', 'spreads-first'],
-      description: 'Specifies top-level groups.',
-      type: 'string',
-    },
-    partitionByNewLine: {
-      description:
-        'Allows to use spaces to separate the nodes into logical groups.',
-      type: 'boolean',
-    },
-    specialCharacters: specialCharactersJsonSchema,
-    ignoreCase: ignoreCaseJsonSchema,
-    alphabet: alphabetJsonSchema,
-    locales: localesJsonSchema,
-    order: orderJsonSchema,
-    type: typeJsonSchema,
+    additionalProperties: false,
+    type: 'object',
   },
-  additionalProperties: false,
-  type: 'object',
+  uniqueItems: true,
+  type: 'array',
 }
 
 export default createEslintRule<Options, MESSAGE_ID>({
@@ -103,21 +119,30 @@ export default createEslintRule<Options, MESSAGE_ID>({
           node.object.type === 'ArrayExpression'
             ? node.object.elements
             : node.object.arguments
-        sortArray<MESSAGE_ID>(context, 'unexpectedArrayIncludesOrder', elements)
+        sortArray<MESSAGE_ID>({
+          availableMessageIds: {
+            unexpectedGroupOrder: 'unexpectedArrayIncludesGroupOrder',
+            unexpectedOrder: 'unexpectedArrayIncludesOrder',
+          },
+          elements,
+          context,
+        })
       }
     },
   }),
   meta: {
+    messages: {
+      unexpectedArrayIncludesGroupOrder:
+        'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
+      unexpectedArrayIncludesOrder:
+        'Expected "{{right}}" to come before "{{left}}".',
+    },
     docs: {
       description: 'Enforce sorted arrays before include method.',
       url: 'https://perfectionist.dev/rules/sort-array-includes',
       recommended: true,
     },
-    messages: {
-      unexpectedArrayIncludesOrder:
-        'Expected "{{right}}" to come before "{{left}}".',
-    },
-    schema: [jsonSchema],
+    schema: jsonSchema,
     type: 'suggestion',
     fixable: 'code',
   },
@@ -125,18 +150,38 @@ export default createEslintRule<Options, MESSAGE_ID>({
   name: 'sort-array-includes',
 })
 
-export let sortArray = <MessageIds extends string>(
-  context: Readonly<RuleContext<MessageIds, Options>>,
-  messageId: MessageIds,
-  elements: (TSESTree.SpreadElement | TSESTree.Expression | null)[],
-): void => {
+export let sortArray = <MessageIds extends string>({
+  availableMessageIds,
+  elements,
+  context,
+}: {
+  availableMessageIds: {
+    unexpectedGroupOrder: MessageIds
+    unexpectedOrder: MessageIds
+  }
+  elements: (TSESTree.SpreadElement | TSESTree.Expression | null)[]
+  context: Readonly<RuleContext<MessageIds, Options>>
+}): void => {
   if (!isSortable(elements)) {
     return
   }
 
-  let settings = getSettings(context.settings)
-  let options = complete(context.options.at(0), settings, defaultOptions)
   let sourceCode = getSourceCode(context)
+  let settings = getSettings(context.settings)
+  let matchedContextOptions = getMatchingContextOptions({
+    nodeNames: elements
+      .filter(element => element !== null)
+      .map(element => getNodeName({ sourceCode, element })),
+    contextOptions: context.options,
+  })
+  let options = complete(matchedContextOptions, settings, defaultOptions)
+  validateGeneratedGroupsConfiguration({
+    customGroups: options.customGroups,
+    selectors: allSelectors,
+    groups: options.groups,
+    modifiers: [],
+  })
+
   let eslintDisabledLines = getEslintDisabledLines({
     ruleName: context.id,
     sourceCode,
@@ -150,17 +195,52 @@ export let sortArray = <MessageIds extends string>(
         return accumulator
       }
 
-      let lastSortingNode = accumulator.at(-1)?.at(-1)
+      let { defineGroup, getGroup } = useGroups(options)
+      let groupKind: 'literal' | 'spread'
+      let selector: Selector
+      if (element.type === 'SpreadElement') {
+        groupKind = 'spread'
+        selector = 'spread'
+      } else {
+        groupKind = 'literal'
+        selector = 'literal'
+      }
+
+      for (let predefinedGroup of generatePredefinedGroups({
+        cache: cachedGroupsByModifiersAndSelectors,
+        selectors: [selector],
+        modifiers: [],
+      })) {
+        defineGroup(predefinedGroup)
+      }
+
+      let name = getNodeName({ sourceCode, element })
+      for (let customGroup of options.customGroups) {
+        if (
+          customGroupMatches({
+            selectors: [selector],
+            elementName: name,
+            customGroup,
+          })
+        ) {
+          defineGroup(customGroup.groupName, true)
+          // If the custom group is not referenced in the `groups` option, it will be ignored
+          if (getGroup() === customGroup.groupName) {
+            break
+          }
+        }
+      }
+
       let sortingNode: SortArrayIncludesSortingNode = {
-        name:
-          element.type === 'Literal'
-            ? `${element.value}`
-            : sourceCode.getText(element),
         isEslintDisabled: isNodeEslintDisabled(element, eslintDisabledLines),
-        groupKind: element.type === 'SpreadElement' ? 'spread' : 'literal',
+        name: getNodeName({ sourceCode, element }),
         size: rangeToDiff(element, sourceCode),
+        group: getGroup(),
         node: element,
+        groupKind,
       }
+
+      let lastSortingNode = accumulator.at(-1)?.at(-1)
       if (
         (options.partitionByComment &&
           hasPartitionComment(
@@ -205,7 +285,11 @@ export let sortArray = <MessageIds extends string>(
       ignoreEslintDisabledNodes: boolean,
     ): SortArrayIncludesSortingNode[] =>
       filteredGroupKindNodes.flatMap(groupedNodes =>
-        sortNodes(groupedNodes, options, { ignoreEslintDisabledNodes }),
+        sortNodesByGroups(groupedNodes, options, {
+          getGroupCompareOptions: groupNumber =>
+            getCustomGroupsCompareOptions(options, groupNumber),
+          ignoreEslintDisabledNodes,
+        }),
       )
     let sortedNodes = sortNodesIgnoringEslintDisabledNodes(false)
     let sortedNodesExcludingEslintDisabled =
@@ -214,6 +298,9 @@ export let sortArray = <MessageIds extends string>(
     pairwise(nodes, (left, right) => {
       let indexOfLeft = sortedNodes.indexOf(left)
       let indexOfRight = sortedNodes.indexOf(right)
+      let leftNumber = getGroupNumber(options.groups, left)
+      let rightNumber = getGroupNumber(options.groups, right)
+
       let indexOfRightExcludingEslintDisabled =
         sortedNodesExcludingEslintDisabled.indexOf(right)
       if (
@@ -235,10 +322,24 @@ export let sortArray = <MessageIds extends string>(
         data: {
           right: toSingleLine(right.name),
           left: toSingleLine(left.name),
+          rightGroup: right.group,
+          leftGroup: left.group,
         },
+        messageId:
+          leftNumber === rightNumber
+            ? availableMessageIds.unexpectedOrder
+            : availableMessageIds.unexpectedGroupOrder,
         node: right.node,
-        messageId,
       })
     })
   }
 }
+
+let getNodeName = ({
+  sourceCode,
+  element,
+}: {
+  element: TSESTree.SpreadElement | TSESTree.Expression
+  sourceCode: TSESLint.SourceCode
+}): string =>
+  element.type === 'Literal' ? `${element.value}` : sourceCode.getText(element)
diff --git a/rules/sort-array-includes.types.ts b/rules/sort-array-includes.types.ts
new file mode 100644
index 000000000..bdaa5d22a
--- /dev/null
+++ b/rules/sort-array-includes.types.ts
@@ -0,0 +1,63 @@
+import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'
+
+import {
+  buildCustomGroupSelectorJsonSchema,
+  elementNamePatternJsonSchema,
+} from '../utils/common-json-schemas'
+
+export type Options = Partial<{
+  useConfigurationIf: {
+    allNamesMatchPattern?: string
+  }
+  type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
+  /**
+   * @deprecated for {@link `groups`}
+   */
+  groupKind: 'literals-first' | 'spreads-first' | 'mixed'
+  partitionByComment: string[] | boolean | string
+  specialCharacters: 'remove' | 'trim' | 'keep'
+  locales: NonNullable<Intl.LocalesArgument>
+  customGroups: CustomGroup[]
+  partitionByNewLine: boolean
+  groups: (Group[] | Group)[]
+  order: 'desc' | 'asc'
+  ignoreCase: boolean
+  alphabet: string
+}>[]
+
+export interface SingleCustomGroup {
+  elementNamePattern?: string
+  selector?: Selector
+}
+
+export interface AnyOfCustomGroup {
+  anyOf: SingleCustomGroup[]
+}
+
+export type Selector = LiteralSelector | SpreadSelector
+
+type CustomGroup = (
+  | {
+      order?: Options[0]['order']
+      type?: Options[0]['type']
+    }
+  | {
+      type?: 'unsorted'
+    }
+) &
+  (SingleCustomGroup | AnyOfCustomGroup) & {
+    groupName: string
+  }
+
+type LiteralSelector = 'literal'
+
+type Group = 'unknown' | string
+
+type SpreadSelector = 'spread'
+
+export let allSelectors: Selector[] = ['literal', 'spread']
+
+export let singleCustomGroupJsonSchema: Record<string, JSONSchema4> = {
+  selector: buildCustomGroupSelectorJsonSchema(allSelectors),
+  elementNamePattern: elementNamePatternJsonSchema,
+}
diff --git a/rules/sort-classes.types.ts b/rules/sort-classes.types.ts
index adde1916f..55dd3ef26 100644
--- a/rules/sort-classes.types.ts
+++ b/rules/sort-classes.types.ts
@@ -22,6 +22,7 @@ export type SortClassesOptions = [
     alphabet: string
   }>,
 ]
+
 export type SingleCustomGroup =
   | AdvancedSingleCustomGroup<FunctionPropertySelector>
   | AdvancedSingleCustomGroup<AccessorPropertySelector>
@@ -32,6 +33,7 @@ export type SingleCustomGroup =
   | BaseSingleCustomGroup<StaticBlockSelector>
   | BaseSingleCustomGroup<ConstructorSelector>
   | AdvancedSingleCustomGroup<MethodSelector>
+
 export type Selector =
   | AccessorPropertySelector
   | FunctionPropertySelector
@@ -42,18 +44,7 @@ export type Selector =
   | SetMethodSelector
   | PropertySelector
   | MethodSelector
-export type CustomGroup = (
-  | {
-      order?: SortClassesOptions[0]['order']
-      type?: SortClassesOptions[0]['type']
-    }
-  | {
-      type?: 'unsorted'
-    }
-) &
-  (SingleCustomGroup | AnyOfCustomGroup) & {
-    groupName: string
-  }
+
 export type Modifier =
   | PublicOrProtectedOrPrivateModifier
   | DecoratedModifier
@@ -64,9 +55,11 @@ export type Modifier =
   | DeclareModifier
   | StaticModifier
   | AsyncModifier
+
 export interface AnyOfCustomGroup {
   anyOf: SingleCustomGroup[]
 }
+
 /**
  * Only used in code as well
  */
@@ -112,6 +105,7 @@ interface AllowedModifiersPerSelector {
   constructor: PublicOrProtectedOrPrivateModifier
   'static-block': never
 }
+
 /**
  * Some invalid combinations are still handled by this type, such as
  * - private abstract X
@@ -130,43 +124,69 @@ type Group =
   | MethodGroup
   | 'unknown'
   | string
+
+type CustomGroup = (
+  | {
+      order?: SortClassesOptions[0]['order']
+      type?: SortClassesOptions[0]['type']
+    }
+  | {
+      type?: 'unsorted'
+    }
+) &
+  (SingleCustomGroup | AnyOfCustomGroup) & {
+    groupName: string
+  }
+
 type NonDeclarePropertyGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${OptionalModifierPrefix}${PropertySelector}`
+
 type FunctionPropertyGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${StaticModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${AsyncModifierPrefix}${FunctionPropertySelector}`
+
 type MethodGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${AsyncModifierPrefix}${OptionalModifierPrefix}${MethodSelector}`
+
 type DeclarePropertyGroup =
   `${DeclareModifierPrefix}${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${ReadonlyModifierPrefix}${OptionalModifierPrefix}${PropertySelector}`
+
 type GetMethodOrSetMethodGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${GetMethodOrSetMethodSelector}`
 
 type AccessorPropertyGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${AccessorPropertySelector}`
+
 type AdvancedSingleCustomGroup<T extends Selector> = {
   decoratorNamePattern?: string
   elementValuePattern?: string
   elementNamePattern?: string
 } & BaseSingleCustomGroup<T>
+
 type PublicOrProtectedOrPrivateModifierPrefix = WithDashSuffixOrEmpty<
   ProtectedModifier | PrivateModifier | PublicModifier
 >
+
 interface BaseSingleCustomGroup<T extends Selector> {
   modifiers?: AllowedModifiersPerSelector[T][]
   selector?: T
 }
 type IndexSignatureGroup =
   `${StaticModifierPrefix}${ReadonlyModifierPrefix}${IndexSignatureSelector}`
+
 type PublicOrProtectedOrPrivateModifier =
   | ProtectedModifier
   | PrivateModifier
   | PublicModifier
+
 type StaticOrAbstractModifierPrefix = WithDashSuffixOrEmpty<
   AbstractModifier | StaticModifier
 >
+
 type ConstructorGroup =
   `${PublicOrProtectedOrPrivateModifierPrefix}${ConstructorSelector}`
+
 type GetMethodOrSetMethodSelector = GetMethodSelector | SetMethodSelector
+
 type DecoratedModifierPrefix = WithDashSuffixOrEmpty<DecoratedModifier>
 
 type OverrideModifierPrefix = WithDashSuffixOrEmpty<OverrideModifier>
@@ -174,10 +194,15 @@ type OverrideModifierPrefix = WithDashSuffixOrEmpty<OverrideModifier>
 type OptionalModifierPrefix = WithDashSuffixOrEmpty<OptionalModifier>
 
 type ReadonlyModifierPrefix = WithDashSuffixOrEmpty<ReadonlyModifier>
+
 type DeclareModifierPrefix = WithDashSuffixOrEmpty<DeclareModifier>
+
 type StaticModifierPrefix = WithDashSuffixOrEmpty<StaticModifier>
+
 type AsyncModifierPrefix = WithDashSuffixOrEmpty<AsyncModifier>
+
 type WithDashSuffixOrEmpty<T extends string> = `${T}-` | ''
+
 type FunctionPropertySelector = 'function-property'
 
 type AccessorPropertySelector = 'accessor-property'
@@ -187,13 +212,21 @@ type StaticBlockGroup = `${StaticBlockSelector}`
 type IndexSignatureSelector = 'index-signature'
 
 type StaticBlockSelector = 'static-block'
+
 type ConstructorSelector = 'constructor'
+
 type GetMethodSelector = 'get-method'
+
 type SetMethodSelector = 'set-method'
+
 type ProtectedModifier = 'protected'
+
 type DecoratedModifier = 'decorated'
+
 type AbstractModifier = 'abstract'
+
 type OverrideModifier = 'override'
+
 type ReadonlyModifier = 'readonly'
 
 type OptionalModifier = 'optional'
diff --git a/rules/sort-modules.types.ts b/rules/sort-modules.types.ts
index 838c2ef55..cf73cc1aa 100644
--- a/rules/sort-modules.types.ts
+++ b/rules/sort-modules.types.ts
@@ -21,6 +21,7 @@ export type SortModulesOptions = [
     alphabet: string
   }>,
 ]
+
 export type SingleCustomGroup = (
   | (DecoratorNamePatternFilterCustomGroup &
       BaseSingleCustomGroup<ClassSelector>)
@@ -30,18 +31,7 @@ export type SingleCustomGroup = (
   | BaseSingleCustomGroup<TypeSelector>
 ) &
   ElementNamePatternFilterCustomGroup
-export type CustomGroup = (
-  | {
-      order?: SortModulesOptions[0]['order']
-      type?: SortModulesOptions[0]['type']
-    }
-  | {
-      type?: 'unsorted'
-    }
-) &
-  (SingleCustomGroup | AnyOfCustomGroup) & {
-    groupName: string
-  }
+
 export type Selector =
   // | NamespaceSelector
   | InterfaceSelector
@@ -50,12 +40,14 @@ export type Selector =
   | ClassSelector
   | TypeSelector
   | EnumSelector
+
 export type Modifier =
   | DecoratedModifier
   | DeclareModifier
   | DefaultModifier
   | ExportModifier
   | AsyncModifier
+
 export interface AnyOfCustomGroup {
   anyOf: SingleCustomGroup[]
 }
@@ -72,6 +64,19 @@ interface AllowedModifiersPerSelector {
   enum: DeclareModifier | ExportModifier
   type: DeclareModifier | ExportModifier
 }
+
+type CustomGroup = (
+  | {
+      order?: SortModulesOptions[0]['order']
+      type?: SortModulesOptions[0]['type']
+    }
+  | {
+      type?: 'unsorted'
+    }
+) &
+  (SingleCustomGroup | AnyOfCustomGroup) & {
+    groupName: string
+  }
 /**
  * Only used in code, so I don't know if it's worth maintaining this.
  */
@@ -86,12 +91,16 @@ type Group =
   | TypeGroup
   | 'unknown'
   | string
+
 type NonDefaultClassGroup =
   `${ExportModifierPrefix}${DeclareModifierPrefix}${DecoratedModifierPrefix}${ClassSelector}`
+
 type DefaultFunctionGroup =
   `${ExportModifierPrefix}${DefaultModifierPrefix}${AsyncModifierPrefix}${FunctionSelector}`
+
 type DefaultClassGroup =
   `${ExportModifierPrefix}${DefaultModifierPrefix}${DecoratedModifierPrefix}${ClassSelector}`
+
 interface BaseSingleCustomGroup<T extends Selector> {
   modifiers?: AllowedModifiersPerSelector[T][]
   selector?: T
@@ -102,12 +111,16 @@ type NonDefaultInterfaceGroup =
 
 type NonDefaultFunctionGroup =
   `${ExportModifierPrefix}${DeclareModifierPrefix}${FunctionSelector}`
+
 type DefaultInterfaceGroup =
   `${ExportModifierPrefix}${DefaultModifierPrefix}${InterfaceSelector}`
+
 type TypeGroup =
   `${ExportModifierPrefix}${DeclareModifierPrefix}${TypeSelector}`
+
 type EnumGroup =
   `${ExportModifierPrefix}${DeclareModifierPrefix}${EnumSelector}`
+
 interface DecoratorNamePatternFilterCustomGroup {
   decoratorNamePattern?: string
 }
@@ -115,12 +128,19 @@ interface DecoratorNamePatternFilterCustomGroup {
 interface ElementNamePatternFilterCustomGroup {
   elementNamePattern?: string
 }
+
 type DecoratedModifierPrefix = WithDashSuffixOrEmpty<DecoratedModifier>
+
 type DeclareModifierPrefix = WithDashSuffixOrEmpty<DeclareModifier>
+
 type DefaultModifierPrefix = WithDashSuffixOrEmpty<DefaultModifier>
+
 type ExportModifierPrefix = WithDashSuffixOrEmpty<ExportModifier>
+
 type AsyncModifierPrefix = WithDashSuffixOrEmpty<AsyncModifier>
+
 type WithDashSuffixOrEmpty<T extends string> = `${T}-` | ''
+
 type DecoratedModifier = 'decorated'
 
 type InterfaceSelector = 'interface'
diff --git a/rules/sort-object-types.types.ts b/rules/sort-object-types.types.ts
index 8ce16ddb6..e2414f1a3 100644
--- a/rules/sort-object-types.types.ts
+++ b/rules/sort-object-types.types.ts
@@ -36,19 +36,6 @@ export type SingleCustomGroup = (
 ) &
   ElementNamePatternFilterCustomGroup
 
-export type CustomGroup = (
-  | {
-      order?: Options[0]['order']
-      type?: Options[0]['type']
-    }
-  | {
-      type?: 'unsorted'
-    }
-) &
-  (SingleCustomGroup | AnyOfCustomGroup) & {
-    groupName: string
-  }
-
 export type Selector =
   | IndexSignatureSelector
   | MultilineSelector
@@ -73,6 +60,19 @@ interface AllowedModifiersPerSelector {
   'index-signature': never
 }
 
+type CustomGroup = (
+  | {
+      order?: Options[0]['order']
+      type?: Options[0]['type']
+    }
+  | {
+      type?: 'unsorted'
+    }
+) &
+  (SingleCustomGroup | AnyOfCustomGroup) & {
+    groupName: string
+  }
+
 type IndexSignatureGroup =
   `${OptionalModifierPrefix | RequiredModifierPrefix}${MultilineModifierPrefix}${IndexSignatureSelector}`
 
diff --git a/rules/sort-sets.ts b/rules/sort-sets.ts
index c99e23826..cdfcd18e4 100644
--- a/rules/sort-sets.ts
+++ b/rules/sort-sets.ts
@@ -1,9 +1,9 @@
-import type { Options } from './sort-array-includes'
+import type { Options } from './sort-array-includes.types'
 
 import { defaultOptions, jsonSchema, sortArray } from './sort-array-includes'
 import { createEslintRule } from '../utils/create-eslint-rule'
 
-type MESSAGE_ID = 'unexpectedSetsOrder'
+type MESSAGE_ID = 'unexpectedSetsGroupOrder' | 'unexpectedSetsOrder'
 
 export default createEslintRule<Options, MESSAGE_ID>({
   create: context => ({
@@ -21,20 +21,29 @@ export default createEslintRule<Options, MESSAGE_ID>({
           node.arguments[0].type === 'ArrayExpression'
             ? node.arguments[0].elements
             : node.arguments[0].arguments
-        sortArray<MESSAGE_ID>(context, 'unexpectedSetsOrder', elements)
+        sortArray<MESSAGE_ID>({
+          availableMessageIds: {
+            unexpectedGroupOrder: 'unexpectedSetsGroupOrder',
+            unexpectedOrder: 'unexpectedSetsOrder',
+          },
+          elements,
+          context,
+        })
       }
     },
   }),
   meta: {
+    messages: {
+      unexpectedSetsGroupOrder:
+        'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
+      unexpectedSetsOrder: 'Expected "{{right}}" to come before "{{left}}".',
+    },
     docs: {
       url: 'https://perfectionist.dev/rules/sort-sets',
       description: 'Enforce sorted sets.',
       recommended: true,
     },
-    messages: {
-      unexpectedSetsOrder: 'Expected "{{right}}" to come before "{{left}}".',
-    },
-    schema: [jsonSchema],
+    schema: jsonSchema,
     type: 'suggestion',
     fixable: 'code',
   },
diff --git a/test/sort-array-includes.test.ts b/test/sort-array-includes.test.ts
index 0959acb1c..4aa82d86b 100644
--- a/test/sort-array-includes.test.ts
+++ b/test/sort-array-includes.test.ts
@@ -766,6 +766,447 @@ describe(ruleName, () => {
         valid: [],
       },
     )
+
+    ruleTester.run(
+      `${ruleName}(${type}): allows to use predefined groups`,
+      rule,
+      {
+        invalid: [
+          {
+            errors: [
+              {
+                data: {
+                  rightGroup: 'spread',
+                  leftGroup: 'literal',
+                  right: '...b',
+                  left: 'c',
+                },
+                messageId: 'unexpectedArrayIncludesGroupOrder',
+              },
+            ],
+            options: [
+              {
+                ...options,
+                groups: ['spread', 'literal'],
+                groupKind: 'mixed',
+              },
+            ],
+            output: dedent`
+              [
+                ...b,
+                'a',
+                'c'
+              ].includes(value)
+            `,
+            code: dedent`
+              [
+                'c',
+                ...b,
+                'a'
+              ].includes(value)
+            `,
+          },
+        ],
+        valid: [],
+      },
+    )
+
+    describe(`${ruleName}: custom groups`, () => {
+      ruleTester.run(`${ruleName}: filters on selector`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    groupName: 'literalElements',
+                    selector: 'literal',
+                  },
+                ],
+                groups: ['literalElements', 'unknown'],
+                groupKind: 'mixed',
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'literalElements',
+                  leftGroup: 'unknown',
+                  left: '...b',
+                  right: 'a',
+                },
+                messageId: 'unexpectedArrayIncludesGroupOrder',
+              },
+            ],
+            output: dedent`
+              [
+                'a',
+                ...b,
+              ].includes(value)
+            `,
+            code: dedent`
+              [
+                ...b,
+                'a',
+              ].includes(value)
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(`${ruleName}: filters on elementNamePattern`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    groupName: 'literalsStartingWithHello',
+                    elementNamePattern: 'hello*',
+                    selector: 'literal',
+                  },
+                ],
+                groups: ['literalsStartingWithHello', 'unknown'],
+                groupKind: 'mixed',
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'literalsStartingWithHello',
+                  right: 'helloLiteral',
+                  leftGroup: 'unknown',
+                  left: 'b',
+                },
+                messageId: 'unexpectedArrayIncludesGroupOrder',
+              },
+            ],
+            output: dedent`
+              [
+                'helloLiteral',
+                'a',
+                'b',
+              ].includes(value)
+            `,
+            code: dedent`
+              [
+                'a',
+                'b',
+                'helloLiteral',
+              ].includes(value)
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(
+        `${ruleName}: sort custom groups by overriding 'type' and 'order'`,
+        rule,
+        {
+          invalid: [
+            {
+              errors: [
+                {
+                  data: {
+                    right: 'bb',
+                    left: 'a',
+                  },
+                  messageId: 'unexpectedArrayIncludesOrder',
+                },
+                {
+                  data: {
+                    right: 'ccc',
+                    left: 'bb',
+                  },
+                  messageId: 'unexpectedArrayIncludesOrder',
+                },
+                {
+                  data: {
+                    right: 'dddd',
+                    left: 'ccc',
+                  },
+                  messageId: 'unexpectedArrayIncludesOrder',
+                },
+                {
+                  data: {
+                    rightGroup: 'reversedLiteralsByLineLength',
+                    leftGroup: 'unknown',
+                    left: '...m',
+                    right: 'eee',
+                  },
+                  messageId: 'unexpectedArrayIncludesGroupOrder',
+                },
+              ],
+              options: [
+                {
+                  customGroups: [
+                    {
+                      groupName: 'reversedLiteralsByLineLength',
+                      selector: 'literal',
+                      type: 'line-length',
+                      order: 'desc',
+                    },
+                  ],
+                  groups: ['reversedLiteralsByLineLength', 'unknown'],
+                  type: 'alphabetical',
+                  groupKind: 'mixed',
+                  order: 'asc',
+                },
+              ],
+              output: dedent`
+                [
+                  'dddd',
+                  'ccc',
+                  'eee',
+                  'bb',
+                  'ff',
+                  'a',
+                  'g',
+                  ...m,
+                  ...o,
+                  ...p,
+                ].includes(value)
+              `,
+              code: dedent`
+                [
+                  'a',
+                  'bb',
+                  'ccc',
+                  'dddd',
+                  ...m,
+                  'eee',
+                  'ff',
+                  'g',
+                  ...o,
+                  ...p,
+                ].includes(value)
+            `,
+            },
+          ],
+          valid: [],
+        },
+      )
+
+      ruleTester.run(
+        `${ruleName}: does not sort custom groups with 'unsorted' type`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  customGroups: [
+                    {
+                      groupName: 'unsortedLiterals',
+                      selector: 'literal',
+                      type: 'unsorted',
+                    },
+                  ],
+                  groups: ['unsortedLiterals', 'unknown'],
+                  groupKind: 'mixed',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    rightGroup: 'unsortedLiterals',
+                    leftGroup: 'unknown',
+                    left: '...m',
+                    right: 'c',
+                  },
+                  messageId: 'unexpectedArrayIncludesGroupOrder',
+                },
+              ],
+              output: dedent`
+                [
+                  'b',
+                  'a',
+                  'd',
+                  'e',
+                  'c',
+                  ...m,
+                ].includes(value)
+              `,
+              code: dedent`
+                [
+                  'b',
+                  'a',
+                  'd',
+                  'e',
+                  ...m,
+                  'c',
+                ].includes(value)
+            `,
+            },
+          ],
+          valid: [],
+        },
+      )
+
+      ruleTester.run(`${ruleName}: sort custom group blocks`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    anyOf: [
+                      {
+                        elementNamePattern: 'foo|Foo',
+                        selector: 'literal',
+                      },
+                      {
+                        elementNamePattern: 'foo|Foo',
+                        selector: 'spread',
+                      },
+                    ],
+                    groupName: 'elementsIncludingFoo',
+                  },
+                ],
+                groups: ['elementsIncludingFoo', 'unknown'],
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'elementsIncludingFoo',
+                  leftGroup: 'unknown',
+                  right: '...foo',
+                  left: 'a',
+                },
+                messageId: 'unexpectedArrayIncludesGroupOrder',
+              },
+            ],
+            output: dedent`
+              [
+                '...foo',
+                'cFoo',
+                'a',
+              ].includes(value)
+            `,
+            code: dedent`
+              [
+                'a',
+                '...foo',
+                'cFoo',
+              ].includes(value)
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(
+        `${ruleName}: allows to use regex for element names in custom groups`,
+        rule,
+        {
+          valid: [
+            {
+              options: [
+                {
+                  customGroups: [
+                    {
+                      elementNamePattern: '^(?!.*Foo).*$',
+                      groupName: 'elementsWithoutFoo',
+                    },
+                  ],
+                  groups: ['unknown', 'elementsWithoutFoo'],
+                  type: 'alphabetical',
+                },
+              ],
+              code: dedent`
+              [
+                'iHaveFooInMyName',
+                'meTooIHaveFoo',
+                'a',
+                'b',
+              ].includes(value)
+            `,
+            },
+          ],
+          invalid: [],
+        },
+      )
+    })
+
+    describe(`${ruleName}(${type}): allows to use 'useConfigurationIf'`, () => {
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use 'allNamesMatchPattern'`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  useConfigurationIf: {
+                    allNamesMatchPattern: 'foo',
+                  },
+                },
+                {
+                  ...options,
+                  customGroups: [
+                    {
+                      elementNamePattern: '^r$',
+                      groupName: 'r',
+                    },
+                    {
+                      elementNamePattern: '^g$',
+                      groupName: 'g',
+                    },
+                    {
+                      elementNamePattern: '^b$',
+                      groupName: 'b',
+                    },
+                  ],
+                  useConfigurationIf: {
+                    allNamesMatchPattern: '^r|g|b$',
+                  },
+                  groups: ['r', 'g', 'b'],
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    rightGroup: 'g',
+                    leftGroup: 'b',
+                    right: 'g',
+                    left: 'b',
+                  },
+                  messageId: 'unexpectedArrayIncludesGroupOrder',
+                },
+                {
+                  data: {
+                    rightGroup: 'r',
+                    leftGroup: 'g',
+                    right: 'r',
+                    left: 'g',
+                  },
+                  messageId: 'unexpectedArrayIncludesGroupOrder',
+                },
+              ],
+              output: dedent`
+                [
+                  'r',
+                  'g',
+                  'b',
+                ].includes(value)
+              `,
+              code: dedent`
+                [
+                  'b',
+                  'g',
+                  'r',
+                ].includes(value)
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
+    })
   })
 
   describe(`${ruleName}: sorting by natural order`, () => {
diff --git a/test/sort-sets.test.ts b/test/sort-sets.test.ts
index 460f26e3e..6d9f66d36 100644
--- a/test/sort-sets.test.ts
+++ b/test/sort-sets.test.ts
@@ -713,6 +713,447 @@ describe(ruleName, () => {
         valid: [],
       },
     )
+
+    ruleTester.run(
+      `${ruleName}(${type}): allows to use predefined groups`,
+      rule,
+      {
+        invalid: [
+          {
+            errors: [
+              {
+                data: {
+                  rightGroup: 'spread',
+                  leftGroup: 'literal',
+                  right: '...b',
+                  left: 'c',
+                },
+                messageId: 'unexpectedSetsGroupOrder',
+              },
+            ],
+            options: [
+              {
+                ...options,
+                groups: ['spread', 'literal'],
+                groupKind: 'mixed',
+              },
+            ],
+            output: dedent`
+              new Set([
+                ...b,
+                'a',
+                'c'
+              ])
+            `,
+            code: dedent`
+              new Set([
+                'c',
+                ...b,
+                'a'
+              ])
+            `,
+          },
+        ],
+        valid: [],
+      },
+    )
+
+    describe(`${ruleName}: custom groups`, () => {
+      ruleTester.run(`${ruleName}: filters on selector`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    groupName: 'literalElements',
+                    selector: 'literal',
+                  },
+                ],
+                groups: ['literalElements', 'unknown'],
+                groupKind: 'mixed',
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'literalElements',
+                  leftGroup: 'unknown',
+                  left: '...b',
+                  right: 'a',
+                },
+                messageId: 'unexpectedSetsGroupOrder',
+              },
+            ],
+            output: dedent`
+              new Set([
+                'a',
+                ...b,
+              ])
+            `,
+            code: dedent`
+              new Set([
+                ...b,
+                'a',
+              ])
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(`${ruleName}: filters on elementNamePattern`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    groupName: 'literalsStartingWithHello',
+                    elementNamePattern: 'hello*',
+                    selector: 'literal',
+                  },
+                ],
+                groups: ['literalsStartingWithHello', 'unknown'],
+                groupKind: 'mixed',
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'literalsStartingWithHello',
+                  right: 'helloLiteral',
+                  leftGroup: 'unknown',
+                  left: 'b',
+                },
+                messageId: 'unexpectedSetsGroupOrder',
+              },
+            ],
+            output: dedent`
+              new Set([
+                'helloLiteral',
+                'a',
+                'b',
+              ])
+            `,
+            code: dedent`
+              new Set([
+                'a',
+                'b',
+                'helloLiteral',
+              ])
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(
+        `${ruleName}: sort custom groups by overriding 'type' and 'order'`,
+        rule,
+        {
+          invalid: [
+            {
+              errors: [
+                {
+                  data: {
+                    right: 'bb',
+                    left: 'a',
+                  },
+                  messageId: 'unexpectedSetsOrder',
+                },
+                {
+                  data: {
+                    right: 'ccc',
+                    left: 'bb',
+                  },
+                  messageId: 'unexpectedSetsOrder',
+                },
+                {
+                  data: {
+                    right: 'dddd',
+                    left: 'ccc',
+                  },
+                  messageId: 'unexpectedSetsOrder',
+                },
+                {
+                  data: {
+                    rightGroup: 'reversedLiteralsByLineLength',
+                    leftGroup: 'unknown',
+                    left: '...m',
+                    right: 'eee',
+                  },
+                  messageId: 'unexpectedSetsGroupOrder',
+                },
+              ],
+              options: [
+                {
+                  customGroups: [
+                    {
+                      groupName: 'reversedLiteralsByLineLength',
+                      selector: 'literal',
+                      type: 'line-length',
+                      order: 'desc',
+                    },
+                  ],
+                  groups: ['reversedLiteralsByLineLength', 'unknown'],
+                  type: 'alphabetical',
+                  groupKind: 'mixed',
+                  order: 'asc',
+                },
+              ],
+              output: dedent`
+                new Set([
+                  'dddd',
+                  'ccc',
+                  'eee',
+                  'bb',
+                  'ff',
+                  'a',
+                  'g',
+                  ...m,
+                  ...o,
+                  ...p,
+                ])
+              `,
+              code: dedent`
+                new Set([
+                  'a',
+                  'bb',
+                  'ccc',
+                  'dddd',
+                  ...m,
+                  'eee',
+                  'ff',
+                  'g',
+                  ...o,
+                  ...p,
+                ])
+            `,
+            },
+          ],
+          valid: [],
+        },
+      )
+
+      ruleTester.run(
+        `${ruleName}: does not sort custom groups with 'unsorted' type`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  customGroups: [
+                    {
+                      groupName: 'unsortedLiterals',
+                      selector: 'literal',
+                      type: 'unsorted',
+                    },
+                  ],
+                  groups: ['unsortedLiterals', 'unknown'],
+                  groupKind: 'mixed',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    rightGroup: 'unsortedLiterals',
+                    leftGroup: 'unknown',
+                    left: '...m',
+                    right: 'c',
+                  },
+                  messageId: 'unexpectedSetsGroupOrder',
+                },
+              ],
+              output: dedent`
+                new Set([
+                  'b',
+                  'a',
+                  'd',
+                  'e',
+                  'c',
+                  ...m,
+                ])
+              `,
+              code: dedent`
+                new Set([
+                  'b',
+                  'a',
+                  'd',
+                  'e',
+                  ...m,
+                  'c',
+                ])
+            `,
+            },
+          ],
+          valid: [],
+        },
+      )
+
+      ruleTester.run(`${ruleName}: sort custom group blocks`, rule, {
+        invalid: [
+          {
+            options: [
+              {
+                customGroups: [
+                  {
+                    anyOf: [
+                      {
+                        elementNamePattern: 'foo|Foo',
+                        selector: 'literal',
+                      },
+                      {
+                        elementNamePattern: 'foo|Foo',
+                        selector: 'spread',
+                      },
+                    ],
+                    groupName: 'elementsIncludingFoo',
+                  },
+                ],
+                groups: ['elementsIncludingFoo', 'unknown'],
+              },
+            ],
+            errors: [
+              {
+                data: {
+                  rightGroup: 'elementsIncludingFoo',
+                  leftGroup: 'unknown',
+                  right: '...foo',
+                  left: 'a',
+                },
+                messageId: 'unexpectedSetsGroupOrder',
+              },
+            ],
+            output: dedent`
+              new Set([
+                '...foo',
+                'cFoo',
+                'a',
+              ])
+            `,
+            code: dedent`
+              new Set([
+                'a',
+                '...foo',
+                'cFoo',
+              ])
+            `,
+          },
+        ],
+        valid: [],
+      })
+
+      ruleTester.run(
+        `${ruleName}: allows to use regex for element names in custom groups`,
+        rule,
+        {
+          valid: [
+            {
+              options: [
+                {
+                  customGroups: [
+                    {
+                      elementNamePattern: '^(?!.*Foo).*$',
+                      groupName: 'elementsWithoutFoo',
+                    },
+                  ],
+                  groups: ['unknown', 'elementsWithoutFoo'],
+                  type: 'alphabetical',
+                },
+              ],
+              code: dedent`
+              new Set([
+                'iHaveFooInMyName',
+                'meTooIHaveFoo',
+                'a',
+                'b',
+              ])
+            `,
+            },
+          ],
+          invalid: [],
+        },
+      )
+    })
+
+    describe(`${ruleName}(${type}): allows to use 'useConfigurationIf'`, () => {
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use 'allNamesMatchPattern'`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  useConfigurationIf: {
+                    allNamesMatchPattern: 'foo',
+                  },
+                },
+                {
+                  ...options,
+                  customGroups: [
+                    {
+                      elementNamePattern: '^r$',
+                      groupName: 'r',
+                    },
+                    {
+                      elementNamePattern: '^g$',
+                      groupName: 'g',
+                    },
+                    {
+                      elementNamePattern: '^b$',
+                      groupName: 'b',
+                    },
+                  ],
+                  useConfigurationIf: {
+                    allNamesMatchPattern: '^r|g|b$',
+                  },
+                  groups: ['r', 'g', 'b'],
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    rightGroup: 'g',
+                    leftGroup: 'b',
+                    right: 'g',
+                    left: 'b',
+                  },
+                  messageId: 'unexpectedSetsGroupOrder',
+                },
+                {
+                  data: {
+                    rightGroup: 'r',
+                    leftGroup: 'g',
+                    right: 'r',
+                    left: 'g',
+                  },
+                  messageId: 'unexpectedSetsGroupOrder',
+                },
+              ],
+              output: dedent`
+                new Set([
+                  'r',
+                  'g',
+                  'b',
+                ])
+              `,
+              code: dedent`
+                new Set([
+                  'b',
+                  'g',
+                  'r',
+                ])
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
+    })
   })
 
   describe(`${ruleName}: sorting by natural order`, () => {