How I created my first APEX Template Component

Creating apps built with โค๏ธ using Oracle APEX. PL/SQL dev. Exploring the AI and ML world. Keen on front-end, visual arts and new technologies. Love travel, sports, photography.
Search for a command to run...

Creating apps built with โค๏ธ using Oracle APEX. PL/SQL dev. Exploring the AI and ML world. Keen on front-end, visual arts and new technologies. Love travel, sports, photography.
Very interesting article, but I wonder where I should put this code:
-- Plamen Mushkov (51')|Zlatan Ibrahimovic (70') select LISTAGG(scorer, '|') WITHIN GROUP (ORDER BY goal_time asc) home_team_scorers from games group by game_id, team_id
Impressions from APEX Alpe Adria 2026

The Use Case Oracle APEX has a special template for Dialog Pages, called Drawer. This template is also available for any Region on you Page (this time called Inline Drawer). ๐ก A Drawer is an overlay

The Use case (and the issue) What you see on this screenshot is a pretty common requirement in an APEX application - A form, where you have some text item or dropdown menu, followed by a button or som

The power of Claude Code - offline, free, secure

Using a REST Media Resource as an image source

You know how you always put a big list of fancy things you want to explore right after attending an Oracle APEX conference? I am not an exception and my list is rather big I must admit. After attending Apex Alpe Adria in Zagreb back in April and listening to Tim Kimberl, one topic topped my list. And it did it again after KScope23 in Aurora back in June.

Yes, Template Components are in my opinion something that puts APEX on another level - but why?
First of all, it allows developers to create reusable components. So that they can be used on multiple pages in multiple applications and by multiple developers - while preserving their style consistently without much effort.
One of their main features is to allow the use of Template Directives. They have been available in some APEX regions for a while, as the list of supported regions grows with every version of APEX. I will share a link to what Template Directives are at the end of this article. But in short - they allow developers to use conditional logic with their HTML, moving some complexity out of the SQL and PL/SQL code, putting an end to outputting raw HTML strings out of database procedures and functions and thus preventing any vulnerabilities associated with it. Last but not least - making your code look clean and separating business logic and data from UI and presentation logic.
Template Components (and Template Directives in particular) allow nesting. So I can easily reference existing Template Components inside any new components that I am building. This is also valid for the built-in components like Cards, Badges, Avatars, etc.

They can be used as a Single standalone component (or Partial) and as part of Multiple-row Report. This is defined in the Template Component settings - sometimes it makes sense to have your template available in both forms. That's exactly what I selected for my first one.
Having explored some of the possibilities of this new APEX feature, I targeted some existing internal apps that could benefit from transforming Dynamic Content regions into Template Components. But before doing so, I needed a POC to test my skills and use as many of the Template Components as possible.
As a big fan of football, I decided that something in this domain would be best fit for the purpose. So there we go - The BBC component for displaying matchday results and goal scorers. It would be great as a standalone region (Partial) and in a Report (when displaying all the results for a matchday or a week for example). Here's how it looks on the BBC website:

This is perfect for a first APEX Template Component, as it looks fairly simple, can be used in both forms and can benefit from some more complex logic like conditional statements, loops or being part of a nested component.
Inspect the BBC website and get the HTML code that renders a single match result. Here I hit the first rock, because it seems it was created using React and as one can expect, 3 lines of code could turn into 30, full of data attributes and meaningless CSS classes. Take a look at this for example, it is the part that displays the goalscorer for Arsenal against Manchester City - Martinelli (86'):
<ul class="sp-c-fixture__player-action sp-c-fixture__scorers sp-c-fixture__scorers-home gel-brevier gel-1/2""
data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0">
<li data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false">
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.0">Martinelli</span>
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:0">(</span>
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0">
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.0">86'</span>
<span class="gs-u-vh" data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.1">minutes</span>
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.2"></span>
</span>
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:2">)</span>
<span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.2"></span>
</li>
</ul>
Ugly, right? Very ugly, indeed! So I needed to clean it out and only use a much lighter version in my Template Component:
<ul class="sp-c-fixture__player-action sp-c-fixture__scorers sp-c-fixture__scorers-home gel-brevier">
{if ?SHOW_SCORERS/}
{loop "|" HOME_TEAM_SCORERS/}
<li><span>&APEX$ITEM.</span></li>
{endloop/}
{endif/}
</ul>
Here, by the way, we already see some of the cool stuff:
{if ?SHOW_SCORERS/} means that the block will only be displayed if the value is not null or empty. And later on I can control this using an item on my page to toggle between both states - displayed or not.
{loop "|" HOME_TEAM_SCORERS/} will go through the string with home team goal scorers and create a separate <li> element for each of them. As seen, they are divided by a "|". A sample goalscorers string in my region or report should look like this: Plamen Mushkov (51')|Zlatan Ibrahimovic (70')
-- Plamen Mushkov (51')|Zlatan Ibrahimovic (70')
select LISTAGG(scorer, '|')
WITHIN GROUP (ORDER BY goal_time asc) home_team_scorers
from games
group by game_id, team_id
Inspect the BBC website and get the CSS code - it's again a tricky task, as the CSS in this case was not put in a special file, but was generated inline in the HTML of the page. It also had a lot of unnecessary classes, that I had to clean. One last step is that I moved the colours to separate CSS variables, so I can change them in only one place if needed, but above all - to make it possible for edit by the Template Component users some day if I decided to.

Insert placeholders in my HTML Template like so:
{if ?GAME_URL/}
<a class="sp-c-fixture__block-link" href="#GAME_URL#">
{endif/}
<article class="sp-c-fixture">
<div class="sp-c-fixture__wrapper">
...
</div>
</article>
...
{if ?GAME_URL/}
</a>
{endif/}
Checking the details of my Custom Attributes - yes, they are auto-detected and created, based on the placeholders in your HTML template. But you can still add Help text, add Examples or Default Values or change their Datatype.

Before going into the implementation part - do yourself a favour and explore the options you have on the Template Component Plug-ins. Sometimes the only way to learn is to experiment, so do it.
Another advice would be to download and explore the Template Component Plug-ins that are publically available - the Demo app that Tim demonstrated, the Sample app on Template Directives by Jorge, the videos and blogs from Philipp, Jon and Matt (sorry if I'm missing someone) and the plugin section of apex.world, now providing a separate category for Template Components (I told you it's a huge thing, right!).
The Demo that I prepared consists of three elements - a Page Item (toggle) to allow users to hide/show goal scorers, an Application Component Type region (Single) "BBC Results" to display a single game and an Interactive Report with a column of an Application Component Type "BBC Results".
select 'CSKA Sofia' home_team, 3 home_team_score,
'Plamen Mushkov (15'')|Plamen Mushkov (62'')|Plamen Mushkov (70'')' home_team_scorers,
'Levski Sofia' away_team, 1 away_team_score,
'Ricardinho (29'')' away_team_scorers,
'FT' game_state, null game_url,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers
from dual


select 'Arsenal' home_team, 1 home_team_score,
'Manchester City' away_team, 0 away_team_score,
'FT' game_state, null game_url,
'Martinelli (86'')' home_team_scorers,
null away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual union all
select 'Brighton' home_team, 2 home_team_score,
'Liverpool' away_team, 2 away_team_score,
'FT' game_state, '#' game_url,
'Adingra (20'')|Dunk (78'')' home_team_scorers,
'Salah (40'', 45''+1 pen)' away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual union all
select 'West Ham' home_team, 2 home_team_score,
'Newcastle' away_team, 2 away_team_score,
'FT' game_state, '#' game_url,
'Soucek (8'')|Kudus (89'')' home_team_scorers,
'Isak (57'', 62'')' away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual


You can see the final Demo here:
https://apex.oracle.com/pls/apex/r/gamma_dev/demo/bbc-results
Thanks to the efforts of the APEX Development team, as well as the awesome community we have, it's very easy to get started with Template Components. Here are the resources I would recommend you to get started with:
๐ http://timplating.com/ - a collection of Demo apps, built by Tim Kimberl, a member of the APEX Development team. I recommend you explore the Metric Card Demo and UT 23.1 Template Components apps to see what a good template component looks like.
๐ https://rimblas.com/blog/presentations/ and Template Directives Demo App - an awesome Demo application by Jorge Rimblas, with sample code included, showcasing conditional Template Directives (a core part of the Template Components), loops, etc.
๐ https://mattmulvaney.hashnode.dev/the-thought-process-involved-in-the-creation-of-apex-template-components - a Step-by-step guide on creating a Template Components by Matt Mulvaney I guarantee you will have a working component in less than an hour if you follow that guide along.
๐ https://hartenfeller.dev/blog/oracle-apex-template-components-introduction - another Step-by-step guide by Philipp Hartenfeller on creating Template Components, also explaining Actions (another good use case for Template components).
๐ https://blog.cloudnueva.com/leveraging-apex-theme-components - A blog post by Jon Dixon, which explains the built-in Template (or Theme) Components like Badges, Avatars, Comments, etc. In another blog post - https://blog.cloudnueva.com/apex-template-directives - he explains some of the features that Template Directives can offer.
๐ Oracle's Documentation on Template Directives: https://docs.oracle.com/en/database/oracle/apex/23.1/htmdb/using-template-directives.html
๐ http://apex.world/ - the Plug-in section of apex.world where you can find a number of community built Template Components, free to use and learn from. Just filter on Plug-in type and pick Template Components.
Join the Template Component Plugin Challenge - deadline October 31st.
Read more about it here: https://apex.mt-itsolutions.com/ords/r/portal/apex/template-component-challenge
Don't forget to follow me on Hashnode, Wordpress and social media. I will soon publish my Template Component to apex.world so you can download it and use it inside your applications too.