diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f627147e4..bae48b418d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,18 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-unknown-property`]: `onError` and `onLoad` both work on `img` and `script` ([#3388][] @ljharb) +* [`no-unknown-property`]: data-* attributes can have numbers ([#3390][] @sjarva) +* [`no-unknown-property`]: add more audio/video attributes ([#3390][] @sjarva) +* [`no-unknown-property`]: move allowfullscreen to case ignored attributes ([#3390][] @sjarva) +* [`no-unknown-property`]: fill works on line, mask, and use elements ([#3390][] @sjarva) +* [`no-unknown-property`]: add onMouseMoveCapture as valid react-specific attribute ([#3390][] @sjarva) +* [`no-unknown-property`]: make onLoad and onError be accepted on more elements ([#3390][] @sjarva) +### Changed + +* [Docs] [`no-unknown-property`]: add a mention about using ignores properties with libraries that add props ([#3390][] @sjarva) + +[#3390]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3390 [#3388]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3388 ## [7.31.5] - 2022.09.03 diff --git a/docs/rules/no-unknown-property.md b/docs/rules/no-unknown-property.md index 108fa42a44..d142def850 100644 --- a/docs/rules/no-unknown-property.md +++ b/docs/rules/no-unknown-property.md @@ -43,7 +43,6 @@ var AnotherComponent = ; // Custom web components are ignored var MyElem =
; var AtomPanel = ; - ``` ## Rule Options @@ -57,6 +56,23 @@ var AtomPanel = ; - `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0. - `ignore`: optional array of property and attribute names to ignore during validation. +If you are using a library that passes something as a prop to JSX elements, it is recommended to add those props to the ignored properties. + +For example, if you use [emotion](https://emotion.sh/docs/introduction) and its [`css` prop](https://emotion.sh/docs/css-prop)), +add the following to your `.eslintrc` config file: + +```js +... +"react/no-unknown-property": ['error', { ignore: ['css'] }] +... +``` + +Now, the following code passes: + +```jsx +var StyledDiv =
; +``` + ## When Not To Use It If you are not using JSX you can disable this rule. diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js index 2867c5d5b1..25a8ece9c6 100644 --- a/lib/rules/no-unknown-property.js +++ b/lib/rules/no-unknown-property.js @@ -36,6 +36,8 @@ const ATTRIBUTE_TAGS_MAP = { 'circle', 'ellipse', 'g', + 'line', + 'mask', 'path', 'polygon', 'polyline', @@ -45,6 +47,7 @@ const ATTRIBUTE_TAGS_MAP = { 'textPath', 'tref', 'tspan', + 'use', // Animation final state 'animate', 'animateColor', @@ -63,8 +66,8 @@ const ATTRIBUTE_TAGS_MAP = { onEmptied: ['audio', 'video'], onEncrypted: ['audio', 'video'], onEnded: ['audio', 'video'], - onError: ['audio', 'video', 'img', 'script'], - onLoad: ['script', 'img'], + onError: ['audio', 'video', 'img', 'link', 'source', 'script'], + onLoad: ['script', 'img', 'link'], onLoadedData: ['audio', 'video'], onLoadedMetadata: ['audio', 'video'], onLoadStart: ['audio', 'video'], @@ -82,6 +85,16 @@ const ATTRIBUTE_TAGS_MAP = { onWaiting: ['audio', 'video'], scrolling: ['iframe'], playsInline: ['video'], + // Video related attributes + autoPictureInPicture: ['video'], + controls: ['audio', 'video'], + controlList: ['video'], + disablePictureInPicture: ['video'], + disableRemotePlayback: ['audio', 'video'], + loop: ['audio', 'video'], + muted: ['audio', 'video'], + poster: ['video'], + preload: ['audio', 'video'], }; const SVGDOM_ATTRIBUTE_NAMES = { @@ -199,6 +212,8 @@ const DOM_PROPERTY_NAMES_ONE_WORD = [ 'property', // React specific attributes 'ref', 'key', 'children', + // Video specific + 'controls', ]; const DOM_PROPERTY_NAMES_TWO_WORDS = [ @@ -209,7 +224,7 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ // Element specific attributes // See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes (includes global attributes too) // To be considered if these should be added also to ATTRIBUTE_TAGS_MAP - 'acceptCharset', 'allowFullScreen', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'classID', 'codeBase', + 'acceptCharset', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'classID', 'codeBase', 'colSpan', 'contextMenu', 'dateTime', 'encType', 'formAction', 'formEncType', 'formMethod', 'formNoValidate', 'formTarget', 'frameBorder', 'hrefLang', 'httpEquiv', 'isMap', 'keyParams', 'keyType', 'marginHeight', 'marginWidth', 'maxLength', 'mediaGroup', 'minLength', 'noValidate', 'onAnimationEnd', 'onAnimationIteration', 'onAnimationStart', @@ -258,9 +273,12 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ 'onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting', + 'onMouseMoveCapture', + // Video specific, + 'autoPictureInPicture', 'controlList', 'disablePictureInPicture', 'disableRemotePlayback', ]; -const DOM_PROPERTIES_IGNORE_CASE = ['charset']; +const DOM_PROPERTIES_IGNORE_CASE = ['charset', 'allowfullscreen']; const ARIA_PROPERTIES = [ // See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes @@ -338,14 +356,14 @@ function isValidHTMLTagInJSX(childNode) { /** * Checks if an attribute name is a valid `data-*` attribute: - * if the name starts with "data-" and has some lowcase (a to z) words, separated but hyphens (-) + * if the name starts with "data-" and has some lowcase (a to z) words that can contain numbers, separated but hyphens (-) * (which is also called "kebab case" or "dash case"), then the attribute is valid data attribute. * * @param {String} name - Attribute name to be tested * @returns {boolean} Result */ function isValidDataAttribute(name) { - const dataAttrConvention = /^data(-[a-z]*)*$/; + const dataAttrConvention = /^data(-[a-z1-9]*)*$/; return !!dataAttrConvention.test(name); } diff --git a/tests/lib/rules/no-unknown-property.js b/tests/lib/rules/no-unknown-property.js index d25c3d7cb4..5312003511 100644 --- a/tests/lib/rules/no-unknown-property.js +++ b/tests/lib/rules/no-unknown-property.js @@ -54,11 +54,14 @@ ruleTester.run('no-unknown-property', rule, { { code: ';' }, { code: '' }, { code: '' }, + { code: '' }, { code: '' }, { code: '' }, { code: '