|
| 1 | +--- |
| 2 | +pageClass: "rule-details" |
| 3 | +sidebarDepth: 0 |
| 4 | +title: "svelte/sort-attributes" |
| 5 | +description: "enforce order of attributes" |
| 6 | +--- |
| 7 | + |
| 8 | +# svelte/sort-attributes |
| 9 | + |
| 10 | +> enforce order of attributes |
| 11 | +
|
| 12 | +- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge> |
| 13 | +- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. |
| 14 | + |
| 15 | +## :book: Rule Details |
| 16 | + |
| 17 | +This rule aims to enforce ordering of attributes. |
| 18 | +The default order is: |
| 19 | + |
| 20 | +- `this` property. |
| 21 | +- `bind:this` directive. |
| 22 | +- `id` attribute. |
| 23 | +- `name` attribute. |
| 24 | +- `slot` attribute. |
| 25 | +- `--style-props` (Alphabetical order within the same group.) |
| 26 | +- `style` attribute, and `style:` directives. |
| 27 | +- `class` attribute. |
| 28 | +- `class:` directives. (Alphabetical order within the same group.) |
| 29 | +- other attributes. (Alphabetical order within the same group.) |
| 30 | +- `bind:` directives (other then `bind:this`), and `on:` directives. |
| 31 | +- `use:` directives. (Alphabetical order within the same group.) |
| 32 | +- `transition:` directive. |
| 33 | +- `in:` directive. |
| 34 | +- `out:` directive. |
| 35 | +- `animate:` directive. |
| 36 | +- `let:` directives. (Alphabetical order within the same group.) |
| 37 | + |
| 38 | +<ESLintCodeBlock fix> |
| 39 | + |
| 40 | +<!-- prettier-ignore-start --> |
| 41 | +<!--eslint-skip--> |
| 42 | + |
| 43 | +```svelte |
| 44 | +<script> |
| 45 | + /* eslint svelte/sort-attributes: "error" */ |
| 46 | +</script> |
| 47 | +
|
| 48 | +<!-- ✓ GOOD --> |
| 49 | +<svelte:component |
| 50 | + this={component} |
| 51 | + --style-props={color} |
| 52 | + bind:value={componentValue} |
| 53 | + on:changeValue={handleChange} |
| 54 | + bind:metaData |
| 55 | +/> |
| 56 | +<input |
| 57 | + bind:this={foo} |
| 58 | + id="foo" |
| 59 | + style="width: 150px;" |
| 60 | + style:color |
| 61 | + class="my-input" |
| 62 | + class:disable |
| 63 | + class:enable={!disable} |
| 64 | + bind:value={inputValue} |
| 65 | + use:action={parameters} |
| 66 | + transition:fn |
| 67 | + in:fn |
| 68 | + out:fn |
| 69 | + animate:name |
| 70 | +/> |
| 71 | +<slot name="content" {abc} {def} /> |
| 72 | +
|
| 73 | +<!-- ✗ BAD --> |
| 74 | +<svelte:component |
| 75 | + bind:value={componentValue} |
| 76 | + this={component} |
| 77 | + on:changeValue={handleChange} |
| 78 | + {def} |
| 79 | + data-foo |
| 80 | + {abc} |
| 81 | + bind:metaData |
| 82 | + --style-props={color} |
| 83 | +/> |
| 84 | +<input |
| 85 | + id="foo" |
| 86 | + bind:this={foo} |
| 87 | + style:color |
| 88 | + style="width: 150px;" |
| 89 | + class="my-input" |
| 90 | + class:enable={!disable} |
| 91 | + class:disable |
| 92 | + animate:name |
| 93 | + use:action |
| 94 | + transition:fn |
| 95 | + bind:value={inputValue} |
| 96 | + in:fn |
| 97 | + out:fn |
| 98 | +/> |
| 99 | +<slot name="content" {def} {abc} data-foo /> |
| 100 | +``` |
| 101 | + |
| 102 | +<!-- prettier-ignore-end --> |
| 103 | + |
| 104 | +</ESLintCodeBlock> |
| 105 | + |
| 106 | +If there is a spread attribute between the attributes, it will not be reported as changing the order can change the behavior. |
| 107 | + |
| 108 | +<ESLintCodeBlock fix> |
| 109 | + |
| 110 | +<!--eslint-skip--> |
| 111 | + |
| 112 | +```svelte |
| 113 | +<script> |
| 114 | + /* eslint svelte/sort-attributes: "error" */ |
| 115 | +</script> |
| 116 | +
|
| 117 | +<!-- ✓ GOOD --> |
| 118 | +<div c d {...attrs} a b /> |
| 119 | +
|
| 120 | +<!-- ✗ BAD --> |
| 121 | +<div d c {...attrs} b a /> |
| 122 | +``` |
| 123 | + |
| 124 | +</ESLintCodeBlock> |
| 125 | + |
| 126 | +## :wrench: Options |
| 127 | + |
| 128 | +```jsonc |
| 129 | +{ |
| 130 | + "svelte/sort-attributes": [ |
| 131 | + "error", |
| 132 | + { |
| 133 | + "order": [ |
| 134 | + // `this` property. |
| 135 | + "this", |
| 136 | + // `bind:this` directive. |
| 137 | + "bind:this", |
| 138 | + // `id` attribute. |
| 139 | + "id", |
| 140 | + // `name` attribute. |
| 141 | + "name", |
| 142 | + // `slot` attribute. |
| 143 | + "slot", |
| 144 | + // `--style-props` (Alphabetical order within the same group.) |
| 145 | + { "match": "/^--/u", "sort": "alphabetical" }, |
| 146 | + // `style` attribute, and `style:` directives. |
| 147 | + ["style", "/^style:/u"], |
| 148 | + // `class` attribute. |
| 149 | + "class", |
| 150 | + // `class:` directives. (Alphabetical order within the same group.) |
| 151 | + { "match": "/^class:/u", "sort": "alphabetical" }, |
| 152 | + // other attributes. (Alphabetical order within the same group.) |
| 153 | + { |
| 154 | + "match": ["!/:/u", "!/^(?:this|id|name|style|class)$/u", "!/^--/u"], |
| 155 | + "sort": "alphabetical" |
| 156 | + }, |
| 157 | + // `bind:` directives (other then `bind:this`), and `on:` directives. |
| 158 | + ["/^bind:/u", "!bind:this", "/^on:/u"], |
| 159 | + // `use:` directives. (Alphabetical order within the same group.) |
| 160 | + { "match": "/^use:/u", "sort": "alphabetical" }, |
| 161 | + // `transition:` directive. |
| 162 | + { "match": "/^transition:/u", "sort": "alphabetical" }, |
| 163 | + // `in:` directive. |
| 164 | + { "match": "/^in:/u", "sort": "alphabetical" }, |
| 165 | + // `out:` directive. |
| 166 | + { "match": "/^out:/u", "sort": "alphabetical" }, |
| 167 | + // `animate:` directive. |
| 168 | + { "match": "/^animate:/u", "sort": "alphabetical" }, |
| 169 | + // `let:` directives. (Alphabetical order within the same group.) |
| 170 | + { "match": "/^let:/u", "sort": "alphabetical" } |
| 171 | + ] |
| 172 | + } |
| 173 | + ] |
| 174 | +} |
| 175 | +``` |
| 176 | + |
| 177 | +- `order` ... Specify an array of your preferred attribute order. Array elements accept strings, string arrays, and objects. |
| 178 | + - String ... Specify the name or pattern of the attribute. |
| 179 | + - String array ... Specifies an array of the names or patterns of the attributes to be grouped. It will not be sorted within this same group. |
| 180 | + - Object ... Specifies an object with a definition for sorting within the same group. |
| 181 | + - `match` ... Specifies an array or string of the name or pattern of the attributes to be grouped. |
| 182 | + - `sort` ... Specify the sorting method. Currently, only `"alphabetical"` is supported. |
| 183 | + - `"alphabetical"` ... Sorts the attributes of the same group in alphabetical order. |
| 184 | + - `"ignore"` ... Attributes in the same group are not sorted. |
| 185 | + |
| 186 | +Note that the behavior may change depending on how you specify the `order` setting. |
| 187 | +For example, `bind:value` and `on:input={() => console.log(value)}` behave differently depending on the order. See <https://svelte.dev/docs#template-syntax-element-directives-bind-property> for details. |
| 188 | +By default it is designed to be sorted safely. |
| 189 | + |
| 190 | +You can use the following formats for names or patterns: |
| 191 | + |
| 192 | +- `"foo"` ... Matches only the `foo` attribute name. |
| 193 | +- `"/foo/"` ... Matches attribute names that match the `/foo/` regex. That is, it matches the attribute name including `foo`. |
| 194 | +- `"!foo"` ... Exclude `foo` attribute from the matched attribute names. When used first in the array or alone, matches other than the `foo` attribute name. |
| 195 | +- `"!/foo/"` ... Excludes attributes that match the `/foo/` regex from the matched attribute names. When used first in the array or alone, matches an attribute name that does not match the `/foo/` regex. |
| 196 | +- `["style", "/^style:/u"]` ... Matches the `style` attribute or the attribute name that matches the `/^style:/u` regex. |
| 197 | +- `["/^bind:/u", "!bind:this", "/^on:/u"]` ... Matches an attribute name that matches `/^bind:/u` and other than `bind:this`, or an attribute name that matches `/^on:/u`. |
| 198 | + |
| 199 | +### `{ order: [ /*See below*/ ] }` |
| 200 | + |
| 201 | +<ESLintCodeBlock fix> |
| 202 | + |
| 203 | +<!--eslint-skip--> |
| 204 | + |
| 205 | +```svelte |
| 206 | +<script> |
| 207 | + /* eslint svelte/sort-attributes: ["error", { |
| 208 | + "order": [ |
| 209 | + "id", |
| 210 | + "class", |
| 211 | + "/^class:/u", |
| 212 | + "value", |
| 213 | + "src", |
| 214 | + "/^data-/u", |
| 215 | + "style", |
| 216 | + "/^style:/u", |
| 217 | + "/^on:/u", |
| 218 | + "/^use:/u", |
| 219 | + "/^animate:/u", |
| 220 | + "/^transition:/u", |
| 221 | + "/^in:/u", |
| 222 | + "/^out:/u", |
| 223 | + "bind:this", |
| 224 | + ["/^bind:/u", "!bind:this"], |
| 225 | + { |
| 226 | + "match": ["!/:/u", "!/^(?:id|class|value|src|style)$/u", "!/^data-/u"], |
| 227 | + "sort": "alphabetical" |
| 228 | + }, |
| 229 | + ] |
| 230 | + }] */ |
| 231 | +</script> |
| 232 | +
|
| 233 | +<!-- ✓ GOOD --> |
| 234 | +<MyComponent data-foo bind:this={comp} bind:data {abc} {def} /> |
| 235 | +<input |
| 236 | + id="foo" |
| 237 | + class="my-block" |
| 238 | + class:bar |
| 239 | + value="abc" |
| 240 | + data-value="x" |
| 241 | + style="width: 30px;" |
| 242 | + style:color |
| 243 | + animate:name |
| 244 | + transition:fn |
| 245 | + in:fn |
| 246 | + out:fn |
| 247 | + bind:this={foo} |
| 248 | +/> |
| 249 | +<img id="bar" {src} alt="bar" /> |
| 250 | +
|
| 251 | +<!-- ✗ BAD --> |
| 252 | +<MyComponent bind:data bind:this={comp} {abc} {def} data-foo /> |
| 253 | +<input |
| 254 | + class:bar |
| 255 | + class="my-block" |
| 256 | + id="foo" |
| 257 | + bind:this={foo} |
| 258 | + value="abc" |
| 259 | + style:color |
| 260 | + style="width: 30px;" |
| 261 | + data-value="x" |
| 262 | + animate:name |
| 263 | + in:fn |
| 264 | + out:fn |
| 265 | + transition:fn |
| 266 | +/> |
| 267 | +<img alt="bar" {src} id="bar" /> |
| 268 | +``` |
| 269 | + |
| 270 | +</ESLintCodeBlock> |
| 271 | + |
| 272 | +## :mag: Implementation |
| 273 | + |
| 274 | +- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/sort-attributes.ts) |
| 275 | +- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/sort-attributes.ts) |
0 commit comments