PVR
GitHub
Dev customizing

Customizing & Extending

Theme the delivered CSS, rebrand the kit, add a new page or widget, and enable dark mode.

4 min read
Updated June 20, 2026

You extend the kit by editing the delivered files and adding your own overrides — there is no build step to run. This guide covers the four most common tasks: theming, rebranding, adding a page, and adding a widget/component.

Theming via an override stylesheet

Don't edit assets/css/style.css directly — it's a single concatenated bundle and your edits would be hard to maintain. Instead, add your own stylesheet after it and override what you need (your rules win because they load later):

<link id="stylesheet" href="assets/css/style.css" media="screen" rel="stylesheet">
<link href="assets/css/your-overrides.css" rel="stylesheet">   <!-- your customizations -->
/* your-overrides.css */
:root { --app-width-lhs: 18rem; }          /* widen the sidebar via the theme variable */
.panel-card .card-title { font-weight: 700; }

The stylesheet's structure, the layout/theme CSS custom properties (--app-width-lhs, --app-head-height, …), the pale colour palette and the badge classes are all documented in CSS System — refer there for the variable and class names rather than redefining them here. Widgets and badges use only that pale palette; keeping to it keeps new screens visually consistent (see Widgets).

Changing the logo, brand and colours

To changeWhere
LogoReplace the files in assets/img/logo/ (keep the same file names so every page picks them up), or edit the <a class="navbar-brand">/logo <img> in the header markup.
FaviconReplace assets/img/favicon/favicon-32x32.png (referenced from each page's <head>).
Brand / accent coloursOverride the relevant CSS custom properties and palette classes in your override stylesheet — see CSS System.
FontsThe pages link Google Fonts in the <head>; swap those <link> tags for your own font.

Because the header and sidebar markup is identical on every page, change them in one page, then copy the updated block to the others (or to your page template).

Recipe: add a new page

The fastest, most reliable approach is to copy the existing page closest to what you need, then change its parts. To add, say, a new master list page:

  1. Copy a similar page — e.g. roleMaster.htmlmyMaster.html.
  2. Edit the content inside .pageWrapper only; leave the header, sidebar and footer intact.
  3. Update the page header: the <h5> title and the .breadcrumb items in .page-header.
  4. Set the active sidebar item: app.js activates the sidebar entry whose link matches the current file name, so just make sure your page is linked from the sidebar (copy a menu entry in the same section and point its href at myMaster.html).
  5. Wire data-i18n keys: add data-i18n="myMaster.someKey" to your text, create assets/locales/en/myMaster.json with those keys, and add myMaster to assets/locales/en/manifest.json. Full rules in Internationalization.
  6. Add a page script: create assets/js/pages/<feature>/myMaster.js, and update the bottom <script> include in myMaster.html to point at it. Build the DataTable there the way the existing page scripts do (see Tables and JavaScript Helpers).
  7. Add an API endpoint: add an entry to API_CONFIG.endpoints in app.js and read it with API_CONFIG.getUrl(...) from your page script. See Data & API Integration.

A minimal page script skeleton:

"use strict";
var myMaster = {
    init: function () {
        $('#initDataTable').DataTable({
            dom: app.datatables.getDom(),
            ajax: {
                url: API_CONFIG.getUrl(API_CONFIG.endpoints.MyMaster.getMyMaster),
                dataSrc: "data"
            },
            columns: [ { data: "name" }, { data: "status" } ]
        });
    }
};
$(document).ready(function () { myMaster.init(); });

Adding a widget or component

You don't build dashboard widgets from scratch — copy a ready-made one:

  1. Open widgets.html, find the card you want, and copy its markup into your page's content area (inside a row/column).
  2. Replace the demo values, icon and labels with your own, or wire it to live data.
  3. If the widget renders a chart or uses live data, also copy its matching <script> include from the bottom of widgets.html.

The full widget gallery and reuse steps are in Widgets; buttons, badges, alerts, modals and other building blocks are catalogued in Components. All of them are plain Bootstrap 5 plus the kit's classes, already styled by style.css, so they work anywhere with no extra setup.

Enabling and customizing dark mode

Dark mode ships built-in and needs no setup. app.js reads the saved preference from localStorage (key theme) and sets data-theme="dark" on the <html> element; the header's #themeToggle button flips it and persists the choice:

// what app.js does — you don't need to write this
document.documentElement.setAttribute('data-theme', 'dark');  // or 'light'
localStorage.setItem('theme', 'dark');

To default the kit to dark, set the preference once (e.g. before app.js loads, or from your own script): localStorage.setItem('theme', 'dark').

To tweak dark-mode colours, add rules scoped to the data-theme="dark" selector in your override stylesheet, reusing the kit's dark-theme CSS variables rather than introducing new hex colours:

/* your-overrides.css */
[data-theme="dark"] .panel-card { background: var(--card-bg); }
[data-theme="dark"] .my-custom-block { color: var(--text-primary); }

For any new markup you add, prefer the kit's theme variables (--card-bg, --panel-bg, --input-bg, --text-primary, --border-primary, …) over fixed colours so your additions follow the theme automatically. See CSS System for the variables.

Where to go next

Was this page helpful?