Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.
Nest a component inside another and keep heading levels valid
Published
A component with a collection of its own can hold components; the heading level is the thing that breaks. Keep the current level in the template context: read it, print, raise it for children, restore it afterwards.
Context
Context. Nesting is a collection area on a component layout: a "columns" component holds a collection whose elements are cards. The mechanics are the same loop as on a page. What goes wrong is the outline: every card prints an <h2> because it does not know it sits under the section's <h2>. The current level lives in the shared template context, which every render in the page can read and write.
Steps
In the page template, after the <h1>, set the level to 2.
In every component that prints a heading: read the level, print at it, set level + 1 for the children, render the children, restore the level.
In a component that prints no heading, pass through: render the children without touching the level.
{# page template, after the h1 #}
{% do _templateContext.set('headingLevel', 2) %}
{# components/columns.html #}
{% set level = _templateContext.get('headingLevel', 2) %}
{% if component.heading is not empty %}
<h{{ level }}>{{ component.heading }}</h{{ level }}>
{% do _templateContext.set('headingLevel', level + 1) %}
{% endif %}
<div class="columns">
{% for element in component.getAreaCollectionElements('columns') %}
<div class="col">{{ element.getComponent().getHtml() }}</div>
{% endfor %}
</div>
{% do _templateContext.set('headingLevel', level) %}
Why this and not that
Not a headingLevel variable passed through getHtml(): it works one level down and stops, and a passed variable cannot override one the page already holds. Not a fixed level per component ("cards are always h3"): the same card sits at three depths on one site. Cap the nesting with supported layouts at three levels; beyond that the outline is right and the page is slow.