How to add settings to your Discourse theme

Discourse now has the ability for themes to have “settings” that can be added by theme developers to allow site owners to customize themes through UI without having to change any line of code and worry about losing their changes with future updates for the theme.

Table of Content

  1. Adding settings to your theme
  2. Supported types
  3. Setting description and localization
  4. Min and max attributes
  5. Access to settings in your JS/CSS/Handlebars

1) Adding settings to your theme

Adding settings to your theme is a bit different from adding CSS and JS code, that is there is no way to do it via the UI.

The way to add settings is to create a repository for your theme, and in the root folder of your repository create a new settings.yaml (or settings.yml) file. In this file you’ll use the YAML language to define your theme settings.

(Note: there is a new tool that’ll make the whole process of developing themes a lot easier. Basically it watches your theme repository and as you make changes to your theme repo locally, it’ll automatically update the theme on your site. More information here: Discourse Theme CLI (console app to help you build themes))

Now if you’re familiar with plugin development, this shouldn’t be a new thing to you - it mostly works the same way as adding site settings to your plugin. Just dump some valid YAML in your settings file and you’ll be good to go.

A valid theme setting must have a name and default value, that’s the bare minimum and it looks like this:

simple_setting: true

As you can probably tell, that will create a setting with the name simple_setting and it’ll have true as its default value.

Similarly, you can add something like this:

site_name: My Forums
max_avatars: 7

And you’ll have two more settings, site_name which will be a string setting with “My Forums” as the default value, and max_avatars as an integer setting with default value of 7.

So until this point we’ve covered the simplest way to define settings. In the next section we’ll dive a bit deeper into the various types of settings and how you can use them.

2) Supported types

There are 6 types of settings:

  1. integer
  2. float
  3. string
  4. bool (for boolean)
  5. list
  6. enum

And you can specify type by adding a type attribute to your setting like this:

  type: float
  default: 3.14

I should say that you don’t always have to explicitly set a type attribute because Discourse is smart enough to work out the setting type from the setting’s default value. So you can reduce the above example to this:

  default: 3.14

That said, you need to set a type attribute when working with list and enum settings, otherwise Discourse will not recognize them correctly.

Example of list and enum settings:

  default: apples|oranges
  type: list

  default: orange
  type: enum
    - apple
    - banana


In case the difference between list and enum settings is not clear to you: enum settings allow your theme users to select only one value from a set of values defined by you (see the choices attribute).

On the other hand, list settings allow your users to create their own list (i.e. an array) of values. They can add to or remove from the setting’s default list of values.
You can set the default list of values for the setting by joining the values with a vertical bar “|” character. See the list setting in the example above.

You can see a real-world use case for list settings here: Linkify words in post.

Note: pay attention to indentation when working with YAML because YAML is very picky about spaces and will throw a syntax error if your code indentation is incorrect.

3) Setting description and localizations

You can add description text to your theme setting and it’ll be shown right under the setting. To do that simply add a description attribute to your setting like so:

  default: apples|oranges
  type: list
  description: "This text will be displayed under this setting and it explains what the setting does!"

And you’ll get this:


Multiple languages support

If you know more than one language, and you’d like to add support for those languages to your theme, then you can totally do that provided that Discourse supports said languages.

First of all, make sure the language you want to support is in this list:

Languages list
Code Name
ar اللغة العربية
bs_BA bosanski jezik
ca català
cs čeština
da dansk
de Deutsch
el ελληνικά
en English
es Español
et eesti
fa_IR فارسی
fi suomi
fr Français
gl galego
he עברית
id Indonesian
it Italiano
ja 日本語
ko 한국어
lv latviešu valoda
nb_NO Norsk bokmål
nl Nederlands
pl_PL język polski
pt Português
pt_BR Português (BR)
ro limba română
ru Русский
sk slovenčina
sq Shqip
sr српски језик
sv svenska
te తెలుగు
th ไทย
tr_TR Türkçe
uk українська мова
ur اردو
vi Việt Nam
zh_CN 中文
zh_TW 中文 (TW)

(If you can’t see your language in the list then you might want to take a look at How to add a new language)

Then you’ll need find your language code from the above list and use the language code as a key under the description attribute and translation as a value for the key like so:

  default: apples|oranges
  type: list
    en: English text
    ar: نص باللغة العربية
    fr: Texte français

And now you have support for 3 languages: English, Arabic and French.

4) Min and max attributes

Sometimes you may need to specify limits that a setting value can’t exceed to prevent your users from accidentally breaking the theme or possibly the whole site.

To specify limits, simply add a min or max or both attributes to your setting like so:

  default: 10
  min: 5
  max: 100

You can specify limits to integer, float and string settings. For integer and float settings, the value of the setting itself is checked against the limits. And for string settings, the length of the value is checked against the specified limits.

If your user tries to enter a value that’s not within the allowed range, they’ll see an error telling them what the min and max values are.

5) Access to settings in your JS/CSS/Handlebars

To have access to setting in your theme JS code, the script tag that wraps your code must have a type="text/discourse-plugin" attribute as well as version specified like so:

<script type="text/discourse-plugin" version="0.8.13">
  alert(settings.integer_setting + 1);

In CSS, you’ll get a variable created for every setting of your theme and each variable will have the same name as the setting it represents.

So if you had a float setting called global_font_size and a string setting called site_background, you could do something like this in your theme CSS:

html {
  font-size: #{$global-font-size}px;
  background: $site-background;

Similarly, theme settings are available in handlebars templates that you define in your theme whether you’re overriding a core template, or creating your own. For example if you have something like this in your theme:

<script type='text/x-handlebars' data-template-name='my-template'>
  <h1>{{theme-setting 'your_setting_key'}}</h1>

It’ll render with your setting value.

You may want to use a boolean setting as a condition for an {{#if}} block in your template, this is how you can do that:

<script type='text/x-handlebars' data-template-name='my-template'>
  {{#if (theme-setting 'my_boolean_setting')}}
    <h1>Value is true!</h1>
    <h1>Value is false!</h1>

If you have a question about this or there is something unclear, feel free to ask - I’ll try to answer/clarify as much as I can. Also this is a wiki post, so contributions to improve this are greatly appreciated! :sunflower:


Will delete this once it is actioned:

Adding settings yaml to a theme is going to have to be done direct in a git repo, not in the UI. I simply do not want to confuse things here. So we should document how you add the settings.yml file and then tie this in to Structure of themes and theme components which needs improvement.


I’m fine with removing it from the UI, although I do have one concern which is how are we going to communicate error messages with the theme dev when there’s an error in the settings yaml? I’m thinking maybe we could do something like this:


Hmmm how are you going to even get into that state? We should not allow importation of a broken theme or theme component in the first place


Turns out you can actually import a broken theme** GitHub - OsamaSayegh/broken-theme

But that’s not really my concern, what I’m concerned about is that we need an outlet to show error messages to theme devs when they’re working on their themes. Without having a way to show them error messages, they’re pretty much on their own to figure out what’s wrong with their YAML. Or maybe I’m overthinking this too much.

** but not always, if settings yaml is invalid you’ll get a 500 error - I had to remove my yaml file to be able to import the broken theme, but broken CSS and JS totally went through.


I would say, much better focus on cleaning up the error reporting on import so we behave in a cleaner way here. This eliminates the problem at the source.

I am pro surfacing a “your theme has problems” section on the main page though, for sure. You should not have to drill in for this.

  • The following CSS sections are broken
  • The following JS is broken
  • Theme YAML is broken

Yes, that sounds like a good solution and totally addresses my concern. If you want these improvements as community contributions I’d be totally happy to work on it (but probably won’t be able to until April, so if anyone wants take a shot at it, feel free!).


Hey! This is a great tutorial! I was able to get my setting to appear in the admin/theme ui very quickly.
However, I am having trouble using that variable in JS.

I have a Settings.yml file with this in it.

  default: 10
  min: 5
  max: 100 

And in my /common/header.html

<script type="text/discourse-plugin" version="0.8.13">
    alert(settings.integer_setting + 1);

But in my dev tools I get

Any ideas? :confused:

1 Like

Try moving that to common/head_tag.html instead.


Ohh right!

That worked! Thank you :slight_smile:

Also, just to clarify, there is no way to access the settings in HTML?
For instance, if I wanted something like this:

<a href="$settings.someUrl"> Goto Some URL </a>
1 Like

Not directly. At least, not that I’m aware of. I typically assign them to component attributes and access them in the templates from there.


How do you do that exactly? I’d like to use a settings element in the footer. I could not find a way to do this so far :frowning:

Did you do the things in the OP? You need to ask a question or say what you have tried that didn’t work. The answer to your current question, is “follow the instructions in the OP.”

1 Like

How can I for example use a string from the settings.yml in the footer of the page? The footer does not seem to accept any javascript.

What did you try? Was it something like:

Yep, this does not work.

Yes, that’s expected. The footer theme field can take any HTML, including script tags, however the content of the script tags won’t execute (you can still see them in the DOM, but they don’t do anything). You’ll need to move your scripts tags to the head_tag field.

1 Like

Yes that I know already. But how to get a setting from the theme - let’s say a string - in the head_tag and then use this string in the footer HTML?

As explained in the OP, you can access your settings in your JS code like this: settings.your_setting_key.
As to how you can pass this to your footer HTML, I can’t answer this because it depends on your code and how you’re implementing your footer.

I suggest you go through this incredibly helpful guide which explains lots of things about the theme system and it even has a footer example:


Oh I’m like 20 times through the entire article without finding the answer for my case.
I know how to access them in js that‘s all fine and good. What I don’t know is how to pass them into the footer from the head_tag

My footer is just plain HTML nothing fancy. Just a simple div with some text (which I would like to set through theme settings).

The footer looks like this:

<div class="footer">
  <div class="copyright">Copyright © {{STRING FROM SETTINGS}}</div>