N1 Nex1on

Your own theme: folder, theme.json, templates and packing

What a theme consists of, which files you can replace, how to edit them in the panel and how to pack a theme as an archive; a working example.

Updated 20.10.2026

A theme is a folder in themes/: a description, styles and, if needed, your own page templates. You do not have to write PHP for a theme: templates are written with the engine's ready-made tags, and everything else comes from the shared markup. A theme with no templates at all is still a full theme: it only recolours and rearranges the styles.

What goes in the folder

Code
themes/my-theme/
├── theme.json
├── assets/
│   ├── css/theme.css
│   └── screenshot.png
├── views/
│   ├── layouts/main.tpl.html
│   ├── errors/404.tpl.html
│   └── news/index.tpl.html
└── locales/
  • theme.json — description and configurable values (required).
  • assets/css/theme.css — theme styles, loaded on every page.
  • assets/screenshot.png — image for the theme card (optional).
  • views/ — your own page templates (optional): the site frame layouts/main.tpl.html, the “not found” page errors/404.tpl.html, the news list news/index.tpl.html and others.
  • locales/ — the theme's own words (optional): en.json, ru.json and so on.

The folder name is lowercase Latin letters, digits, hyphen and underscore, starting with a letter.

A minimal example

A theme of three files: a description, styles and your own “not found” page. The site draws everything else with the engine's shared markup.

themes/my-theme/theme.jsonJSON
{
    "name": "my-theme",
    "version": "1.0.0",
    "title": {"en": "My theme", "ru": "Моя тема", "uk": "Моя тема", "no": "Mitt tema", "pl": "Mój motyw", "sv": "Mitt tema", "lt": "Mano tema"},
    "description": {
        "en": "A light theme with one green accent.",
        "ru": "Светлая тема с одним зелёным акцентом.",
        "uk": "Світла тема з одним зеленим акцентом.",
        "no": "Et lyst tema med én grønn aksent.",
        "pl": "Jasny motyw z jednym zielonym akcentem.",
        "sv": "Ett ljust tema med en grön accent.",
        "lt": "Šviesi tema su vienu žaliu akcentu."
    },
    "author": "Your name",
    "engine": ">=0.9.9",
    "variables": {
        "color_accent": {
            "type": "color",
            "default": "#1a7f5a",
            "label": {"en": "Accent colour", "ru": "Основной цвет", "uk": "Основний колір", "no": "Hovedfarge", "pl": "Kolor główny", "sv": "Huvudfärg", "lt": "Pagrindinė spalva"}
        }
    }
}
themes/my-theme/assets/css/theme.cssCSS
:root {
    --color-accent: #1a7f5a;
}

body {
    border-top: 4px solid var(--color-accent);
}

h1,
h2 {
    color: var(--color-accent);
}
themes/my-theme/views/errors/404.tpl.htmlHTML
<section class="error error--404">
  <p class="error__code">{status}</p>
  <h1>{message}</h1>
  <div class="error__find">{search}</div>
  <p><a href="{home}">← {site_name}</a></p>
</section>

You do not need to write the third file from scratch. Create the theme and ask the engine for a template starter:

Bash
php nex1on theme:files my-theme
php nex1on theme:file my-theme errors/404

The first command prints the list of all pages the theme can replace and shows which of them are already yours. The second creates the file views/errors/404.tpl.html from the starter: edit it and the page picks the file up at once.

Then you can turn the theme on: “Design → Themes”, the “Make active” button on the “My theme” card (or php nex1on theme:use my-theme). Open any address that does not exist: there is a green stripe at the top and the heading is green.

theme.json: fields

FieldWhat it is
namerequired, matches the folder name
versionrequired: "1.0.0"
title, descriptionname and description per language; if a language is missing, English is used
author, enginethe author and the engine versions the theme works with: ">=0.9.9"
screenshotpath to the picture for the card: "assets/screenshot.png"
variablesvalues the owner changes under “Design” without editing files: colours, fonts, sizes, choice lists
regionsplaces for module pieces (side column, footer…) that are filled in later in the panel: a key and a name in several languages

Each variable has a type (color, size, text, choice), a default value, a label in several languages and, optionally, a hint. A choice also gets options. The name color_accent becomes the CSS variable --color-accent (underscore becomes hyphen).

Important. A value the owner has not changed is not printed on the page by the engine: it assumes the theme supplies it. So for each variable of your own, write the default value in theme.css in the :root block, as in the example. Otherwise, until anything is changed, var(--color-accent) is empty and the browser drops the whole rule.

Page templates

Each template is a file views/<folder>/<name>.tpl.html: plain HTML with tags in curly braces ({site_name}, {menu}, {content}) and blocks ([each:menu]…[/each], [if:user.logged]…[/if]). Which template is responsible for which page is shown by theme:files:

FileWhat it is responsible for
views/layouts/main.tpl.htmlthe frame of all pages: header, menu, the content place {content}, footer
views/partials/header, footer, sidebar, cardparts of the frame and the entry card
views/news/index, showthe news list and a single news item
views/pages/showan ordinary page
views/auth/login, register, profile…sign-in, registration, profile
views/errors/404, 403, 500, 503error pages and the “site under maintenance” page
views/searchsearch results
views/forum/…, shop/…, downloads/…module pages: forum, shop, downloads and so on (the full list is given by theme:files)

If your theme has no file, the engine uses its own ready-made page, so you can replace templates one at a time. If the tag file is missing or broken (a block is not closed), the standard view works and the site stays up. Tags and page examples are in the articles Theme on tags and The site’s main template on tags; for module pages, see “Views on tags”.

Editing in the panel

Templates can be edited without files too: “Design → Theme code” (the theme editor). It is off by default: only the site owner can turn it on, with a repeated password. While it is off, no theme file is changed from the panel. In the editor your theme is the ready-made theme plus only the files you changed, so updates of the ready-made theme keep reaching you. The editor checks a template before saving, shows a preview, and the previous version of a file can be restored. Files created in the panel live in the theme folder, so such a theme can be packed afterwards.

The theme's words

If templates need labels, do not write them straight into the HTML: put them in the theme's locales/<code>.json and use them by key. Files are per language, as in a module; if a language is missing, English is used. Labels inside the engine's ready-made tags (member menu, sign-in, search, language choice) are already translated into all seven languages, so a theme that uses only them works in any language without translations of its own.

What a theme must not contain

  • PHP files: in a theme without a Nex1on signature the installer rejects them, and tag-based templates need no PHP.
  • The tags form, script and style and event handlers in the markup: only the engine draws forms, scripts and protection keys.
  • Files of types other than php, json, md, txt, html, xml, csv, css, js, png, jpg, gif, webp, ico, woff, woff2. svg images are accepted only in an archive signed by Nex1on; in your own theme use png or webp.

Packing

Bash
php nex1on theme:pack my-theme

The command builds the archive my-theme-1.0.0.zip (the name carries the version from theme.json) and prints its path: by default the folder nex1on-moduli/zip two levels above the site folder; you can change it with the key app.release_directory in config/local.php. The archive is unsigned: this is how you install your own themes. How to put it on a site is in the article “Installing your own add-on”. Before packing, raise version if you are updating a theme that is already installed.

Was this article helpful?
On this page