# Better know a framework #18: what processContent is and what it is used for

**URL:** <https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785>\
**Category:** Framework Knowledge\
**Created:** [October 20, 2018, 1:19am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785 "2018-10-20T01:19:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [October 20, 2018, 1:19am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/1 "2018-10-20T01:19:11Z")

</div>

Abbreviation:

- CE: custom element
- CA: custom attribute

Terminologies:

- Consumer template:  
A consumer template of a CE/CA is a template where a CE/CA is used). For example, the following is a consumer template of CE `name-tag`:

```auto
<!-- app.html -->
<template>
  First Name: <input value.bind="firstName" />
  Last Name: <input value.bind="lastName" />

  <name-tag name="${firstName} ${lastName}"></name-tag>
</template>

```

* * *

### How it looks like

Sometimes, you may come across a tutorial or a code block of Aurelia that looks like this

```auto
@processContent(...)
export class Example {
}

```

Notice decorator usage `@processContent`, it defines some metadata for the class (CE/CA) of how to process the content in consumer template. So what is / are the **content**?

- For CE: Content is the children elements / nodes of the CE element in consumer template. For example, suppose we have CE named `panel`, in the following template:

```auto
<template>
  <panel>
    <header></header>
    <div class="panel-body"></div>
  </panel>
</template>

```

**content** will be all child nodes of `<panel>` element
- For CA: Content is the children elements / nodes of the element that the CA resides. For example, suppose we have CA named `selectable`, in the following template:

```auto
<template>
  <div id="selectable-div" selectable>
    <div repeat.for="item of selection">${item}</div>
  </div>
</template>

```

**conent** will be all child nodes of `<div/>` with id `selectable-div`

### What is it for

`@processContent` is used for ensuring the content of a target element to a more suitable template form.  
For example, a `<ux-select/>` CE should only accept 2 CE in its content: `<ux-option/>` and `<ux-optgroup/>`. However, the user of `<ux-select/>` may accidentally supplied a `<div/>`, which will cause the widget to function incorrectly or even break:

```auto
<template>
  <ux-select>
    <ux-option>...</ux-option>
    <div>oops gonna break</div>
  </ux-select>
</template>

```

With `@processContent`, author of `<ux-select/>` can define a function that helps remove all invalid child nodes before progressing further, to either issue a warning so either developers can fix the template, or prevent the widget from breaking. **`processContent`** function takes 4 parameters:

1. `compiler`: the view compiler instance being used for compilation
2. `resources`: the view resources instance being used for resources lookup during compilation
3. `node`: the element where the content of it needs to be processed
4. `instruction`: the behavior instruction instance that is associated with either CE/CA in the consumer template

Back to our example above with the troublesome `<div/>`, we can use **`@processContent`** to remove it:

```auto
import { ViewCompiler, ViewResources, BehaviorInstruction, processContent } from 'aurelia-framework';

@processContent((
    compiler: ViewCompiler,
    resources: ViewResources,
    node: Element,
    instruction: BehaviorInstruction
  ): boolean => {
    // remove every child element that is not either `<ux-option/>` or `<ux-optgroup/>`
    // ... real code to remove ... ex. node.removeChild(node.lastElementChild)
    return true;
  }
)
export class UxSelect {

}

```

Notice the `return true` at the end of the function, by returning true, we are signaling the compiler to continue the compilation process for the content, as it was paused when it hit a CE or an element with CA on it. Some examples of advanced usage:

- combining **`@processContent`** with `return false` to extract the content and compile into a factory, marked with an ID to use later. Everyone can go pretty clever & creative with this.
- combining **`@processContent`** with `replace-part` & `<template/>` to target `replaceable` template in CE

### Live example

- official `<ux-select/>` element: [https://github.com/aurelia/ux/blob/master/packages/select/src/ux-select.ts#L505-L526](https://github.com/aurelia/ux/blob/master/packages/select/src/ux-select.ts#L505-L526)
- … to be updated

* * *

If you have an example of **`@processContent`** you would like to share to help folks better understand it, please leave a link and I’ll incorporate it in live example section

---

<div class="post-metadata">

**Author:** ![fkleuver](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/fkleuver/32/994_2.png) [@fkleuver](https://discourse.aurelia.io/u/fkleuver)\
**Post date:** [October 20, 2018, 1:50am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/2 "2018-10-20T01:50:31Z")

</div>

In layman’s terms, I like to think of `@processContent` as an interceptor. You can do some stuff to the template before the `ViewCompiler` starts working on it (with the option of telling the `ViewCompiler` not to touch it at all).

The ViewCompiler analyzes the attributes, element names and raw text in the template to decide where it needs to put custom attributes, custom elements or interpolations.

`@processContent` has 2 use cases that I myself find interesting and occasionally useful:

1. Pass it some reusable function with some app-wide common replacements in it, for example adding the `& t` bindingBehavior to all interpolations (if you’re using i18n), or a boolean valueConverter to all `input type="checkbox" value.bind` expressions. With a `TreeWalker`you can easily make your views more maintainable by moving common bloat to the function.
2. Implement your own mini templating syntax without having to do any complex compiling yourself. Perhaps you prefer a certain subset of the angular, or knockout data-\* or vue syntax, or you just want to easily migrate something. With `@processContent` you can make the replacements without having to implement the compiler

---

<div class="post-metadata">

**Author:** ![davismj](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/davismj/32/267_2.png) [@davismj](https://discourse.aurelia.io/u/davismj)\
**Post date:** [October 20, 2018, 3:47am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/3 "2018-10-20T03:47:28Z")

</div>

I’ve used `@processContent` extensively to do the heavy lifting for a widely used component library. An excellent example is a tabs component. What you might want to write is something like:

```auto
<tabs>
  <tab>
    <tab-header>
      Tab 1
    </tab-header>
    <tab-body>
      This is tab 1
    </tab-body>
  </tab>
</tabs>

```

But what you need rendered to look and behave correctly is something like this:

```auto
<div class="tab-headers">
  <span class="tab-header">Tab 1</span>
</div>
<div class="tabs">
  <div class="tab">
    This is Tab 1
  </div>
</div>

```

This is impossible to do with custom elements alone, as it requires a full rearrangement of components. This is where `@processContent(_, _, element: HTMLElement, _)` comes in. You can read, add, remove, and replace all elements in the custom element, and `return true` to let Aurelia pick up processing when you’re done.

There is an advanced approach that involves creating views and view slots, processing them in the `created()` callback, etc. I’ve found that this is a bit too complicated both to write and to read, so I’ve skipped this approach almost every time.

In vNext I believe there is already a proposal to make `@processContent` less of a transformation on the class and more of an transformation on the instance, which will allow not only manipulating the DOM elements but also setting variables on the custom element _instance_ according to the incoming element.

---

<div class="post-metadata">

**Author:** ![sean.hunter.aus](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sean.hunter.aus/32/17_2.png) [@sean.hunter.aus](https://discourse.aurelia.io/u/sean.hunter.aus)\
**Post date:** [October 31, 2018, 2:24am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/4 "2018-10-31T02:24:59Z")

</div>

> [@bigopon](#):
>
> [https://github.com/aurelia/ux/blob/master/packages/select/src/ux-select.ts#L505-L526](https://github.com/aurelia/ux/blob/master/packages/select/src/ux-select.ts#L505-L526)

Nice, I really like the proposal for where it sounds like this is going for vnext. Do you have a link to the vnext Github issue for this (if there is one)? I’d be interested in watching this as it shapes up.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [October 31, 2018, 2:41am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/5 "2018-10-31T02:41:17Z")

</div>

There is no specific github issue for this atm, as its shaped is still being discussed. The reason is it should be in some form that can be used for both AOT and JIT scenario, while not losing too much power. of `@processContent` flexible API. If you have any idea, it’d be nice if you open a issue for that.

---

<div class="post-metadata">

**Author:** ![sean.hunter.aus](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sean.hunter.aus/32/17_2.png) [@sean.hunter.aus](https://discourse.aurelia.io/u/sean.hunter.aus)\
**Post date:** [October 31, 2018, 2:46am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/6 "2018-10-31T02:46:02Z")

</div>

Thanks @bigopon will keep an eye out for upcoming updates 👍

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 16, 2019, 9:17am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/7 "2019-01-16T09:17:33Z")

</div>

Is there a way to inject my custom elements in `processContent`? For example, in my Tabs view I have something like below:

```auto
<template class.bind="styles.tabs">
    <require from="my-package/elements/MyControl"></require>
    <slot></slot>
</template>

```

And in my `processContent`, I am doing something like below:

```auto
@processContent(Tabs.processTabs)
export class Tabs {
  public static processTabs(_compiler, _resources, node: HTMLElement, instruction: BehaviorInstruction): boolean {
    ...
    const tabHeader = document.createElement("my-control");
    tabHeader.setAttribute("value", header || ""); // header is a string
    // append tabHeader to node or to one of its children ...
    return true;
  }
}

```

However, the `my-control`s are not processed further; i.e. the elements are present in the DOM, but without further inner contents. It seems that custom elements can be injected using `_resources`, however, I have not found any such example so far. Is there a way to resolve this?

It might be possible that if I use `<require from="my-package/elements/MyControl"></require>` it the view where I use `<tabs/>` element, it will work correctly, but then my custom element is no longer in full control of itself.

---

<div class="post-metadata">

**Author:** ![davismj](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/davismj/32/267_2.png) [@davismj](https://discourse.aurelia.io/u/davismj)\
**Post date:** [January 16, 2019, 9:30am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/8 "2019-01-16T09:30:43Z")

</div>

So actually what happens is Aurelia parses the content first, so when you add new elements it doesn’t know about them. It has already passed the point where it would be looking for new custom elements.

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 16, 2019, 10:53am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/9 "2019-01-16T10:53:13Z")

</div>

Only things help here is to `<require>` the resources in client code or register those as global resources.  
The later is not a problem in my case, as the Tabs control resides a plugin project, where the global resources can be `configure`d. Though this option breaches the principle of keeping the stuffs together that belongs together, it is undoubtedly better than the previous option.

Here are couple of questions though, to make my understanding of this better.

1. Let the Tabs view be as follows.

2. I have tried to add view resources in `processContent` as follows:

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 16, 2019, 11:37am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/10 "2019-01-16T11:37:22Z")

</div>

Furthermore, is there a reason for supporting only boolean return value from `processContent`?If a `Promise<boolean>` return value from that function is supported, can that mitigate the problem of loading the additional resources asynchronously?

Sorry for bombarding with question. This is a the first time, in last 2/3 years, Aurelia is forcing me to go for such architecture/design that can be frowned upon 🙂

---

<div class="post-metadata">

**Author:** ![davismj](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/davismj/32/267_2.png) [@davismj](https://discourse.aurelia.io/u/davismj)\
**Post date:** [January 21, 2019, 3:48am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/11 "2019-01-21T03:48:23Z")

</div>

> However, this didn’t work as well. Is there any way I can register the required elements correctly (so Aurelia can process the custom elements further) during this phase?

Yes, but I never do this so I dunno off the top of my head. @bigopon might know.

> Furthermore, is there a reason for supporting only boolean return value from `processContent` ?If a `Promise<boolean>` return value from that function is supported, can that mitigate the problem of loading the additional resources asynchronously?

Yes, the process content hook was mostly added to _prevent_ Aurelia from processing content, not to manipulate how it processes content so that you could handle your own DOM processing, particularly for jQuery style controls. The idea of manipulating content was more of an afterthought, I think. Since that time we’ve learned that there are better ways to approach 3rd party controls, but process content is the best way to handle manipulating content.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 21, 2019, 6:51am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/12 "2019-01-21T06:51:44Z")

</div>

@Sayan751 From your example code, it should just work. I don’t know exactly what issue you ran into, but I can help if you could share a reproduction, based on this template [https://codesandbox.io/s/wnr6zxv6vl](https://codesandbox.io/s/wnr6zxv6vl)

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 21, 2019, 8:12am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/13 "2019-01-21T08:12:50Z")

</div>

That is promising to hear. I will try to reproduce it in the sandbox.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 21, 2019, 8:26am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/14 "2019-01-21T08:26:43Z")

</div>

Or you can use normal one that represents how you do your app, instead of aurelia-script based one [https://codesandbox.io/s/y41qjr36j](https://codesandbox.io/s/y41qjr36j) . Sorry I forgot to give this option.

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 22, 2019, 6:54pm UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/15 "2019-01-22T18:54:02Z")

</div>

Finally, I got time to reproduce the issue in sandbox.

Without loading additional resources in `processContent`: [https://codesandbox.io/s/r4p7503wro](https://codesandbox.io/s/r4p7503wro)

Attempt to load additional resources in `processContent`: [https://codesandbox.io/s/w25n2mqqk5](https://codesandbox.io/s/w25n2mqqk5)

The former works iff the respective `require` is uncommented in `app.html`. The problem with the second is without `async` `processContent` it shows DI error, which I believe is due to the failed attempt to “enhance” the custom element used in `processContent`. On the other hand, with `async` function, it simply does not wait the function to be completed. Thus, the actual “processing” part of the function is skipped before Aurelia processes the element.

Hope these help.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 22, 2019, 10:19pm UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/16 "2019-01-22T22:19:08Z")

</div>

Thanks.

For both examples, when you append new content to the node being processed, it’s appended to parent/ or consumer template, not the child/custom-element-template. Thus, having `<require from='./MyText'/>` didn’t work as you would expect it to be because the parent doesn’t have any knowledge about it.

For dynamically load `MyText` dependencies, you don’t have to do this, it’s already been loaded by the time the compilation happens, as it’s ensured to load everything before compilation. Example here [https://codesandbox.io/s/0xlx9x2vy0](https://codesandbox.io/s/0xlx9x2vy0)

I think it’s the scope of `MyText` that wasn’t clear that caused the confusion.

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 23, 2019, 5:14am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/17 "2019-01-23T05:14:08Z")

</div>

Thank you for the explanation.

I am trying to sum up to make my understanding better. By the time the `processContent` is called, Aurelia has already compiled the view of that custom element and thus, knows about the view resources required by the element. Therefore it is enough to register the additional custom elements “correctly” (getting the resource from the already compiled stuff, namely `instruction.type.viewFactory.resources`) in `processContent`. Is this correct?

Also as you indicated, a few `private` properties of Aurelia internals are being touched in the process. In that case, maybe it is better to make those properties part of public API, or create public API to expose those in a more developer/consumer friendly manner.

I think `processContent` is one of the most cool features of Aurelia, with next to no documentation. It deserves a section on its own merit, with bit more detailed explanation along with the different use cases for this.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 23, 2019, 5:30am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/18 "2019-01-23T05:30:25Z")

</div>

> I am trying to sum up to make my understanding better. By the time the `processContent` is called, Aurelia has already compiled the view of that custom element and thus, knows about the view resources required by the element. Therefore it is enough to register the additional custom elements “correctly” (getting the resource from the already compiled stuff, namely `instruction.type.viewFactory.resources` ) in `processContent` . Is this correct?

That is correct, as you already noticed.

> Also as you indicated, a few `private` properties of Aurelia internals are being touched in the process. In that case, maybe it is better to make those properties part of public API, or create public API to expose those in a more developer/consumer friendly manner.

As you stated, this is the first time in years of using Aurelia, you ever need it. That kind of justifies it’s current state. For the suggestion, there is no harm making them `public`, though I’d prefer to let @EisenbergEffect give some thoughts on APIs.

> I think `processContent` is one of the most cool features of Aurelia, with next to no documentation. It deserves a section on its own merit, with bit more detailed explanation along with the different use cases for this.

Wish some community members could help the team more here 😄

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [January 23, 2019, 6:47am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/19 "2019-01-23T06:47:34Z")

</div>

> [@bigopon](#):
>
> Wish some community members could help the team more here

I would be happy to help. Need a bit of help on “where to start” 🙂

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [January 23, 2019, 7:00am UTC](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785/20 "2019-01-23T07:00:08Z")

</div>

You can start here [http://github.com/aurelia/documentation](http://github.com/aurelia/documentation). But let’s also ping @EisenbergEffect for more input 😄

[Next page](https://discourse.aurelia.io/t/better-know-a-framework-18-what-processcontent-is-and-what-it-is-used-for/1785.md?page=2)
