diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d957976ac..a2eed5f339 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
### Added
* [`display-name`]: add `checkContextObjects` option ([#3529][] @JulesBlm)
+* [`jsx-first-prop-new-line`]: add `multiprop` option ([#3533][] @haydncomley)
### Fixed
* [`no-array-index-key`]: consider flatMap ([#3530][] @k-yle)
@@ -14,6 +15,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`no-unknown-property`]: allow `onLoad` on `source` (@ljharb)
[#3538]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3538
+[#3533]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3533
[#3530]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3530
[#3529]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3529
diff --git a/docs/rules/jsx-first-prop-new-line.md b/docs/rules/jsx-first-prop-new-line.md
index 0ec839dbdc..36215794cf 100644
--- a/docs/rules/jsx-first-prop-new-line.md
+++ b/docs/rules/jsx-first-prop-new-line.md
@@ -15,6 +15,7 @@ This rule checks whether the first property of all JSX elements is correctly pla
- `always`: The first property should always be placed on a new line.
- `never` : The first property should never be placed on a new line, e.g. should always be on the same line as the Component opening tag.
- `multiline`: The first property should always be placed on a new line when the JSX tag takes up multiple lines.
+- `multiprop`: The first property should never be placed on a new line unless there are multiple properties.
- `multiline-multiprop`: The first property should always be placed on a new line if the JSX tag takes up multiple lines and there are multiple properties. This is the `default` value.
Examples of **incorrect** code for this rule, when configured with `"always"`:
diff --git a/lib/rules/jsx-first-prop-new-line.js b/lib/rules/jsx-first-prop-new-line.js
index d301a5f3aa..143368c137 100644
--- a/lib/rules/jsx-first-prop-new-line.js
+++ b/lib/rules/jsx-first-prop-new-line.js
@@ -30,7 +30,7 @@ module.exports = {
messages,
schema: [{
- enum: ['always', 'never', 'multiline', 'multiline-multiprop'],
+ enum: ['always', 'never', 'multiline', 'multiline-multiprop', 'multiprop'],
}],
},
@@ -46,6 +46,7 @@ module.exports = {
if (
(configuration === 'multiline' && isMultilineJSX(node))
|| (configuration === 'multiline-multiprop' && isMultilineJSX(node) && node.attributes.length > 1)
+ || (configuration === 'multiprop' && node.attributes.length > 1)
|| (configuration === 'always')
) {
node.attributes.some((decl) => {
@@ -59,7 +60,10 @@ module.exports = {
}
return true;
});
- } else if (configuration === 'never' && node.attributes.length > 0) {
+ } else if (
+ (configuration === 'never' && node.attributes.length > 0)
+ || (configuration === 'multiprop' && isMultilineJSX(node) && node.attributes.length <= 1)
+ ) {
const firstNode = node.attributes[0];
if (node.loc.start.line < firstNode.loc.start.line) {
report(context, messages.propOnSameLine, 'propOnSameLine', {
diff --git a/tests/lib/rules/jsx-first-prop-new-line.js b/tests/lib/rules/jsx-first-prop-new-line.js
index 8fea1441fc..7e5d485689 100644
--- a/tests/lib/rules/jsx-first-prop-new-line.js
+++ b/tests/lib/rules/jsx-first-prop-new-line.js
@@ -139,6 +139,24 @@ ruleTester.run('jsx-first-prop-new-line', rule, {
`,
options: ['always'],
},
+ {
+ code: `
+
+ `,
+ options: ['multiprop'],
+ },
+ {
+ code: `
+
+ `,
+ options: ['multiprop'],
+ },
+ {
+ code: `
+
+ `,
+ options: ['multiprop'],
+ },
]),
invalid: parsers.all([
@@ -209,5 +227,38 @@ bar={{
options: ['multiline-multiprop'],
errors: [{ messageId: 'propOnNewLine' }],
},
+ {
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: ['multiprop'],
+ errors: [{ messageId: 'propOnNewLine' }],
+ },
+ {
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: ['multiprop'],
+ errors: [{ messageId: 'propOnSameLine' }],
+ },
+ {
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: ['multiprop'],
+ errors: [{ messageId: 'propOnSameLine' }],
+ },
]),
});