The HTML Tags Checker uses a sophisticated validation algorithm implemented in the canContain() function to determine if one HTML element can contain another according to W3C standards.
Core Function: canContain(parentTag, childTag) in index.js:779-899 is the heart of the validation engine.
// If child is a void element, it can be in almost any locationif (childType === 'void') { return { valid: true, message: messages.voidChild.replace('{parent}', parentTag).replace('{child}', childTag), warning: false };}
Void elements can be children: Void elements like <br>, <img>, <hr> can appear in most contexts.
Example:
canContain('p', 'br')// Returns: { valid: true, message: "The <p> tag can contain the void element <br>." }
These special cases enforce that interactive elements (<a>, <button>, <label>) cannot contain block-level elements, even though their specific rules allow ‘inline’ and ‘text’.
Example:
canContain('button', 'div')// Returns: { valid: false, message: "The <button> tag cannot contain block elements like <div>..." }
Block elements follow general rules allowing both block and inline children. From index.js:860-867:
// General rules for block elementsif (parentType === 'block') { // Block elements can contain block or inline elements return { valid: true, message: messages.blockCanContain.replace('{parent}', parentTag).replace('{child}', childTag), warning: false };}
Block flexibility: Most block elements (<div>, <section>, <article>) can contain any block or inline elements.
Example:
canContain('div', 'section')// Returns: { valid: true, message: "The <div> tag is a block element and can contain block or inline elements like <section>." }canContain('article', 'p')// Returns: { valid: true, message: "The <article> tag is a block element and can contain block or inline elements like <p>." }
Inline elements have strict restrictions. From index.js:870-891:
// General rules for inline elementsif (parentType === 'inline') { // Inline elements can only contain inline elements or text if (childType === 'inline') { return { valid: true, message: messages.inlineCanContain.replace('{parent}', parentTag).replace('{child}', childTag), warning: false }; } else if (childType === 'void') { return { valid: true, message: messages.inlineCanContainVoid.replace('{parent}', parentTag).replace('{child}', childTag), warning: false }; } else { return { valid: false, message: messages.inlineCannotContain.replace('{parent}', parentTag).replace('{child}', childTag), warning: false }; }}
Inline restriction: Inline elements can only contain other inline or void elements, never block elements.
Examples:
canContain('span', 'strong')// Returns: { valid: true, message: "The <span> tag is an inline element and can contain other inline elements like <strong>." }canContain('span', 'br')// Returns: { valid: true, message: "The <span> tag is an inline element and can contain void elements like <br>." }canContain('span', 'div')// Returns: { valid: false, message: "The <span> tag is an inline element and cannot contain block elements like <div>..." }
Every validation returns a consistent object structure:
interface ValidationResult { valid: boolean; // Is the nesting allowed? message: string; // Descriptive message explaining the result warning: boolean; // Is this a warning case? (valid but uncertain)}
Valid
{ valid: true, warning: false }Nesting is explicitly allowed by HTML5 standards.