diff --git a/.changeset/early-trainers-know.md b/.changeset/early-trainers-know.md
new file mode 100644
index 000000000..c379b3735
--- /dev/null
+++ b/.changeset/early-trainers-know.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+feat: added the `consistent-selector-style` rule
diff --git a/README.md b/README.md
index b2bac0116..ac522d6e1 100644
--- a/README.md
+++ b/README.md
@@ -380,6 +380,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
| Rule ID | Description | |
|:--------|:------------|:---|
+| [svelte/consistent-selector-style](https://sveltejs.github.io/eslint-plugin-svelte/rules/consistent-selector-style/) | enforce a consistent style for CSS selectors | |
| [svelte/derived-has-same-inputs-outputs](https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/) | derived store should use same variable names between values and callback | |
| [svelte/first-attribute-linebreak](https://sveltejs.github.io/eslint-plugin-svelte/rules/first-attribute-linebreak/) | enforce the location of first attribute | :wrench: |
| [svelte/html-closing-bracket-new-line](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-new-line/) | Require or disallow a line break before tag's closing brackets | :wrench: |
diff --git a/docs/rules.md b/docs/rules.md
index f07b703a2..f6f5a9f5c 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -77,6 +77,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
| Rule ID | Description | |
| :------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | :------- |
+| [svelte/consistent-selector-style](./rules/consistent-selector-style.md) | enforce a consistent style for CSS selectors | |
| [svelte/derived-has-same-inputs-outputs](./rules/derived-has-same-inputs-outputs.md) | derived store should use same variable names between values and callback | |
| [svelte/first-attribute-linebreak](./rules/first-attribute-linebreak.md) | enforce the location of first attribute | :wrench: |
| [svelte/html-closing-bracket-new-line](./rules/html-closing-bracket-new-line.md) | Require or disallow a line break before tag's closing brackets | :wrench: |
diff --git a/docs/rules/consistent-selector-style.md b/docs/rules/consistent-selector-style.md
new file mode 100644
index 000000000..12f7990f9
--- /dev/null
+++ b/docs/rules/consistent-selector-style.md
@@ -0,0 +1,98 @@
+---
+pageClass: 'rule-details'
+sidebarDepth: 0
+title: 'svelte/consistent-selector-style'
+description: 'enforce a consistent style for CSS selectors'
+---
+
+# svelte/consistent-selector-style
+
+> enforce a consistent style for CSS selectors
+
+- :exclamation: **_This rule has not been released yet._**
+
+## :book: Rule Details
+
+This rule allows you to set a preferred style for your CSS (& other style language) selectors. In CSS, there is a wide list of options for selecting elements, however, the three most basic types are:
+
+- Selecting by element type (i.e. tag name), such as `a {}`
+- Selecting by element ID, such as `#link {}`
+- Selecting by element class, such as `.link {}`
+ This rule allows you to set a preference for some of these three styles over others. Not all selectors can be used in all situations, however. While class selectors can be used in any situation, ID selectors can only be used to select a single element and type selectors are only applicable when the list of selected elements is the list of all elements of the particular type. To help with this, the rule accepts a list of selector style preferences and reports situations when the given selector can be rewritten using a more preferred style.
+
+
+
+```svelte
+
+
+Click me!
+
+Click me too!
+
+Text one
+
+Text two
+
+Text three
+
+
+```
+
+## :wrench: Options
+
+```json
+{
+ "svelte/consistent-selector-style": [
+ "error",
+ {
+ "checkGlobal": false,
+ "style": ["type", "id", "class"]
+ }
+ ]
+}
+```
+
+- `checkGlobal` ... Whether to check styles in `:global` blocks as well. Default `false`.
+- `style` ... A list of style preferences. Default `["type", "id", "class"]`.
+
+## :books: Further Reading
+
+- [CSS selector documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/consistent-selector-style.ts)
+- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/consistent-selector-style.ts)
diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts
index 3bc21b67f..3b3e4eaa6 100644
--- a/packages/eslint-plugin-svelte/src/rule-types.ts
+++ b/packages/eslint-plugin-svelte/src/rule-types.ts
@@ -34,6 +34,11 @@ export interface RuleOptions {
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/comment-directive/
*/
'svelte/comment-directive'?: Linter.RuleEntry
+ /**
+ * enforce a consistent style for CSS selectors
+ * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/consistent-selector-style/
+ */
+ 'svelte/consistent-selector-style'?: Linter.RuleEntry
/**
* derived store should use same variable names between values and callback
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/
@@ -387,6 +392,12 @@ type SvelteButtonHasType = []|[{
type SvelteCommentDirective = []|[{
reportUnusedDisableDirectives?: boolean
}]
+// ----- svelte/consistent-selector-style -----
+type SvelteConsistentSelectorStyle = []|[{
+ checkGlobal?: boolean
+
+ style?: []|[("class" | "id" | "type")]|[("class" | "id" | "type"), ("class" | "id" | "type")]|[("class" | "id" | "type"), ("class" | "id" | "type"), ("class" | "id" | "type")]
+}]
// ----- svelte/first-attribute-linebreak -----
type SvelteFirstAttributeLinebreak = []|[{
multiline?: ("below" | "beside")
diff --git a/packages/eslint-plugin-svelte/src/rules/consistent-selector-style.ts b/packages/eslint-plugin-svelte/src/rules/consistent-selector-style.ts
new file mode 100644
index 000000000..00134c5d3
--- /dev/null
+++ b/packages/eslint-plugin-svelte/src/rules/consistent-selector-style.ts
@@ -0,0 +1,263 @@
+import type { AST } from 'svelte-eslint-parser';
+import type { AnyNode } from 'postcss';
+import type {
+ ClassName as SelectorClass,
+ Identifier as SelectorIdentifier,
+ Node as SelectorNode,
+ Tag as SelectorTag
+} from 'postcss-selector-parser';
+import { findClassesInAttribute } from '../utils/ast-utils.js';
+import { getSourceCode } from '../utils/compat.js';
+import { createRule } from '../utils/index.js';
+
+export default createRule('consistent-selector-style', {
+ meta: {
+ docs: {
+ description: 'enforce a consistent style for CSS selectors',
+ category: 'Stylistic Issues',
+ recommended: false,
+ conflictWithPrettier: false
+ },
+ schema: [
+ {
+ type: 'object',
+ properties: {
+ checkGlobal: {
+ type: 'boolean'
+ },
+ style: {
+ type: 'array',
+ items: {
+ enum: ['class', 'id', 'type']
+ },
+ maxItems: 3,
+ uniqueItems: true
+ }
+ },
+ additionalProperties: false
+ }
+ ],
+ messages: {
+ classShouldBeId: 'Selector should select by ID instead of class',
+ classShouldBeType: 'Selector should select by element type instead of class',
+ idShouldBeClass: 'Selector should select by class instead of ID',
+ idShouldBeType: 'Selector should select by element type instead of ID',
+ typeShouldBeClass: 'Selector should select by class instead of element type',
+ typeShouldBeId: 'Selector should select by ID instead of element type'
+ },
+ type: 'suggestion'
+ },
+ create(context) {
+ const sourceCode = getSourceCode(context);
+ if (
+ !sourceCode.parserServices.isSvelte ||
+ sourceCode.parserServices.getStyleSelectorAST === undefined ||
+ sourceCode.parserServices.styleSelectorNodeLoc === undefined
+ ) {
+ return {};
+ }
+ const getStyleSelectorAST = sourceCode.parserServices.getStyleSelectorAST;
+ const styleSelectorNodeLoc = sourceCode.parserServices.styleSelectorNodeLoc;
+
+ const checkGlobal = context.options[0]?.checkGlobal ?? false;
+ const style = context.options[0]?.style ?? ['type', 'id', 'class'];
+
+ const classSelections: Map = new Map();
+ const idSelections: Map = new Map();
+ const typeSelections: Map = new Map();
+
+ /**
+ * Checks selectors in a given PostCSS node
+ */
+ function checkSelectorsInPostCSSNode(node: AnyNode): void {
+ if (node.type === 'rule') {
+ checkSelector(getStyleSelectorAST(node));
+ }
+ if (
+ (node.type === 'root' ||
+ (node.type === 'rule' && (node.selector !== ':global' || checkGlobal)) ||
+ node.type === 'atrule') &&
+ node.nodes !== undefined
+ ) {
+ node.nodes.flatMap((node) => checkSelectorsInPostCSSNode(node));
+ }
+ }
+
+ /**
+ * Checks an individual selector
+ */
+ function checkSelector(node: SelectorNode): void {
+ if (node.type === 'class') {
+ checkClassSelector(node);
+ }
+ if (node.type === 'id') {
+ checkIdSelector(node);
+ }
+ if (node.type === 'tag') {
+ checkTypeSelector(node);
+ }
+ if (
+ (node.type === 'pseudo' && (node.value !== ':global' || checkGlobal)) ||
+ node.type === 'root' ||
+ node.type === 'selector'
+ ) {
+ node.nodes.flatMap((node) => checkSelector(node));
+ }
+ }
+
+ /**
+ * Checks a class selector
+ */
+ function checkClassSelector(node: SelectorClass): void {
+ const selection = classSelections.get(node.value) ?? [];
+ for (const styleValue of style) {
+ if (styleValue === 'class') {
+ return;
+ }
+ if (styleValue === 'id' && canUseIdSelector(selection)) {
+ context.report({
+ messageId: 'classShouldBeId',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ if (styleValue === 'type' && canUseTypeSelector(selection, typeSelections)) {
+ context.report({
+ messageId: 'classShouldBeType',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ }
+ }
+
+ /**
+ * Checks an ID selector
+ */
+ function checkIdSelector(node: SelectorIdentifier): void {
+ const selection = idSelections.get(node.value) ?? [];
+ for (const styleValue of style) {
+ if (styleValue === 'class') {
+ context.report({
+ messageId: 'idShouldBeClass',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ if (styleValue === 'id') {
+ return;
+ }
+ if (styleValue === 'type' && canUseTypeSelector(selection, typeSelections)) {
+ context.report({
+ messageId: 'idShouldBeType',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ }
+ }
+
+ /**
+ * Checks a type selector
+ */
+ function checkTypeSelector(node: SelectorTag): void {
+ const selection = typeSelections.get(node.value) ?? [];
+ for (const styleValue of style) {
+ if (styleValue === 'class') {
+ context.report({
+ messageId: 'typeShouldBeClass',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ if (styleValue === 'id' && canUseIdSelector(selection)) {
+ context.report({
+ messageId: 'typeShouldBeId',
+ loc: styleSelectorNodeLoc(node) as AST.SourceLocation
+ });
+ return;
+ }
+ if (styleValue === 'type') {
+ return;
+ }
+ }
+ }
+
+ return {
+ SvelteElement(node) {
+ if (node.kind !== 'html') {
+ return;
+ }
+ addToArrayMap(typeSelections, node.name.name, node);
+ const classes = node.startTag.attributes.flatMap(findClassesInAttribute);
+ for (const className of classes) {
+ addToArrayMap(classSelections, className, node);
+ }
+ for (const attribute of node.startTag.attributes) {
+ if (attribute.type !== 'SvelteAttribute' || attribute.key.name !== 'id') {
+ continue;
+ }
+ for (const value of attribute.value) {
+ if (value.type === 'SvelteLiteral') {
+ addToArrayMap(idSelections, value.value, node);
+ }
+ }
+ }
+ },
+ 'Program:exit'() {
+ const styleContext = sourceCode.parserServices.getStyleContext!();
+ if (
+ styleContext.status !== 'success' ||
+ sourceCode.parserServices.getStyleSelectorAST === undefined
+ ) {
+ return;
+ }
+ checkSelectorsInPostCSSNode(styleContext.sourceAst);
+ }
+ };
+ }
+});
+
+/**
+ * Helper function to add a value to a Map of arrays
+ */
+function addToArrayMap(
+ map: Map,
+ key: string,
+ value: AST.SvelteHTMLElement
+): void {
+ map.set(key, (map.get(key) ?? []).concat(value));
+}
+
+/**
+ * Checks whether a given selection could be obtained using an ID selector
+ */
+function canUseIdSelector(selection: AST.SvelteHTMLElement[]): boolean {
+ return selection.length <= 1;
+}
+
+/**
+ * Checks whether a given selection could be obtained using a type selector
+ */
+function canUseTypeSelector(
+ selection: AST.SvelteHTMLElement[],
+ typeSelections: Map
+): boolean {
+ const types = new Set(selection.map((node) => node.name.name));
+ if (types.size > 1) {
+ return false;
+ }
+ if (types.size < 1) {
+ return true;
+ }
+ const type = [...types][0];
+ const typeSelection = typeSelections.get(type);
+ return typeSelection !== undefined && arrayEquals(typeSelection, selection);
+}
+
+/**
+ * Compares two arrays for item equality
+ */
+function arrayEquals(array1: AST.SvelteHTMLElement[], array2: AST.SvelteHTMLElement[]): boolean {
+ return array1.length === array2.length && array1.every((e) => array2.includes(e));
+}
diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts
index 9f58e5335..6757e231e 100644
--- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts
+++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts
@@ -1,16 +1,8 @@
import { createRule } from '../utils/index.js';
-import type {
- SourceLocation,
- SvelteAttribute,
- SvelteDirective,
- SvelteGenericsDirective,
- SvelteShorthandAttribute,
- SvelteSpecialDirective,
- SvelteSpreadAttribute,
- SvelteStyleDirective
-} from 'svelte-eslint-parser/lib/ast';
+import type { AST } from 'svelte-eslint-parser';
import type { AnyNode } from 'postcss';
import type { Node as SelectorNode } from 'postcss-selector-parser';
+import { findClassesInAttribute } from '../utils/ast-utils.js';
import { getSourceCode } from '../utils/compat.js';
import type { SourceCode } from '../types.js';
@@ -44,7 +36,7 @@ export default createRule('no-unused-class-name', {
return {};
}
const allowedClassNames = context.options[0]?.allowedClassNames ?? [];
- const classesUsedInTemplate: Record = {};
+ const classesUsedInTemplate: Record = {};
return {
SvelteElement(node) {
@@ -78,30 +70,6 @@ export default createRule('no-unused-class-name', {
}
});
-/**
- * Extract all class names used in a HTML element attribute.
- */
-function findClassesInAttribute(
- attribute:
- | SvelteAttribute
- | SvelteShorthandAttribute
- | SvelteSpreadAttribute
- | SvelteDirective
- | SvelteStyleDirective
- | SvelteSpecialDirective
- | SvelteGenericsDirective
-): string[] {
- if (attribute.type === 'SvelteAttribute' && attribute.key.name === 'class') {
- return attribute.value.flatMap((value) =>
- value.type === 'SvelteLiteral' ? value.value.trim().split(/\s+/u) : []
- );
- }
- if (attribute.type === 'SvelteDirective' && attribute.kind === 'Class') {
- return [attribute.key.name.name];
- }
- return [];
-}
-
/**
* Extract all class names used in a PostCSS node.
*/
diff --git a/packages/eslint-plugin-svelte/src/utils/ast-utils.ts b/packages/eslint-plugin-svelte/src/utils/ast-utils.ts
index e844ab842..1b804baef 100644
--- a/packages/eslint-plugin-svelte/src/utils/ast-utils.ts
+++ b/packages/eslint-plugin-svelte/src/utils/ast-utils.ts
@@ -545,6 +545,30 @@ function getAttributeValueRangeTokens(
};
}
+/**
+ * Extract all class names used in a HTML element attribute.
+ */
+export function findClassesInAttribute(
+ attribute:
+ | SvAST.SvelteAttribute
+ | SvAST.SvelteShorthandAttribute
+ | SvAST.SvelteSpreadAttribute
+ | SvAST.SvelteDirective
+ | SvAST.SvelteStyleDirective
+ | SvAST.SvelteSpecialDirective
+ | SvAST.SvelteGenericsDirective
+): string[] {
+ if (attribute.type === 'SvelteAttribute' && attribute.key.name === 'class') {
+ return attribute.value.flatMap((value) =>
+ value.type === 'SvelteLiteral' ? value.value.trim().split(/\s+/u) : []
+ );
+ }
+ if (attribute.type === 'SvelteDirective' && attribute.kind === 'Class') {
+ return [attribute.key.name.name];
+ }
+ return [];
+}
+
/**
* Returns name of SvelteElement
*/
diff --git a/packages/eslint-plugin-svelte/src/utils/rules.ts b/packages/eslint-plugin-svelte/src/utils/rules.ts
index 43d6772b7..2a2ddeeda 100644
--- a/packages/eslint-plugin-svelte/src/utils/rules.ts
+++ b/packages/eslint-plugin-svelte/src/utils/rules.ts
@@ -6,6 +6,7 @@ import typescriptEslintNoUnnecessaryCondition from '../rules/@typescript-eslint/
import blockLang from '../rules/block-lang.js';
import buttonHasType from '../rules/button-has-type.js';
import commentDirective from '../rules/comment-directive.js';
+import consistentSelectorStyle from '../rules/consistent-selector-style.js';
import derivedHasSameInputsOutputs from '../rules/derived-has-same-inputs-outputs.js';
import experimentalRequireSlotTypes from '../rules/experimental-require-slot-types.js';
import experimentalRequireStrictEvents from '../rules/experimental-require-strict-events.js';
@@ -77,6 +78,7 @@ export const rules = [
blockLang,
buttonHasType,
commentDirective,
+ consistentSelectorStyle,
derivedHasSameInputsOutputs,
experimentalRequireSlotTypes,
experimentalRequireStrictEvents,
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/_config.json
new file mode 100644
index 000000000..872db17e4
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "checkGlobal": true }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-errors.yaml
new file mode 100644
index 000000000..11974f271
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-errors.yaml
@@ -0,0 +1,56 @@
+- message: Selector should select by ID instead of class
+ line: 10
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 14
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 18
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 22
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 22
+ column: 19
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 26
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 30
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 35
+ column: 5
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 39
+ column: 5
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 43
+ column: 5
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 47
+ column: 5
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 47
+ column: 13
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 51
+ column: 5
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 55
+ column: 5
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-input.svelte
new file mode 100644
index 000000000..0e69dd3c7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-id01-input.svelte
@@ -0,0 +1,59 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-errors.yaml
new file mode 100644
index 000000000..c6811d24e
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-errors.yaml
@@ -0,0 +1,88 @@
+- message: Selector should select by element type instead of class
+ line: 12
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 16
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 20
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 28
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 28
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 32
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 36
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 40
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 44
+ column: 15
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 48
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 53
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 57
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 61
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 65
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 65
+ column: 13
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 69
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 73
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 77
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 81
+ column: 5
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 85
+ column: 9
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 89
+ column: 5
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-input.svelte
new file mode 100644
index 000000000..b33b92162
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/global/should-be-type01-input.svelte
@@ -0,0 +1,93 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/_config.json
new file mode 100644
index 000000000..785bad119
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["id", "class", "type"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-errors.yaml
new file mode 100644
index 000000000..20b348a6c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-errors.yaml
@@ -0,0 +1,48 @@
+- message: Selector should select by ID instead of class
+ line: 12
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 13
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 14
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 15
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 15
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 16
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 17
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 18
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 19
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 20
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 20
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 21
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-input.svelte
new file mode 100644
index 000000000..7240fadf3
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id-combination01-input.svelte
@@ -0,0 +1,24 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 3
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-errors.yaml
new file mode 100644
index 000000000..0ed971448
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-errors.yaml
@@ -0,0 +1,48 @@
+- message: Selector should select by ID instead of class
+ line: 12
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 16
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 20
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 24
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 24
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 28
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 32
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 36
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 40
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 44
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 44
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 48
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-input.svelte
new file mode 100644
index 000000000..f58dd4518
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-class-type/should-be-id01-input.svelte
@@ -0,0 +1,51 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 3
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/_config.json
new file mode 100644
index 000000000..76b7a1bea
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["id", "type", "class"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-errors.yaml
new file mode 100644
index 000000000..0ed971448
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-errors.yaml
@@ -0,0 +1,48 @@
+- message: Selector should select by ID instead of class
+ line: 12
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 16
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 20
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 24
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 24
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 28
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 32
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 36
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 40
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 44
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 44
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of element type
+ line: 48
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-input.svelte
new file mode 100644
index 000000000..f58dd4518
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-id01-input.svelte
@@ -0,0 +1,51 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 3
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-errors.yaml
new file mode 100644
index 000000000..f09167627
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-errors.yaml
@@ -0,0 +1,28 @@
+- message: Selector should select by element type instead of class
+ line: 10
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 14
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 18
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 22
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 22
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 26
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 30
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-input.svelte
new file mode 100644
index 000000000..87b25c29d
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/id-type-class/should-be-type01-input.svelte
@@ -0,0 +1,33 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/_config.json
new file mode 100644
index 000000000..249f96ef9
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["type", "class", "id"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-errors.yaml
new file mode 100644
index 000000000..57e5e2be5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-errors.yaml
@@ -0,0 +1,44 @@
+- message: Selector should select by element type instead of class
+ line: 12
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 16
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 20
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 28
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 32
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 36
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 40
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 44
+ column: 7
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 48
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-input.svelte
new file mode 100644
index 000000000..1d1fa7078
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-class-id/should-be-type01-input.svelte
@@ -0,0 +1,51 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-errors.yaml
new file mode 100644
index 000000000..e153ca3c9
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-errors.yaml
@@ -0,0 +1,28 @@
+- message: Selector should select by ID instead of class
+ line: 18
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 22
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 26
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 30
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 30
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 34
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 38
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-input.svelte
new file mode 100644
index 000000000..bd34fdaf6
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id-with-components01-input.svelte
@@ -0,0 +1,41 @@
+
+
+Click me!
+
+Component
+
+Click me two!
+
+Text 1
+
+Component
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-errors.yaml
new file mode 100644
index 000000000..f2f218ba8
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-errors.yaml
@@ -0,0 +1,28 @@
+- message: Selector should select by ID instead of class
+ line: 10
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 14
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 18
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 22
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 22
+ column: 11
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 26
+ column: 3
+ suggestions: null
+- message: Selector should select by ID instead of class
+ line: 30
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-input.svelte
new file mode 100644
index 000000000..6dee3410d
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-id01-input.svelte
@@ -0,0 +1,33 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-errors.yaml
new file mode 100644
index 000000000..c047f4278
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-errors.yaml
@@ -0,0 +1,44 @@
+- message: Selector should select by element type instead of class
+ line: 22
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 26
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 30
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 34
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 34
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 38
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 42
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 46
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 50
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 54
+ column: 7
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 58
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-input.svelte
new file mode 100644
index 000000000..b892b9f79
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type-with-components01-input.svelte
@@ -0,0 +1,61 @@
+
+
+Click me!
+
+Click me two!
+
+Component
+
+Text 1
+
+Text 2
+
+Component
+
+Italic
+
+Component
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-errors.yaml
new file mode 100644
index 000000000..57e5e2be5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-errors.yaml
@@ -0,0 +1,44 @@
+- message: Selector should select by element type instead of class
+ line: 12
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 16
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 20
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 24
+ column: 11
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 28
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of class
+ line: 32
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 36
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 40
+ column: 3
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 44
+ column: 7
+ suggestions: null
+- message: Selector should select by element type instead of ID
+ line: 48
+ column: 3
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-input.svelte
new file mode 100644
index 000000000..1d1fa7078
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/invalid/type-id-class/should-be-type01-input.svelte
@@ -0,0 +1,51 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Italic
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/_config.json
new file mode 100644
index 000000000..60025219d
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["class", "id", "type"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class-scss01-input.svelte
new file mode 100644
index 000000000..04ace664c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class-scss01-input.svelte
@@ -0,0 +1,15 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class01-input.svelte
new file mode 100644
index 000000000..405f8c459
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-id-type/class01-input.svelte
@@ -0,0 +1,31 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/_config.json
new file mode 100644
index 000000000..be9cf9216
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["class", "type", "id"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class-scss01-input.svelte
new file mode 100644
index 000000000..04ace664c
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class-scss01-input.svelte
@@ -0,0 +1,15 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class01-input.svelte
new file mode 100644
index 000000000..405f8c459
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/class-type-id/class01-input.svelte
@@ -0,0 +1,31 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/_config.json
new file mode 100644
index 000000000..785bad119
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["id", "class", "type"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/class01-input.svelte
new file mode 100644
index 000000000..f3564d8eb
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/class01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id-scss01-input.svelte
new file mode 100644
index 000000000..824d6e651
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id-scss01-input.svelte
@@ -0,0 +1,15 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id01-input.svelte
new file mode 100644
index 000000000..79afbb38b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-class-type/id01-input.svelte
@@ -0,0 +1,31 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/_config.json
new file mode 100644
index 000000000..76b7a1bea
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["id", "type", "class"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/class01-input.svelte
new file mode 100644
index 000000000..878799bde
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/class01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id-scss01-input.svelte
new file mode 100644
index 000000000..824d6e651
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id-scss01-input.svelte
@@ -0,0 +1,15 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id01-input.svelte
new file mode 100644
index 000000000..79afbb38b
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/id01-input.svelte
@@ -0,0 +1,31 @@
+Click me!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/type01-input.svelte
new file mode 100644
index 000000000..f8e9f2aa5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/id-type-class/type01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/_config.json
new file mode 100644
index 000000000..249f96ef9
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["type", "class", "id"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/class01-input.svelte
new file mode 100644
index 000000000..b770c0572
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/class01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type-scss01-input.svelte
new file mode 100644
index 000000000..4edab8017
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type-scss01-input.svelte
@@ -0,0 +1,13 @@
+Click me!
+
+Text 1
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type01-input.svelte
new file mode 100644
index 000000000..f8e9f2aa5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-class-id/type01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/class01-input.svelte
new file mode 100644
index 000000000..92e8c4e31
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/class01-input.svelte
@@ -0,0 +1,37 @@
+Click me!
+
+Click me two!
+
+Click me three!
+
+Text 1
+
+Text 2
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/global01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/global01-input.svelte
new file mode 100644
index 000000000..a63fa30e5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/global01-input.svelte
@@ -0,0 +1,157 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/id01-input.svelte
new file mode 100644
index 000000000..363844f29
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/id01-input.svelte
@@ -0,0 +1,33 @@
+Click me!
+
+Click me too!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type-scss01-input.svelte
new file mode 100644
index 000000000..4edab8017
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type-scss01-input.svelte
@@ -0,0 +1,13 @@
+Click me!
+
+Text 1
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type01-input.svelte
new file mode 100644
index 000000000..f8e9f2aa5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id-class/type01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/_config.json
new file mode 100644
index 000000000..8d5a6bf74
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["type", "id"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/class01-input.svelte
new file mode 100644
index 000000000..92e8c4e31
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/class01-input.svelte
@@ -0,0 +1,37 @@
+Click me!
+
+Click me two!
+
+Click me three!
+
+Text 1
+
+Text 2
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/id01-input.svelte
new file mode 100644
index 000000000..363844f29
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/id01-input.svelte
@@ -0,0 +1,33 @@
+Click me!
+
+Click me too!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type-scss01-input.svelte
new file mode 100644
index 000000000..4edab8017
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type-scss01-input.svelte
@@ -0,0 +1,13 @@
+Click me!
+
+Text 1
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type01-input.svelte
new file mode 100644
index 000000000..f8e9f2aa5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type-id/type01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/_config.json
new file mode 100644
index 000000000..0afc12b50
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/_config.json
@@ -0,0 +1,3 @@
+{
+ "options": [{ "style": ["type"] }]
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/class01-input.svelte
new file mode 100644
index 000000000..2f1bc20a7
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/class01-input.svelte
@@ -0,0 +1,44 @@
+Click me!
+
+Click me two!
+
+Click me three!
+
+Click me three!
+
+Text 1
+
+Text 2
+
+Text 3
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/id01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/id01-input.svelte
new file mode 100644
index 000000000..363844f29
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/id01-input.svelte
@@ -0,0 +1,33 @@
+Click me!
+
+Click me too!
+
+Text 1
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type-scss01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type-scss01-input.svelte
new file mode 100644
index 000000000..4edab8017
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type-scss01-input.svelte
@@ -0,0 +1,13 @@
+Click me!
+
+Text 1
+
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type01-input.svelte
new file mode 100644
index 000000000..f8e9f2aa5
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/consistent-selector-style/valid/type/type01-input.svelte
@@ -0,0 +1,35 @@
+Click me!
+
+Click me two!
+
+Text 1
+
+Text 2
+
+Text 2
+
+
diff --git a/packages/eslint-plugin-svelte/tests/src/rules/consistent-selector-style.ts b/packages/eslint-plugin-svelte/tests/src/rules/consistent-selector-style.ts
new file mode 100644
index 000000000..edd626103
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/src/rules/consistent-selector-style.ts
@@ -0,0 +1,12 @@
+import { RuleTester } from '../../utils/eslint-compat';
+import rule from '../../../src/rules/consistent-selector-style';
+import { loadTestCases } from '../../utils/utils';
+
+const tester = new RuleTester({
+ languageOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module'
+ }
+});
+
+tester.run('consistent-selector-style', rule as any, loadTestCases('consistent-selector-style'));