Joomla 4 – Cassiopeia Template – a bunch of Tips & Tricks

by Marc Dechèvre



Joomla User Group New Jersey | 2022.01.20

present slides

video (available soon)

1. Resources

“Standing on the shoulders of giants”

The goal of this session is to try and give tips & tricks about Cassiopeia which are not already out there.

But what if it is out there and you missed it?

I always like to gather all the available sources about a topic, be it Custom Fields… or Cassiopeia 🙂

So here is all I am aware of (and please get back to me if I have forgotten some):

2. Reasons to love Cassiopeia

There are many good reasons to stick to the native template Cassiopeia

Of course, you might also have you own (good) reasons to use another template/framework.

But Cassiopeia is clearly an excellent option for Joomla 4 (while for Joomla 3 I have never considered using Protostar to build a website except for testing purposes)

3. Drawbacks of Cassiopeia

The first time I saw the Cassiopeia Template Options I thought “oh nooo, so few Options”.

But actually -as we see in this presentation and in the other resources mentioned- we can easily compensate for that.

At the end of the day, it is even a good thing to have a default Template which is not bloated because it means

4. Tips & tricks around Cassiopeia

4.1. Changing the color set on the whole site

Add the following CSS to /templates/cassiopeia/css/user.css

:root {
  --cassiopeia-color-primary: red;
  --cassiopeia-color-hover: green;
  --cassiopeia-color-link: blue);

4.2. Changing the color set on a given page

Basic example:

.colors1 {
  --website-color-1: #5e2688;
  --cassiopeia-color-primary: var(--website-color-1);

More advanced example allowing to play with transparency (RGBA) because my initial variable is not directly expressed as a color, but as the RGB value (example: 37, 143, 167):

.colors1 {
  --website-color-primary: 37, 143, 167;
  --website-color-hover: 242, 48, 48;
  --cassiopeia-color-primary: rgba(var(--website-color-primary),0.5);
  --cassiopeia-color-hover: rgb(var(--website-color-hover));
  --cassiopeia-color-link: rgb(var(--website-color-primary));

4.3. Changing the Layout ie moving Positions around

If you inspect a website using Cassiopeia you will see the following CSS:

@supports (display: grid) {
    .site-grid {
          ". banner banner banner banner ."
          ". top-a top-a top-a top-a ."
          ". top-b top-b top-b top-b ."
          ". comp comp comp comp ."
          ". side-r side-r side-r side-r ."
          ". side-l side-l side-l side-l ."
          ". bot-a bot-a bot-a bot-a ."
          ". bot-b bot-b bot-b bot-b .";
    @media (min-width: 992px) {
        .site-grid {
              ". banner banner banner banner ."
              ". top-a top-a top-a top-a ."
              ". top-b top-b top-b top-b ."
              ". side-l comp comp side-r ."
              ". bot-a bot-a bot-a bot-a ."
              ". bot-b bot-b bot-b bot-b ."

This is CSS Grid. It is very easy and very visual as you can see. If you know little or nothing about CSS Grid, it is definitely worth learning the basic for example on

So if you would like to adapt the Layout and have for instance on desktop view

all it takes is to add the following CSS to /templates/cassiopeia/css/user.css

@supports (display: grid) {
    @media (min-width: 992px) {
        .site-grid {
              ". top-a top-a top-a top-a ."
              ". top-b top-b top-b top-b ."
              ". side-l comp comp side-r ."
              ". bot-a bot-a bot-b bot-b ."
              ". banner banner banner banner ."

With other words, the nice thing about having a template based on CSS Grid is that you can change the Layout just with a few lnes of CSS, without having to edit/override/fork any PHP file.

Create the appropriate new Module

See the result on the front-end

Customize those two Language Strings

If you want to have both Texts on the same Row on large screens (which is nicer I think) simply add the following CSS to /templates/cassiopeia/css/user.css

footer div.mod-footer {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
@media (min-width: 768px) {
  footer div.mod-footer {
    flex-direction: row;

This is not specific to Cassiopeia: that Footer was already there since the Mambo days I hear. But since Cassiopeia does not have tens/hundreds of Options, this is a very elegant way to get a nice customized footer.

4.5. Adding an icon to a Menu Item – requires J4.1

Txs to Christiane Maier-Stadtherr for this new feature added in J4.1

Note: this does not impose Font Awesome: it will work with any icon font the template wants to use (obviously the template would have to support an icon font for it to work)

More information on

In Joomla 4.0 you could reach a similar result in a manual way

ul.mod-menu {
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    content: "";
    margin-right: 4px;
    display: inline-block;
    width: 1.25em !important;

Besides this, you could also use only the icons mapped here as Font Awesome classes without further ado:

4.6. Dark Mode

There are many good reasons to have Dark Mode on your website.

Thanks to the free plugin Dark Magic by Nicholas Dionysopoulos you can very easily enable and customize Dark Mode

Note: at the moment the on only mentions Joomla 3. But actually the plugin has two versions, one for J3 and one for J4. Simply click on Releases on the right column

Of course, especially for the front-end, you will probably want to customize further some colors. Good news: Cassiopeia makes an extensive use of what is commonly called “CSS Variables” (the real name is “Custom Properties”), which makes it easy to customize ao colors: they are defined once and are then used at 100+ different places.

Here is an example CSS I added to /templates/cassiopeia/css/user.css in order to customize further the front-end colors in Dark Mode:

:root {
    --website-color-1: #D95F69;
    --website-color-2: #F29544;
@media screen and (prefers-color-scheme: dark) { /* to override the Dark Mode Colors defined in the Dark Magic plugin */
    :root {
        --cassiopeia-color-primary: var(--website-color-1) !important;
        --cassiopeia-color-link: var(--website-color-1) !important;
        --cassiopeia-color-hover: var(--website-color-2) !important;
        --cassiopeia-color-gradient-end: var(--website-color-1) !important;
        --cassiopeia-color-gradient-start: var(--website-color-2) !important;
    .btn-primary {
        background-color: var(--website-color-1) !important;
    .btn-primary:focus, .btn-primary:hover {
        background-color: var(--website-color-2) !important;
    .back-to-top-link {
        color: white !important;
    #cf_1 { /* Convert Forms also uses CSS Variables */
        --background-color: rgba(0, 0, 0, 0.9) !important;

4.7. Add Google Fonts to your template

/* Import font from Google - Go to, select a font and look for the import command */
@import url('');
/* Use the imported font on the page: On Google you can also find the CSS instruction for using the font. If you put this in the body element then the font will be used on the whole website. */
body {
    font-family: 'Georama', sans-serif;


4.8. Add Google Fonts locally to your template

Because of Privacy laws (like GDPR in Europe), you might not be allowed to call a distant font (because it allows the provider to track your visitors).

No problem! You can easily download the necessary files and add the corresponding CSS to /templates/cassiopeia/css/user.css


Source: > Fonts Scheme

4.9. Changing the width of Left / Component / Right areas

4.9.1. Case 1 – when Cassiopeia’s Layout is set on Fluid

What determines the width of the columns in this case is the following CSS line (being CSS Grid):

body.wrapper-fluid .site-grid {
  grid-template-columns: [full-start] minmax(0,1fr) [main-start] repeat(4,minmax(0,25%)) [main-end] 100px [full-end]

Note the part in the middle, namely repeat(4,minmax(0,25%)) This is equivalent to minmax(0,25%) minmax(0,25%) minmax(0,25%) minmax(0,25%) :

So for example if I want to reduce Left and Right from 25% width to 20%, I would simply add the following CSS to /templates/cassiopeia/css/user.css

body.wrapper-fluid .site-grid {
  grid-template-columns: [full-start] minmax(0,1fr) [main-start] minmax(0,20%) minmax(0,30%) minmax(0,30%) minmax(0,20%) [main-end] 100px [full-end]

4.9.2. Case 2 – when Cassiopeia’s Layout is set on Static

In this case, for a large screen (remember: Cassiopeia is Mobile First) what determines the width of the columns is the following CSS line (still CSS Grid):

@supports (display: grid) {
  @media (min-width: 992px) {
    .site-grid {
      grid-template-columns: [full-start] minmax(0,1fr) [main-start] repeat(4,minmax(0,19.875rem)) [main-end] minmax(0,1fr) [full-end]

Note the part in the middle, namely repeat(4,minmax(0,19.875rem)) (rem being a Relative Unit) This is equivalent to minmax(0,19.875rem) minmax(0,19.875rem) minmax(0,19.875rem) minmax(0,19.875rem) :

So for example if I want to reduce Left and Right from 19.875rem to 9.875rem (but still keep the same total width), I would simply add the following CSS to /templates/cassiopeia/css/user.css

@supports (display: grid) {
  @media (min-width: 992px) {
    .site-grid {
      grid-template-columns: [full-start] minmax(0,1fr) [main-start] minmax(0,9.875rem) minmax(0,29.875rem) minmax(0,29.875rem) minmax(0,9.875rem) [main-end] minmax(0,1fr) [full-end]

Of course I could also very easily change the total width by playing with the sum of 4*19.875rem

4.10. Customizing the Blog View layout

Beyond the classical Options available in Joomla for the Blog View, Cassiopeia has some handy Classes that can be set in the Menu Item (of type Blog View) > Blog Layout tab > Article Class option:

For more information, see

Other Classes are also available in Cassiopeia which allow for example to have a “Masonry” Layout:

See an example of masonry-3 on

I am not too sure about the use of columns-X because there is now an Option #Columns (which was not there initially in the first drafts of J4)

4.11. Articles Images – Left, Center or Right

Joomla 4 has changed the float options for images: there is no select box with “right”, “left” or “none” anymore, but a field to insert a css class. Cassiopeia offer the classes “float-start” for positioning the full image on the left (on the right for rtl languages), “float-end” for positioning the full image on the right (on the left for rtl languages) and “float-none” for no floating.

Of course it is also possible to modify the position of the image using own css classes. Examples:

.float-center.item-image {
  text-align: center;

You can use the classes globally for all articles, go to Content -> Options -> Editing Layout and enter the class you want in the field “Full Text Image Class”.

Or you can use the classes on each individual article:

Source : Viviana on

4.12. Module Styles – card or noCard

Of course, you still have the standard Joomla Module Styles, namely

4.13. How to have the Logo on the same row as the Menu

In System > Template Styles > Cassiopeia > Advanced tab > Brand option, if set to Yes you can either

This works of course but given the Layout of Cassiopeia, this Logo or Title are on a separate row before the Header row typically containing the Menu.

OK, why not. There is probably a reason for that that I ignore but it is clearly not the practice on 99,9% of the website.

So if you want your Logo on the same row as the Menu, you can simply proceed as follows:

4.14. Know all possible Positions in Cassiopeia

The most complete/accurate listing of all avaiblable positions is available here:

See “How to find the module positions” on

4.15. How to have a Hamburger Menu in Cassiopeia

See “Change the Menu Layout” on

4.16. Adding a Banner in Cassiopeia

See “Adding a Site header” on

4.17. Adding a custom javascript

4.17.1. Option 1 – directly in user.js

Type for example the following code in user.js and you will have a popup appearing in the front-end:

alert( 'Hello, world!' );

4.17.2. Option 2 – using a Child Template

This requires J4.1 (release date : 15 February 2022)

See in the Resources the presentations made by Dimitris.

4.17.3. Option 3 – using an Module Alternate Layout

Actually with any Template and with any Joomla version, you can also very easily add any CSS or (inline or external) JS. The idea is to create a Module which will inject all the CSS & JS thanks to an Alternate Layout (Override). The advantage of this technique: you can

Here is the procedure

Arbitrary example of code for our Alternate Layout (adding an animation for .images, h2 and h3):

use Joomla\CMS\Factory;
defined('_JEXEC') or die;
$doc = Factory::getDocument();

// adding some css file - for pure css animation
// either via a local file (to be added manually)
// $doc->addStyleSheet("/templates/cassiopeia/css/animate.css", array('version'=>'auto'));
// either via a distant file - see
$doc->addStyleSheet("", [], ["integrity" => "sha512-c42qTSw/wPZ3/5LBzD+Bw5f7bSF2oxou6wEb+I/lqeaKV5FDIfMvvRp772y4jcJLKuGUOpbJMdg/BTl50fJYAw==", "crossorigin" => "anonymous" , "referrerpolicy" => "no-referrer" ]);

// adding some script for animation using intersection-observer
// either via a local file (to be added manually)
// $doc->addScript('/templates/cassiopeia/js/animate.js', array('version'=>'auto'));
// either via an inline script
$myAnimation = <<<MYJS
document.addEventListener('DOMContentLoaded', function() {

    let observer = new IntersectionObserver(function (observables) {
      observables.forEach(function (observable) {
        // the element becomes visible
        if (observable.intersectionRatio > 0.5) {
    }, {
      threshold: [0.5]

    // we observe the elements
    let items = document.querySelectorAll('.image, h2, h3')
    items.forEach(function (item) {

// add the script

with the corresponding addition to /templates/cassiopeia/css/user.css where all the animations would be defined:

h2.mytest, h3.mytest, p.mytest {
    animation: fadeIn; /* referring directly to the animation's @keyframe declaration */
    animation-duration: 2s; /* don't forget to set a duration! */

4.18. How to Customize the height of the Banner Module

Simply adapt the following CSS to your needs and add it to /templates/cassiopeia/css/user.css

.container-banner .banner-overlay {   
    height: max(300px, 50vh); /* by default is 50vh in Cassiopeia */ 
@media (min-width: 768px) {
    .container-banner .banner-overlay {   
        height: max(300px, 45vh);
@media (min-width: 992px) {
    .container-banner .banner-overlay {   
        height: max(300px, 40vh);
@media (min-width: 1200px) {
    .container-banner .banner-overlay {   
        height: max(300px, 35vh);

4.19. How to add an overlay to the Banner Module

Simply adapt the following CSS to your needs and add it to /templates/cassiopeia/css/user.css

.container-banner .banner-overlay .overlay {
    background-image: linear-gradient(120deg, rgba(231, 48, 42, 0.7), rgba(234, 174, 2, 0.7));

4.20. How to add a Video Banner Module

Cassiopeia foresees a Banner Module having a background image, which takes about 50% of the viewport height.

For a website I wanted

To do this


<div class="video-banner">
<div class="text">
<h1 class="display-4 text-thin">Liège Cargo Agency</h1>
<p class="lead">Active since September 2002, LCA is providing all cargo related services and cost-efficient logistics services at Liege Airport.</p>
<p><a class="btn btn-primary btn-lg" href="en/contact?view=form">Contact us</a></p>
<video poster="" autoplay="autoplay" loop="loop" muted="" width="300" height="150">
  <source src="" type="video/mp4" /></video></div>


/* VIDEO BANNER - see */ {
    display: grid;
    grid-template-areas: "hero";
    place-items: center;
    height: max(300px, calc(100vh - 152px)); /* viewport height minus the fixed height of menu header on current website, with a minimum of X pixels */
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.5);
} > * {
    grid-area: hero; /* stacking all the child elements of the grid - could simply have set 1 / 1 / 2 / 2 instead of naming the area hero */
} div.text {
    z-index: 1; /* to be sure that this is on top of the video */
    text-align: center;
    color: white;
    text-shadow: 2px 2px 5px black;
} div.overlay {
    width: 100%;
    height: 100%;
    background-image: linear-gradient(120deg, var(--cassiopeia-color-link), var(--cassiopeia-color-hover));
    opacity: 0.7;
} video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    overflow: hidden;

4.21. Accessibility

This is a J4 feature, not a Cassipeia feature as such. But since Cassiopeia is conceived from scratch to be Accessible it is worth reminding those two features :

4.22. Having Hamburger Menu before Logo on small screens even if it is after on big screens

Typically on a website you would have in the Menu Position the following modules in this order

  1. Logo (Custom HTML Module)
  2. Menu
  3. Language Switcher Module and/or Search Module

But on mobile view this is annoying because our Hamburger Menu (assuming we are using the Collapsible Dropdown Style for the Menu Module) stays “in the middle”. If you want to change the order and have that Hamburger Menu first, simply add the following to /templates/cassiopeia/css/user.css

@media (max-width: 992px) {
  nav.navbar {order: -1;}

4.23. Calling only the necessary Javascript from Bootstrap 5 shipping with J4


Suppose you need to use Tabs in a given Article. There copy-paste the following HTML (taken from the examples on

<div class="bd-example">
    <div class="nav nav-tabs mb-3" id="nav-tab" role="tablist">
      <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
      <button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>
      <button class="nav-link" id="nav-contact-tab" data-bs-toggle="tab" data-bs-target="#nav-contact" type="button" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</button>
  <div class="tab-content" id="nav-tabContent">
    <div class="tab-pane fade active show" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">
      <p><strong>Home text</p>
    <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">
      <p><strong>Profile text</p>
    <div class="tab-pane fade" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab">
      <p><strong>Contact text</p>

See the result in the front-end: the Tabs do appar, but clicking on the 2nd or 3rd Tab does not “do” anything.

This is because we still need to tell Joomla to load the Javascript for Tabs, namely via

\Joomla\CMS\HTML\HTMLHelper::_('', '.selector', []);

You can easily add any Bootstrap Javascript to Cassiopeia by following the Official Documentation:

If you follow “Approach 3: Using a Template Override” don’t forget to add the Module Class bs-tab to the Module you create and then the Tabs will be working.

5. Help the Community with those issues!

5.1. Issue 1 – the Hamburger Menu on small screens

On a website, you would typically have in the header

  1. the Logo
  2. the Menu Items
  3. the Language switcher and/or the Search

But on smartphone (more generally on small screens) even when using the Cassiopeia Collapsible Dropdown Menu, clicking on the Hamburger Menu gives something ugly:


5.2. Issue 2 – the Read More button partially hidden

On a Blog View, according to the lenght of the text, the viewport etc, the Read More button is often partially hidden:


5.3. Issue 3 – Layout in Blog View

When using Article Class image-right for a Blog View (1 column for instance), I noticed that the Images and Introtext would not display evenly: when the Introtext is too short for example when the Image on the Right comes next to the Text on the Left (instead of having a 50%-50% Layout).

Illustration with image-right image-alternate boxed (but I double-checked: image-right is enough to create the issue)


I did not have much time to investigate this but as a quick workaround I added the following to /templates/cassiopeia/css/user.css

.image-left .blog-item .item-content, .image-right .blog-item .item-content {
    flex: 1 0 40%;

If you can investigate further and fix Cassiopeia for this it would be highly appreciated.

6. Thank you

Joomla User Group New Jersey for having me today

So many members of the Joomla Community for being #jPositive


7. Get in touch

Any suggestion about this presentation?
Please feel free to contact me. I’ll be happy to keep improving it 🙂

Marc Dechèvre | woluweb
+32 474 37 13 12 | +32 2 772 58 69