Indentation: JSX child element multiline prop gets unexpected extra indentation level
See original GitHub issueTell us about your environment
- ESLint Version: 5.6.0
- Node Version: 9.8.0
- npm Version: 5.6.0
What parser (default, Babel-ESLint, etc.) are you using? Babel-ESLint
Please show your full configuration:
Configuration
{
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"babel",
"react"
],
"rules": {
"indent": [ "error", 4 ],
"indent-legacy": "off",
"jsx-quotes": [ "error", "prefer-double" ]
}
}
What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.
export default <test prop={
null
}><inner prop={
null
} /></test>;
node_modules/.bin/eslint test.jsx
What did you expect to happen? No errors
What actually happened? Please include the actual, raw output from ESLint.
$ node_modules/.bin/eslint test.jsx
/path/to/project/test.jsx
4:1 error Expected indentation of 8 spaces but found 4 indent
5:1 error Expected indentation of 4 spaces but found 0 indent
✖ 2 problems (2 errors, 0 warnings)
2 errors and 0 warnings potentially fixable with the `--fix` option.
My initial encounter with this behaviour was with more complex use cases (JSX function-as-a-child pattern) but the above sample syntax is the simplest one that still triggers the indentation error.
In comparison, the following JSX syntax does not trigger the indentation error:
export default <test prop={null}><inner prop={
null
} /></test>;
Looking at indent.js
, I think the place that effects this result is the JSX element handler:
// ...
JSXElement(node) {
if (node.closingElement) {
addElementListIndent(node.children, sourceCode.getFirstToken(node.openingElement), sourceCode.getFirstToken(node.closingElement), 1);
}
},
// ...
The children of an element are expected to be 1 level in, relative to the starting token of the opening tag - which is the <
. However, if the child starts on the same line as the opening tag, that offset is nullified (per logic in getDesiredIndent(token)
function).
This is why the second JSX example does not trigger the indentation error - the inner element starts on same line as the starting <
of the outer element. But in the first JSX example the inner element is no longer on the same line as the outer element’s <
token, and that makes the lint rule expect one more indentation level for the inner element’s prop value.
The obvious workaround is to just put <inner ... />
on a new line and indent it. But it feels like using the starting <
as indentation offset reference is a bit too simplistic? Just doesn’t feel completely “right”; also, we use a lot of function-as-a-child syntax and it would help save on indentation levels.
In my tests, I changed the JSX element handler logic to use the last token of the opening tag (i.e. the >
that immediately precedes the contents), and that worked really well. If the child literal or expression starts on a new line, then the indentation level is increased by one as intended, but if it is on the same line, then the offset gets correctly ignored and the inner multiline props do not trigger the indentation error.
However, there is a problem with that approach - in some style guides, the opening tag’s >
is expected to be indented relative to the <
: i.e the react/jsx-closing-bracket-location
rule with props-aligned
setting. Thus, the following code would be valid but still trip up indent
if the >
is used as offset reference:
export default <test
prop={null}
>
Some content
</test>;
I am not sure how many folks are using that convention - the indent
rule actually “fights” it anyway as is - but that is still a caveat.
Thoughts? If there is a configuration option that might apply, happy to try it.
Thanks!
Issue Analytics
- State:
- Created 5 years ago
- Comments:10 (4 by maintainers)
Top GitHub Comments
Folks, this turned out to be not enough of a priority to put out a polished-enough fix on my end - I just got used to a more indent-heavy code style anyway. Thanks for helping discuss this!
Yes, we can reopen this, no worries. Thanks for your interest!