# Does ht-include allow for recursion?

**URL:** <https://hypertexting.community/t/does-ht-include-allow-for-recursion/61>\
**Category:** HyperTemplates\
**Created:** [June 18, 2025, 3:34pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61 "2025-06-18T15:34:17Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 18, 2025, 3:34pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/1 "2025-06-18T15:34:17Z")

</div>

Does ht-include allow for recursion?

Meaning, can we ht-include a HTML file which then ht-includes some other HTML file which then ht-includes some other HTML file … ?

This would finally solve the long-standing HTML pain point of not being able to compartmentalize content.

Thanks.

---

<div class="post-metadata">

**Author:** ![jordan](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/jordan/32/19_2.png) [@jordan](https://hypertexting.community/u/jordan)\
**Post date:** [June 18, 2025, 8:17pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/2 "2025-06-18T20:17:32Z")

</div>

Yes, totally! Here is a quick example… Let’s say your layout has an element with `ht-include='partials/parent-component.html'`:

```html
<section>
  <article ht-include='partials/parent-component.html'></article>
</section>

```

… and `partials/parent-component.html` looks like this:

```html
<article>
  <h2>This is a parent component</h2>
  <div ht-include='partials/sub-component.html'>PLACEHOLDER FOR SUB-COMPONENT</div>
</article>

```

… and `partials/sub-component.html` looks like this:

```html
<p>This is a sub component</p>

```

Then the output would be:

```html
<section>
  <article>
    <h2>This is a parent component</h2>
    <p>This is a sub component</p>
  </article>
</section>

```

Hopefully that answers your question? Or were you thinking more along the lines of a component that calls _itself_ recursively? ~~I haven’t tested that…~~ 🤔

EDIT: just tested this, a partial recursively calling itself, I think the build wasn’t happy. I didn’t see any errors get spit out, but perhaps it should… Pinging @calebhailey.com for input here. While may not be very likely someone will try to do this, would be good to get an error from the CLI and maybe have a comment added to the docs with a mention that this should not be done. ([ht-include attribute](https://hypertemplates.net/docs/reference/core/attributes/ht-include/))

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [June 18, 2025, 8:50pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/3 "2025-06-18T20:50:35Z")

</div>

Yes, this is supported, as @jordan already explained. There aren’t currently any guard rails around a component including itself (I’ll open an issue for that), so some caution is necessary, but for the most part it should work exactly you hoped it would @AtmanActive 👍

I hope this helps!

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 18, 2025, 11:26pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/4 "2025-06-18T23:26:05Z")

</div>

This is awesome.

How about conditional inclusion?  
Variable-driven inclusion?

For example, if cookie ‘lang’ has value ‘fr’, then we ht-include /something/$cookie\_value.lang/somethingelse …

Is that supported?

(I did read the docs, but questions & answers like this help to cut through the fog and summarize the available advanced concepts.)

Thanks.

---

<div class="post-metadata">

**Author:** ![jordan](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/jordan/32/19_2.png) [@jordan](https://hypertexting.community/u/jordan)\
**Post date:** [June 19, 2025, 1:19am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/5 "2025-06-19T01:19:12Z")

</div>

> [@AtmanActive](#):
>
> How about conditional inclusion?  
> Variable-driven inclusion?
> 
> For example, if cookie ‘lang’ has value ‘fr’, then we ht-include /something/$cookie\_value.lang/somethingelse …

hmm… 🤔

I’m definitely not a power user at this point, I’m also not at my computer to test right now, so I don’t quite know if that is possible. I don’t know if you can put variables within the attribute value like that, but I’m fairly certain _there is an approach_ to accomplish this — just requires a slight shift in thinking… It is likely not going to be done with `ht-include` alone… we might need some combination of `ht-if` / `ht-not` attributes… Or this might be better suited for [the ht-block attribute](https://hypertemplates.net/docs/reference/core/attributes/ht-block/).

Also worth noting here that if we’re speaking of using the `hyperctl` cli tool for static site generation, _no client-side data_ like cookies and such would be accessible at build time.

**I might be able to work on some mockups of layouts that change based on variables, but to make sure I’m on the same page, do you have any examples of how you would want your HTML layout to change related to some data variable?**

Taking your example of a `lang` variable, I could see there being some layout differences with certain language variants based on [their writing mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode), but I could also see how a modern CSS approach would likely resolve the need for different templates. For example, instead of using directional styling like `margin-top`, `margin-left`, where we might run into styling rules that don’t quite work between languages that flow in different directions. However using [margin-block-start](https://developer.mozilla.org/en-US/docs/Web/CSS/margin-block-start) and [margin-inline-start](https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-start) might remedy those issues without needing a separate HTML layout.

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 19, 2025, 10:13am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/6 "2025-06-19T10:13:53Z")

</div>

I don’t have anything particular in mind. We are just brainstorming here.

Yes, cookie is a bad example since that is runtime information.

I guess, variables could come from ENV or from site.json or from a command line parameter?

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [June 19, 2025, 6:51pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/7 "2025-06-19T18:51:32Z")

</div>

Currently there are four sources of template data: site data, page data, namespace data, and layout data. I just updated the documentation to make this more clear (see the “Template data sources” heading):

> **[Template Data](https://hypertemplates.net/docs/reference/core/data/#template-data-sources)**
>
> Learn more about the HyperTemplates data model.

Depending on the data structure, one or both of the [`ht-if`](https://hypertemplates.net/docs/reference/core/attributes/ht-if/) and [`ht-not`](https://hypertemplates.net/docs/reference/core/attributes/ht-not/) attributes could be used to configure conditional layouts. And these can be combined with `ht-include` or any of the other templating attributes. Understanding the [order](https://hypertemplates.net/docs/reference/core/pipeline/#order-of-operations) in which these templating attributes are evaluated may help you imagine how they might be combined to achieve different results.

[Lesson 3](https://hypertemplates.net/docs/tutorials/learn/lesson-3/) of the [Learn HyperTemplates tutorial](https://hypertemplates.net/docs/tutorials/learn/) provides a simple introduction to conditional templating. It doesn’t get into [conditional _values_](https://hypertemplates.net/docs/reference/core/attributes/ht-if/#conditional-values), like `ht-if='page.foo==baz'` but those are also supported.

_PS – So far your first two questions are in the same order that we have documented the [templating attributes reference](https://hypertemplates.net/docs/reference/core/attributes/) – includes (`ht-include`), then conditional templating (`ht-if` and `ht-not`). In the off chance that you’re thinking about these high level concepts in the same order that we’ve documented them, the next templating attribute that might be of interest is `ht-template` which **repeats** elements (i.e. `for...in` or `for...of` loops)._ 😊

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 20, 2025, 12:37am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/8 "2025-06-20T00:37:46Z")

</div>

Alright, thank you.

I read the [Template Data Sources](https://hypertemplates.net/docs/reference/core/data/#template-data-sources), and it seems to me there is still something missing: an ad-hoc layer of data/variables that could be set/overridden at build time. Like a GLOBAL object that exists at all times and is set/overridden with ENV and/or command line parameters, without touching site.json. In this way, depending on the environment, CLI could build several versions of the site from the same source. Similar to how you now treat [$ENV{ HYPER\_CONFIG }](https://hypertemplates.net/docs/reference/cli/commands/build/#c-config), but available to inner workings and data sources (to use in paths, ht-ifs, ht-nots, and so on).

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 20, 2025, 9:27am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/9 "2025-06-20T09:27:36Z")

</div>

… and just like that I accidentally stumbled upon an explanation of the concept I’m talking about in a somewhat related tool called [Hurl](https://hurl.dev/docs/templates.html#injecting-variables).

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [June 20, 2025, 5:59pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/10 "2025-06-20T17:59:39Z")

</div>

Hurl looks cool! I think I’ve seen this before.

In any case, I like the idea of an `env.` template data prefix. I suspect it will put an asterisk on HyperTemplates guarantees RE: reproducible builds, but I think that’s acceptable.

> **[Builds](https://hypertemplates.net/docs/reference/cms/builds/#reproducible-builds)**
>
> The pure-HTML templating system for the modern web.

A website that doesn’t use environment template data will always be reproducible, and even websites that do use environment variables can be reproducible with care.

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 20, 2025, 6:47pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/11 "2025-06-20T18:47:36Z")

</div>

In my humble opinion, it is important to have sensible defaults, so that lack of defined GLOBAL variables doesn’t wreck havoc. It is expected that 99% of sites/setups/builds won’t be using these, but then, when/if a need arises, it should be easy to start using them.

For example: global.language, shouldn’t be empty, or undefined, but should have value of “en”, if not defined anywhere. Then, just by adding ENV HYPTEM\_language and setting it to “fr”, enables build process to explicitly build that version of the site (if used in the templates, of course).

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [June 20, 2025, 7:42pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/12 "2025-06-20T19:42:03Z")

</div>

/me nods

This is making me think that environment variables should hook into the existing tool for global data: namespaces.

[Namespaces](https://hypertemplates.net/docs/reference/cms/namespaces/)

There is no such concept (yet) of builtin variables, but a user-defined `data.global` namespace would be as easy as dropping a YAML or JSON file in the data directory.

Perhaps environment variables should use a prefix like `HT_` to avoid collisions with other tools, then support some naming convention that would allow for overriding. For example, a `data.global.lang` property could be overwritten with the `HT_data_global_lang` environment variable.

What do you think?

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [June 21, 2025, 12:06am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/13 "2025-06-21T00:06:27Z")

</div>

That’s it.

Also, try to envision and normalize the defaults for all common build flags. I’ll start:

```auto
data.global.lang = "en";
data.global.version = "1";
data.global.direction = "ltr";
data.global.theme = "default";
data.global.stage = "production";
data.global.branch = "main";
data.global.meta.version = "0.14.2"; // dynamic by hyperctl
data.global.meta.os = "windows"; // dynamic by hyperctl
data.global.meta.build.date = "2025-06-21"; // dynamic by hyperctl

```

…

add as many as you can think of.

Then, document them all, thus giving ideas to users what they can easily override to cater for all use cases.

Done.

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [July 2, 2025, 4:46pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/14 "2025-07-02T16:46:58Z")

</div>

Hmm, did I say something wrong?

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [July 3, 2025, 4:34am UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/15 "2025-07-03T04:34:24Z")

</div>

Nope! Your reply made so much sense that I just got to work. Sorry for the radio silence. 😊 I actually just got environment variable-based template data hooked up yesterday and will likely cut a new 0.17.0 release tomorrow. I had a few other changes in the pipeline that I needed to finish up and release first, and those are available now (a 0.14.3 bugfix release, and 0.15.0 and 0.16.0 new feature releases):

> **[Downloads](https://hypertemplates.net/downloads/)**
>
> The pure-HTML templating system for the modern web.

I’ll update again soon when the `env.` namespace is ready. 😊

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [July 3, 2025, 3:18pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/16 "2025-07-03T15:18:11Z")

</div>

That’s great news, thank you.

Looking forward to testing the new release.

By the way, thinking some more about it and looking at my various projects’ tree structures, I think the better default for `data.global.version` would be “v1” instead of just “1”. Usually in paths, the version is designated with a prefix “v”.  
All these defaults will need to live hard-coded in the hyperctl itself and once people start using it left and right, there will be room for changes anymore, so better to think twice about each and every one of them.

I also realized that I have no way of following the news/logs about the HyperTemplates project development. Usually on Github I would just click on Watch and be always notified when there is something new.

Thanks.

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [July 3, 2025, 4:31pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/17 "2025-07-03T16:31:37Z")

</div>

Yeah I intend to use these forums for that. I created an [Announcements](https://hypertexting.community/c/the-latest-product-releases-and-other-announcements-from-the-team-behind-hypertemplates/5) category, and a [Releases](https://hypertexting.community/c/the-latest-product-releases-and-other-announcements-from-the-team-behind-hypertemplates/releases/14) subcategory for that. I believe new users are auto-subscribed to these categories. I just need to start posting to them. 😊

EDIT: I just added the 0.14.3, 0.15.0, and 0.16.0 release topics with a little more detailed changelog than the snippet on the downloads page.

EDIT: aaaaand I just cut a 0.16.1 release, which clears the path for the 0.17.0 release. I’m trying to maintain good semver release hygiene such that .0 releases are only for new features and changes, so bugfixes should be released in .x patch versions.

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [July 3, 2025, 6:24pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/18 "2025-07-03T18:24:25Z")

</div>

> [@AtmanActive](#):
>
> By the way, thinking some more about it and looking at my various projects’ tree structures, I think the better default for `data.global.version` would be “v1” instead of just “1”. Usually in paths, the version is designated with a prefix “v”.

So it occurs to me that environment variables as I’m approaching them might not address this use case. The [HyperTemplates CMS](https://hypertemplates.net/docs/reference/cms/) uses the [directory structure](https://hypertemplates.net/docs/reference/cms/page/#directory-structure) of content files for generating page paths (see [Pages](https://hypertemplates.net/docs/reference/cms/page/) and [`page.path`](https://hypertemplates.net/docs/reference/cms/page/#page-path) for more information). This approach is very similar to [Hugo page bundles](https://gohugo.io/content-management/page-bundles/). There is currently no support for programatic “rewrites” of page paths. I’m not opposed to enabling rewrites, but I do like the simplicity of a 1:1 mapping of directories-with-page-index-files to generated pages.

In a previous life I have maintained documentation websites for open source software projects in which we used versioned paths for new releases; for example: `/docs/v1/api/overview/` versus `/docs/v2/api/overview/`. These documentation websites were built on static site generators like [Middleman](https://middlemanapp.com) (wayyyyy back in the day) and [Hugo](https://gohugo.io), and at one point even a custom [Express](https://expressjs.com) web app that was more or less backed by files on disk. No matter which tooling we used, we almost always followed the same workflow of copying the current version content into a new version _directory_, then updating the new version content with any changes. Then we would just symlink a “latest” directory and the static site generators were none the wiser. Is that a different approach than you would take?

In version 0.17.0 I will be adding two new [template data sources](https://hypertemplates.net/docs/reference/core/data/#template-data-sources): build data and environment data. Build data is automatically provided and only includes two properties so far: a `build.id` and a `build.date`. But environment data will allow you construct complex [template data objects](https://hypertemplates.net/docs/reference/core/data/#template-data-object) from environment variables.

**Example**

Given the following environment variables:

```auto
export HT_globals_foo="bar"
export HT_globals_bar="baz"
export HT_globals_lang="en"
export HT_globals_meta_version="v1"

```

HyperTemplates would have access to the following template data with an `env.` prefix, so `env.globals.foo` (`bar`) and `env.globals.meta.version` (`v1`), etc…

```javascript
{
  env: {
    globals: {
      foo: "bar",
      bar: "baz",
      meta: {
        version: "v1"
      }
    }
  }
}

```

Instead of letting environment variable template data overwrite `site.` or `data.` properties, they can be added with a higher priority to templating attributes. For example:

```html
<a href='/docs/latest/' ht-content='env.globals.meta.version,site.version'></a>

```

In this example `ht-content` will use `env.globals.meta.version` if it is available, or `site.version`. I like this _explicit_ approach where it is easy to find all the uses of environment variables in templates over an _implicit_ approach where environment variables could overwrite a `site.` or `data.` property.

Does this make sense? And am I missing anything RE: what you’d imagine using environment variables for?

---

<div class="post-metadata">

**Author:** ![AtmanActive](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/atmanactive/32/55_2.png) [@AtmanActive](https://hypertexting.community/u/AtmanActive)\
**Post date:** [July 3, 2025, 8:17pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/19 "2025-07-03T20:17:43Z")

</div>

Yeah, that’s great, I like it!

> [@calebhailey.com](#):
>
> `env.globals.meta.version,site.version`

In this case. definitely no need for hard-coded defaults.  
The defaults are in the site.json and can be overridden using ENV.  
Great!

But, this approach where a comma means || is very new to me. I’m kind of used to comma being a series of sorts. It’s not that I have anything against this, I just think that it needs to be documented and explained to death in many, many examples so that people can grasp (and memorize!) the concept. Otherwise, I’m all for it.  
On the other hand, If you are able to change comma `,` for OR `||` in your parser, in this case, that would make it even better/easier.

To answer your question about v1/v2: yes, that’s exactly what I’m on about. Keeping the tree of the old version always allows one to go back and dig up something of value there. Same thing with Git branches. As long as we can ad-hoc steer hyperctl to build version X or branch Y - we’re golden.

Looking forward!

---

<div class="post-metadata">

**Author:** ![calebhailey.com](https://yyz2.discourse-cdn.com/flex036/user_avatar/hypertexting.community/calebhailey.com/32/18_2.png) [@calebhailey.com](https://hypertexting.community/u/calebhailey.com)\
**Post date:** [July 3, 2025, 9:47pm UTC](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61/20 "2025-07-03T21:47:02Z")

</div>

> [@AtmanActive](#):
>
> As long as we can ad-hoc steer hyperctl to build version X or branch Y - we’re golden.

Aha! This was the piece I was missing. This is a little different than the examples I shared in that the versions were a subpath (e.g. `content/docs/v1/` and `content/docs/v2`), so we were always building every version of the docs). If I’m following correctly, what you want is more like `content/v1/docs/` and `content/v2/docs/`, yes? You want to version the entire content tree.

In HyperTemplates this is configurable in `site.yaml` or `site.json` via the [`site.config.content_dir`](https://hypertemplates.net/docs/reference/cms/website/#site-config) property. You can basically specify where the content “root” is. This could be updated to `content/v1` or `content/v2`, etc. And [`hyperctl build`](https://hypertemplates.net/docs/reference/cli/commands/build/) further supports a `--config` flag for managing which configuration file to use, so you could experiment with multiple build configurations in this way. But managing multiple site configuration files for anything more than an experiment feels messy.

I definitely don’t want to use the `HT_*` environment variables for overwriting configuration and template data (as I outlined above). I like keeping `HT_*` for template data only. But I could add a `hyperctl build --contentdir` flag with its own environment variable (e.g. `HYPER_CONTENT_DIR`) for managing this on a per-build basis, then you could easily build completely different (new/old) versions of a site without any code changes.

I can add this in 0.17.0 no problem. 👍

[Next page](https://hypertexting.community/t/does-ht-include-allow-for-recursion/61.md?page=2)
