diff --git a/debug/src/debug.js b/debug/src/debug.js
index 73c9c3dcef..56998711a1 100644
--- a/debug/src/debug.js
+++ b/debug/src/debug.js
@@ -353,7 +353,13 @@ export function initDebug() {
});
}
- if (typeof type === 'string' && (isTableElement(type) || type === 'p')) {
+ if (
+ typeof type === 'string' &&
+ (isTableElement(type) ||
+ type === 'p' ||
+ type === 'a' ||
+ type === 'button')
+ ) {
// Avoid false positives when Preact only partially rendered the
// HTML tree. Whilst we attempt to include the outer DOM in our
// validation, this wouldn't work on the server for
@@ -420,6 +426,16 @@ export function initDebug() {
`\n\n${getOwnerStack(vnode)}`
);
}
+ } else if (type === 'a' || type === 'button') {
+ if (getDomChildren(vnode).indexOf(type) !== -1) {
+ console.error(
+ `Improper nesting of interactive content. Your <${type}>` +
+ ` should not have other ${type === 'a' ? 'anchor' : 'button'}` +
+ ' tags as child-elements.' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
}
}
diff --git a/debug/test/browser/debug.test.js b/debug/test/browser/debug.test.js
index b88bd8cb2c..fa318697d8 100644
--- a/debug/test/browser/debug.test.js
+++ b/debug/test/browser/debug.test.js
@@ -667,6 +667,94 @@ describe('debug', () => {
});
});
+ describe('button nesting', () => {
+ it('should not warn on a regular button', () => {
+ const Button = () => ;
+
+ render(, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ it('should warn for nesting illegal dom-nodes under a button', () => {
+ const Button = () => (
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should warn for nesting illegal dom-nodes under a button as func', () => {
+ const ButtonChild = ({ children }) => {children};
+ const Button = () => (
+
+ Hello world
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should not warn for nesting non-interactive content under a button', () => {
+ const Button = () => (
+
+ Hello
+ World
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.not.be.called;
+ });
+ });
+
+ describe('anchor nesting', () => {
+ it('should not warn a regular anchor', () => {
+ const Anchor = () => Hello world;
+
+ render(, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ it('should warn for nesting illegal dom-nodes under an anchor', () => {
+ const Anchor = () => (
+
+ Hello world
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should warn for nesting illegal dom-nodes under an anchor as func', () => {
+ const AnchorChild = ({ children }) => {children};
+ const Anchor = () => (
+
+ Hello world
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should not warn for nesting non-interactive content under an anchor', () => {
+ const Anchor = () => (
+
+ Hello
+ World
+
+ );
+
+ render(, scratch);
+ expect(console.error).to.not.be.called;
+ });
+ });
+
describe('PropTypes', () => {
beforeEach(() => {
resetPropWarnings();