# (not recommended) Overriding Discourse templates from a Theme or Plugin

**URL:** https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487
**Category:** Developer Guides
**Tags:** how-to
**Created:** [December 2, 2022, 1:52pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487 "2022-12-02T13:52:58Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [December 2, 2022, 1:52pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/1 "2022-12-02T13:52:58Z")

</div>

Ideally, when customizing Discourse via themes/plugins, you should use CSS, [the JavaScript Plugin API](https://meta.discourse.org/t/a-new-versioned-api-for-client-side-plugins/40051), or [plugin outlets](https://meta.discourse.org/t/connect-your-theme-to-plugin-outlets-to-inject-templates-with-custom-content/32727). If none of these work for your use-case, feel free to open a PR to Discourse core or start a #Development topic here on Meta. We’re always happy to discuss adding new outlets/APIs to make customization easier.

If you’ve exhausted all other options, you may need to resort to template overrides. This technique allows you to override the entire template of any Ember Component or Route from your theme/plugin.

> 🚨 **This is not a recommended way of customizing Discourse.** Day-to-day changes in Discourse core **will** conflict with your template override eventually, potentially causing catastrophic errors when rendering the forum.
> 
> If you decide to take this approach, make sure you have sufficient automated testing and QA processes to detect regressions. If you distribute a theme/plugin with template overrides, please ensure forum admins are aware of the stability risks your theme/plugin carries.

> 🚨 🚨 🚨 **October 2023 Update** : For new features, Discourse is increasingly moving towards using components authored using Ember’s `.gjs` file format. Templates for these components are defined inline, and cannot be overridden by themes/plugins.
> 
> Going forward, all template customizations should be done using [Plugin Outlets](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727)

> **I understand this will break in the near future, show me the docs anyway**
>
> ## Overriding Component Templates
> 
> To override an Ember Component template (i.e. anything under [`components/*`](https://github.com/discourse/discourse/tree/main/frontend/discourse/app/components) in Discourse core), you should create an identically-named `.hbs` in your theme/plugin. For example, to override the template for the `badge-button` component in Discourse core, you would create a template file in your theme/plugin at this location:
> 
> 🎨 `{theme}/javascripts/discourse/templates/components/badge-button.hbs`
> 
> 🔌 `{plugin}/assets/javascripts/discourse/templates/components/badge-button.hbs`
> 
> The override must always be nested inside the `/templates` directory, even if the core component has a ‘colocated’ template.
> 
> ## Overriding Route Templates
> 
> Overriding route templates (i.e. all the non-component templates under [`templates/*`](https://github.com/discourse/discourse/tree/main/frontend/discourse/app/templates)) works in the same way as components. Create an identically named template in your theme/plugin. For example, to override `discovery.hbs` in core, you would create a file like
> 
> 🎨 `{theme}/javascripts/discourse/templates/discovery.hbs`
> 
> 🔌 `{plugin}/assets/javascripts/discourse/templates/discovery.hbs`
> 
> ## Interaction between multiple themes / plugins
> 
> If multiple installed themes/plugins override the same template, the ‘winner’ is the one with the lowest-numbered ranking in this list:
> 
> 1. Theme overrides (highest theme ‘id’ wins)
> 2. Plugin overrides (latest alphabetical plugin name wins)
> 3. Core
> 
> This precedence also means that you can override plugin templates from themes. Technically you can also override theme templates from other themes, and plugin templates from other plugins, but the behavior can be surprising because of the dependence on plugin-name and theme-id.
> 
> ## How does this work?
> 
> Discourse assembles and prioritises templates in the [DiscourseTemplateMap](https://github.com/discourse/discourse/blob/666fd43c37/app/assets/javascripts/discourse-common/addon/lib/discourse-template-map.js) class. For colocated component templates, that information is used [during app initialization](https://github.com/discourse/discourse/blob/666fd43c37/app/assets/javascripts/discourse/app/initializers/colocated-template-overrides.js) to replace the core template associations. For all other templates, the map is used by [the resolver at runtime](https://github.com/discourse/discourse/blob/666fd43c37/app/assets/javascripts/discourse-common/addon/resolver.js#L327) to fetch the correct template.

* * *

This document is version controlled - suggest changes [on github](https://github.com/discourse/discourse/blob/main/docs/developer-guides/docs/03-code-internals/19-overriding-templates.md).

---

<div class="post-metadata">

### Author: ![misham](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/misham/32/282796_2.png) [@misham](https://meta.discourse.org/u/misham)
#### Post date: [December 7, 2022, 3:44pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/2 "2022-12-07T15:44:25Z")

</div>

And what about mobile templates? What is the directory structure to rewrite templates from core

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [December 7, 2022, 3:47pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/3 "2022-12-07T15:47:59Z")

</div>

It should work exactly the same - you match the name of the core template. So if it has `/mobile`, include that in your override.

---

<div class="post-metadata">

### Author: ![misham](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/misham/32/282796_2.png) [@misham](https://meta.discourse.org/u/misham)
#### Post date: [December 14, 2022, 10:42am UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/4 "2022-12-14T10:42:19Z")

</div>

I try to rewrite mobile login.hbs template and it doesn’t work [Imgur: The magic of the Internet](https://i.imgur.com/zOyJ5ET.png), am I right with the path?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [December 14, 2022, 11:18am UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/5 "2022-12-14T11:18:44Z")

</div>

The full path isn’t visible in your screenshot as far as I can see. Please can you paste it here as text.

---

<div class="post-metadata">

### Author: ![misham](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/misham/32/282796_2.png) [@misham](https://meta.discourse.org/u/misham)
#### Post date: [December 14, 2022, 12:00pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/6 "2022-12-14T12:00:13Z")

</div>

themeroot/javascripts/mobile/modal/login.hbs

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [December 14, 2022, 12:03pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/7 "2022-12-14T12:03:06Z")

</div>

You’re missing `discourse/templates` from your path

> [@david](#):
>
> ## Overriding Route Templates
> 
> Overriding route templates (i.e. all the non-component templates under [`templates/*`](https://github.com/discourse/discourse/tree/main/app/assets/javascripts/discourse/app/templates)) works in the same way as components. Create an identically named template in your theme/plugin. For example, to override `discovery.hbs` in core, you would create a file like
> 
> 🎨 `{theme}/javascripts/discourse/templates/discovery.hbs`

So in your case, it would be `{theme}/javascripts/discourse/templates/mobile/modal/login.hbs`

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [March 7, 2024, 1:00pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/12 "2024-03-07T13:00:38Z")

</div>

> [@david](#):
>
> For new features, Discourse is increasingly moving towards using components authored using Ember’s `.gjs` file format. Templates for these components are defined inline, and cannot be overridden by themes/plugins.

Is this still the case?

I’m a bit sad the ability to override a lot of code is being removed.

It makes sense to replace the bespoke Widget system, to some extent, but that gave us the ability to hook into existing code at multiple levels, reducing a lot of breaking change risk as we could target just small blocks in clever ways that would allow us to:

- add features
- not disturb anything else.

I’ve just had to remove TWO significant features from Discourse Journal, for example, that were based on fine grain overrides to widgets because the only way to have recreated them in Glimmer is via a pair of Template overrides (including an attempt to change a .gjs file) which is apparently no longer supported.

Even if this was supported, we would be left with overriding bigger stretches of code than under the widget framework, with an associated increase in risk of core changes conflicting with the overrides.

This isn’t healthy for the extensibility of the platform.

Can anything be done about it?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [March 7, 2024, 1:17pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/13 "2024-03-07T13:17:34Z")

</div>

> [@merefield](#):
>
> gave us the ability to hook into existing code at multiple levels, reducing a lot of breaking change risk

Yeah I hear you - there were some nice things about widget extensibility APIs.

But the flip side is that it’s been incredibly difficult for us to modify ANY of the widget-based UI in core, because we have no idea what random methods/decorations people might be introducing. That’s why widget customisations have seemed relatively stable - we’ve been too scared to touch the core implementations.

> [@merefield](#):
>
> we could target just small blocks in clever ways

Our solution for this going forward is [Wrapper Plugin Outlets](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727#wrapper-outlets-2). These allow themes and plugins to optionally override very small chunks of templates with their own implementation.

For example, see how Chat conditionally [overrides the home-logo](https://github.com/discourse/discourse/blob/a9371a2a8777cdf1db7f3c10b85cfe6a84837869/plugins/chat/assets/javascripts/discourse/connectors/home-logo-wrapper/chat-header-connector.hbs#L1-L1) with [a custom component](https://github.com/discourse/discourse/blob/a9371a2a8777cdf1db7f3c10b85cfe6a84837869/plugins/chat/assets/javascripts/discourse/components/chat-header.gjs#L49-L66). That works for the existing widget-based header, and the new glimmer-based header (coming soon! ™)

We’re generally happy to accept PRs to add new wrapper outlets in various places. If you’re unsure about a particular use-case, please feel free to open a #Development topic with details!

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [March 7, 2024, 1:20pm UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/14 "2024-03-07T13:20:54Z")

</div>

OK that’s sounds like a way forward, thank you.

I’ll need to digest the implications of that and adjust to a strategy along those lines.

Appreciate the response!

---

<div class="post-metadata">

### Author: ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)
#### Post date: [May 25, 2024, 8:41am UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/15 "2024-05-25T08:41:47Z")

</div>



---

<div class="post-metadata">

### Author: ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)
#### Post date: [July 26, 2024, 11:30am UTC](https://meta.discourse.org/t/not-recommended-overriding-discourse-templates-from-a-theme-or-plugin/247487/17 "2024-07-26T11:30:50Z")

</div>


