Child Template Setup
A child template inherits all layouts, module positions, and
compiled CSS from the jcrafts parent template. It
adds only customer-specific branding — colors, fonts, and optional
component overrides — without duplicating any parent code.
How Joomla Parent/Child Templates Work
The jcrafts template has
<inheritable>1</inheritable> in its
manifest. A child template declares:
<extension type="template" client="site">
<name>jcrafts_customer</name>
<parent>jcrafts</parent>
...
</extension>
Joomla then:
- Serves all PHP files from the parent unless the child provides its own override.
- Loads parent CSS and JS assets automatically.
-
Loads
user.cssfrom the child's media directory (via thetemplate.userasset already defined in the parent'sjoomla.asset.json) — this is where customer branding is applied.
Two levels of customization
| Level | What you change | Build step needed? |
|---|---|---|
| CSS override |
Write user.css directly with CSS custom
property overrides
|
No |
| Token rebuild |
Replace brand.tokens, run Terrazzo + Sass
to regenerate user.css
|
Yes (npm) |
Step-by-Step Repository Setup
Use the Quick Start path below to bootstrap a new repo from the scaffold in under a minute. The Manual Setup section further down explains each file in detail.
Quick Start (scaffold)
-
Create a new Forgejo repo named
tmpl_jcrafts_<customer>and clone it. -
Create
.npmrcin the repo root (required beforenpm installcan reach the private registry):
# .npmrc
@simplysmart-it:registry=https://git.simplysmart-it.de/api/packages/JCrafts/npm/
//git.simplysmart-it.de/api/packages/JCrafts/npm/:_authToken=${NPM_TOKEN}
Set NPM_TOKEN as an environment variable or
Forgejo secret. Never commit a real token.
How to create and set NPM_TOKEN
1. Create a Forgejo access token
In Forgejo:
User Settings → Applications → Access Tokens → Generate
Token. Enable the read:package permission
(read-only is enough for npm install). Copy
the generated value — it is shown only once.
2a. Local development
Add the token to your shell profile (~/.zshrc
or ~/.bashrc). The project's
.npmrc reads it via
$ { NPM_TOKEN} at runtime — the actual token
is never written into any .npmrc file in the
repo:
# Add to ~/.zshrc or ~/.bashrc (not to .npmrc)
export NPM_TOKEN=your_token_here
After saving, reload your shell (source ~/.zshrc) or open a new terminal. Run npm install —
it picks up the token automatically.
2b. Forgejo Actions (CI/CD)
In Forgejo:
Repository → Settings → Actions → Secrets → Add Secret. Name: NPM_TOKEN, Value: the token from
step 1. In your workflow YAML it is available as
$ — the .npmrc reads it
automatically via _authToken=$ { NPM_TOKEN}.
- name: Install dependencies
run: npm install
env:
NPM_TOKEN: $
- Install the parent package and run the init script with your customer slug (lowercase letters and underscores only):
npm install @simplysmart-it/tmpl-jcrafts
npx jcrafts-init acme
The script copies all scaffold files, substitutes
jcrafts_acme /
Acme\Template\JCrafts /
tmpl-jcrafts-acme throughout, and renames the
dotfile templates.
-
Edit
tokens/brand.tokens— swap the color hue references (e.g.{ base.color.blue.*}→ your customer's palette) and update font families. - Build:
npm run build
This generates media/css/user.css. Install both
the parent and child templates in Joomla, activate the child,
and the site uses the customer brand colors.
Manual Setup (reference)
Follow these steps if you want to set up each file by hand or understand what the scaffold contains.
1. Create a new repository
Name it tmpl_jcrafts_<customer> and
initialise it in Forgejo.
2. Configure the npm registry
Create .npmrc in the repo root. The
_authToken line intentionally omits
https::
# .npmrc
@simplysmart-it:registry=https://git.simplysmart-it.de/api/packages/SimplySmart-IT/npm/
//git.simplysmart-it.de/api/packages/SimplySmart-IT/npm/:_authToken=${NPM_TOKEN}
Set NPM_TOKEN as an environment variable or
Forgejo secret — see the
Quick Start section above
for step-by-step instructions. Never commit a real token.
3. Install the parent package
npm install @simplysmart-it/tmpl-jcrafts
4. Copy the brand token starter
mkdir -p tokens
cp node_modules/@simplysmart-it/tmpl-jcrafts/scaffold/tokens/brand.tokens tokens/brand.tokens
Edit tokens/brand.tokens — change the color
references (e.g. { base.color.blue.*} → a
different hue) and font family values to match the customer
brand.
5. Create the source directory structure
mkdir -p src/templates/jcrafts_customer
mkdir -p src/media/templates/site/jcrafts_customer/scss
mkdir -p src/media/templates/site/jcrafts_customer/css
mkdir -p src/media/templates/site/jcrafts_customer/fonts
6. Create user.scss
This file imports the parent's compiled token CSS and adds any additional overrides:
// src/media/templates/site/jcrafts_customer/scss/user.scss
// Import parent token CSS custom properties (compiled by tokens:build step)
@use 'node_modules/@simplysmart-it/tmpl-jcrafts/src/media/templates/site/jcrafts/scss/tokens/abstracts/ds-tokens' as *;
// Custom fonts — run `npm run grab-fonts` first, then uncomment and adapt:
// @use '@simplysmart-it/tmpl-jcrafts/src/media/templates/site/jcrafts/scss/abstracts/fontface' as fontface;
// @layer base {
// @include fontface.font("public-sans", "Public Sans", "normal-400-latin", 400, normal);
// }
// Any additional component overrides go here
7. Add build scripts and config to package.json
The config block drives all script paths — only
the slug in the config needs to change per customer:
{
"config": {
"build": {
"extension": "build/tmp",
"media": "build/tmp/media",
"zipname": "jcrafts_customer"
},
"dev": {
"extension": "src/templates/jcrafts_customer",
"media": "src/media/templates/site/jcrafts_customer"
}
},
"scripts": {
"tokens:build": "BRAND_TOKENS_PATH=./tokens/brand.tokens npx tz build --config node_modules/@simplysmart-it/tmpl-jcrafts/design-system/terrazzo.config.mjs",
"sass:compile": "sass --no-source-map --style=expanded --update --load-path=node_modules ./$npm_package_config_dev_media/scss:./$npm_package_config_build_media/css",
"css:prefix": "postcss --use autoprefixer -b 'defaults' --no-map --replace ./$npm_package_config_build_media/css/*.css",
"css:minify": "cleancss --output ./$npm_package_config_build_media/css/ --batch --batch-suffix \".min\" \"./$npm_package_config_build_media/css/*.css\"",
"compile": "npm run tokens:build && npm run sass:compile && npm run css:prefix && npm run css:minify",
"build:prod": "npm run compile && node build/SetupExtPackage.mjs && cd build/tmp && npm pack"
}
}
7a. Download custom fonts (optional)
If the customer uses Google Fonts other than the parent template's defaults, configure and download them:
-
Create
fonts.jsonat the repo root listing the desired families:
[
{ "family": "Roboto", "weights": [400, 700] }
]
- Run the download script (requires the parent package to be installed):
npm run grab-fonts
Fonts are downloaded to
src/media/templates/site/jcrafts_customer/fonts/
and the script prints the exact
@include fontface.font(…) lines to add to
user.scss.
8. Create templateDetails.xml
Place this file at
src/templates/jcrafts_customer/templateDetails.xml:
<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site">
<name>jcrafts_customer</name>
<version>1.0.0</version>
<parent>jcrafts</parent>
<namespace path="src">Customer\Template\JCrafts</namespace>
<files folder="templates/jcrafts_customer">
<!-- PHP override files go here; leave empty if using no overrides -->
</files>
<media destination="templates/site/jcrafts_customer" folder="media">
<folder>css</folder>
<folder>fonts</folder>
</media>
</extension>
9. Run the build
npm run build:prod
This generates
src/media/templates/site/jcrafts_customer/css/user.css
and packages everything into
build/jcrafts_customer-1.0.0.zip. Install both
the parent template and this child template in Joomla,
activate the child, and the site will use the customer brand
colors.
Previewing Your Brand in the Design System
The parent package includes the full 11ty design system. You can run it locally with your brand tokens applied so you see every component in the customer's colors before touching a Joomla instance.
1. Install the design system dependencies
cd node_modules/@simplysmart-it/tmpl-jcrafts/design-system
npm install
cd -
2. Build tokens with your brand override
BRAND_TOKENS_PATH=$(pwd)/tokens/brand.tokens \
npx --prefix node_modules/@simplysmart-it/tmpl-jcrafts/design-system \
tz build \
--config node_modules/@simplysmart-it/tmpl-jcrafts/design-system/terrazzo.config.mjs
3. Start the design system dev server
npm --prefix node_modules/@simplysmart-it/tmpl-jcrafts/design-system run start
Open localhost:8080 — you'll see the full component library rendered with your customer's primary, secondary, and accent colors.
Tip:
Add a convenience script to your child template's
package.json:
{
"scripts": {
"design-system": "BRAND_TOKENS_PATH=$(pwd)/tokens/brand.tokens npm --prefix node_modules/@simplysmart-it/tmpl-jcrafts/design-system run start"
}
}
Then simply run npm run design-system from the
child template root.
Overriding Individual Components
For structural changes beyond colors and fonts — different button shapes, altered card layout, custom navigation — copy the relevant SCSS file from the parent package and override it in the child template.
SCSS component override
-
Find the component SCSS in
node_modules/@simplysmart-it/tmpl-jcrafts/src/media/templates/site/jcrafts/scss/components/ -
Copy it to
src/media/scss/components/in your child repo -
Import it in
user.scssafter the parent's token import so your rules take precedence
// user.scss
@use 'node_modules/@simplysmart-it/tmpl-jcrafts/src/media/templates/site/jcrafts/scss/tokens/abstracts/ds-tokens' as *;
// Component override: custom button shape
@use 'components/button' as *;
PHP / module template override
To override a Joomla module or component layout, mirror the
path from the parent's html/ folder in the child
template. For example, to override the menu output:
# In the child Joomla template directory:
mkdir -p html/mod_menu
cp /path/to/jcrafts/html/mod_menu/default.php html/mod_menu/default.php
# Edit html/mod_menu/default.php as needed
Joomla's template override system automatically uses the child's file when it exists.
Injecting Custom Components into the Design System
Child templates can add their own components to the design system explorer alongside the parent components. No changes to the parent package are needed — the design system discovers child components at runtime via a symlink.
How it works
Two environment variables control the injection:
| Variable | Required | Default | Purpose |
|---|---|---|---|
CHILD_COMPONENTS_PATH |
Yes | — | Path to the child template's component directory |
CHILD_COMPONENTS_LABEL |
No | _child |
Group name shown in the sidebar; also used as the symlink directory name |
Before each build, the design system creates a symlink
src/_includes/components/<label> pointing
to your component directory. The existing component discovery
globs follow symlinks, so no other config changes are needed.
1. Component file structure
Each component needs at minimum a .config.js (for
the explorer) and a .njk (for the preview). A
.webc file is optional but required if the
component is used as a WebC element.
src/components/
└── MyWidget/
├── my-widget.config.js # required — name, label, variants
├── my-widget.njk # required — preview template
└── my-widget.webc # optional — WebC component definition
2. Minimal .config.js
module.exports = {
name: 'my-widget',
label: 'My Widget',
variants: [
{ name: 'default', label: 'Default' }
]
};
3. Add the script to your child's package.json
Extend the design-system script with the two new
variables:
{
"scripts": {
"design-system": "BRAND_TOKENS_PATH=$(pwd)/tokens/brand.tokens CHILD_COMPONENTS_PATH=$(pwd)/src/components CHILD_COMPONENTS_LABEL=Acme npm --prefix node_modules/@simplysmart-it/tmpl-jcrafts/design-system run start"
}
}
Then run npm run design-system — your components
appear in the sidebar under the label you chose, alongside all
parent components, rendered in your brand colors.
Notes
-
The symlink is created fresh before each build and is not
cleaned up on exit (it is listed in the parent's
.gitignoreso it won't be committed accidentally). -
If you use a custom
CHILD_COMPONENTS_LABELother than_child, add it to your child repo's.gitignoreunder the design-system path:node_modules/@simplysmart-it/tmpl-jcrafts/design-system/src/_includes/components/Acme -
File changes inside
CHILD_COMPONENTS_PATHtrigger live reload duringnpm run start.