Skip to contentSkip to author details

Creating a Bootstrap Theme Selector for your Site

 blog  bootstrap  themes  development  bootswatch

I have recently converted my Ghost blog to use Bootstrap. As part of that, I decided to add a little toy to the sidebar that would allow users to change the Bootstrap theme that the site uses to display its content. All code for my custom theme can be found on GitHub in the ghost-cerkit-theme repository.

This post will outline the design and code for the theme selection "control".

Themes

I am using the Bootswatch themes for my website. This will give us quite a few decent looking themes to choose from. They're also free.

Source Files

For this control to work, we will need to add an id to the link tag that we use for our initial Bootstrap theme (bootstrap-theme):

<link id="bootstrap-theme" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.6/superhero/bootstrap.min.css" rel="stylesheet"  crossorigin="anonymous" />

This will allow us to use this link element in jQuery to actually change the CSS source file location.

You will also need to add a link to the JavaScript code in your page. For my Ghost theme, I used the following code below the link to jQuery:

<script type="text/javascript" src="{{asset "js/bootstrap-theme-selector.js"}}"></script>

In order to display this and other controls on the side, I have added a sidebar partial to my Ghost theme.

<!-- sidebar -->  
{{!include the various components}}
{{> "search-form"}}
{{> "sidebar-bio"}}
{{> "sidebar-theme-picker"}}

Let's take a look at the code for the sidebar-theme-picker.hbs partial.

<div class="panel panel-primary">  
    <div class="panel-heading">
        Alternate Theme
    </div>
    <div class="panel-body">
        <form class="form-inline" id="theme-selection-form">
            <div class="form-group">
                <div class="input-group">
                    <select id="theme-selector" class="form-control">
                        <option value="cerulean">Cerulean</option>
                        <option value="cosmo">Cosmo</option>
                        <option value="cyborg">Cyborg</option>
                        <option value="darkly">Darkly</option>
                        <option value="flatly">Flatly</option>
                        <option value="journal">Journal</option>
                        <option value="lumen">Lumen</option>
                        <option value="paper">Paper</option>
                        <option value="readable">Readable</option>
                        <option value="sandstone">Sandstone</option>
                        <option value="simplex">Simplex</option>
                        <option value="slate">Slate</option>
                        <option value="spacelab">Spacelab</option>
                        <option value="superhero">Superhero</option>
                        <option value="united">United</option>
                        <option value="yeti">Yeti</option>
                    </select>
                </div> <!-- .input-group -->
            </div> <!-- .form-group -->
            <button class="btn btn-success form-control" onclick="clearTheme()">Reset</button>
        </form>
    </div>
</div>

This will give us the drop down control that we need to choose the theme.

The JavaScript code that wires this control up to the change event can be found in the bootstrap-theme-selector.js file.

In addition, all initialization of the variables for the theme selector can be found in the site-init.js file. Here is the required code for initialization of the theme selector:

var linkToBootstrapCDN = "//maxcdn.bootstrapcdn.com/bootswatch/3.3.6/";  
var themeStyleCss = "/bootstrap.min.css";  
var defaultTheme = 'superhero';  
var showThemeSelector = true;

Here is the code that runs when the document is ready:

$(document).ready(function() {

    var selectedTheme = $.cookie('user-theme');

    if(selectedTheme != null) {     
        changeTheme(selectedTheme);
    }
    else {
        setSelectedOption(defaultTheme);
    }

    $(document).on('change', '#theme-selector', function(e) {
        var selectedTheme = e.target.options[e.target.selectedIndex].value;
        setTheme(selectedTheme);
    });

    if(!showThemeSelector) {
        $('#theme-selector').css('display','none');
    }
});

We start by pulling a cookie out that stores the value of the user selected theme. If this value is not set, then we use the default theme as defined by our defaultTheme variable. Otherwise, we use the theme name as set in the cookie. We do this by calling the changeTheme() function, passing the name of the theme we wish to change to.

Here is the code for the changeTheme() function:

function changeTheme(selectedTheme) {  
    setSelectedOption(selectedTheme);

    var completeCssLink = linkToBootstrapCDN + selectedTheme + themeStyleCss;
    $('link#bootstrap-theme').attr('href', completeCssLink);
}

The first thing we do is call the setSelectedOption() function to loop through all of the options in the theme selection control and find the currently selected theme. When we find it, we set the selected attribute to 'true' (this has the same effect as adding an empty selected attribute). For options that aren't the currently selected theme, we simply remove the selected attribute altogether (it may or may not be on that option, but it doesn't hurt to attempt to remove a non-existent attribute).

After that, we build the entire link to the selected CSS file by combining the Bootstrap CDN address with the selected theme name and the filename to link to.

Then, we change the href attribute of the link element with the id of bootstrap-theme to point to the newly created CSS address. This is what triggers the browser to change the CSS theme that it uses to format the content.

Note: If you've made any CSS modifications that need to override the Bootstrap themes, you will need to also load those in the changeTheme() function after you have loaded the Bootstrap theme.

Here is the code for setSelectedOption():

function setSelectedOption(selectedTheme) {  
    $("#theme-selector option").each(function() {
        if ($(this).val() === selectedTheme) {
            $(this).attr('selected','true');
        }
        else {
            $(this).removeAttr('selected');
        }
    });
}

Selection control change event handler

In order to change the theme when the user selects a new theme from the drop-down list, we need to respond to the change event on the control. We wire up the change event by using the jQuery on() function like so (all of this happens during the $(document).ready() handler):

$(document).on('change', '#theme-selector', function(e) {  
    var selectedTheme = e.target.options[e.target.selectedIndex].value;
    setTheme(selectedTheme);
});

Note: #theme-selector is the id of the select control containing the list of themes.

After pulling the value of the theme out of the currently selected option, we call the setTheme() function, passing the name of the selected theme. Here is the code for setTheme():

function setTheme(theme) {  
    $.cookie('user-theme', theme, { expires: 170, path: '/' });
    changeTheme(theme);
}

As you can see, all this function does is set the user's cookie to hold the value of the selected theme and then call the changeTheme() function to trigger the browser to actually load the theme.

Resetting the theme

The sidebar form also contains a button that allows the user to reset the theme back to the default (as chosen by the blog theme author, or as defined in the header of the Settings->Code Injection section of the blog dashboard). The button itself is defined to call the clearTheme() function when clicked:

<button class="btn btn-success form-control" onclick="clearTheme()">Reset</button>

Here is the code for the clearTheme() function:

function clearTheme() {  
    $.removeCookie('user-theme', { path: '/' });
    changeTheme(defaultTheme);
}

All we do here is remove the cookie and change the theme to the default theme.

Hiding the control

The ghost-cerkit-theme allows you to hide this control by adding the following code to your header in Settings->Code Injection:

<script>  
    showThemeSelector = false;
</script>

Here is the code to check to see if the theme selector should display:

if(!showThemeSelector) {  
    $('#theme-selector').css('display','none');
}

This code exists in the $(document).ready() handler below everything else.

Summary

While not necessary, this control allows the user to change your blog's theme to something other than the theme you set during your design. This allows them to set it to a theme that is easier for them to read, or just change it to something different to keep from getting bored.