It's easy to forget about the [HTML `` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title) when building a Plain or Django app. You put one in your `base.html` when you start the project, but forget to actually change the title when making your individual views and templates. ```html <!doctype html> <html lang="en"> <head> <title>Forge ``` But good page titles are incredibly useful! ![](/assets/guides/django-page-titles-dynamic.png) Forgetting them can hurt both SEO and user experience. ![](/assets/guides/django-page-titles-same.png)   There are two ways we recommend implementing HTML page titles in Plain or Django: 1. [Using template blocks](#django-page-titles-using-template-blocks) (simpler) 2. [Using class-based views](#django-page-titles-using-class-based-views) (more powerful) ## Page titles using template blocks Template blocks can be used for small pieces of content just like they can be used for entire headers/bodies/footers. In your `base.html`, use a standard template block inside the `` tag: ```html <!doctype html> <html lang="en"> <head> <title>{% block title %}{% endblock %} ``` When you extend your template, simply use the `{% block title %}` to set the page title: ```html {% extends "base.html" %} {% block title %}Billing{% endblock %} {% block content %} ... {% endblock %} ``` You can use context variables just like any other template blocks: ```html {% extends "base.html" %} {% block title %}{{ obj.name }} billing{% endblock %} {% block content %} ... {% endblock %} ``` That's all there is to it! If you don't know where to start then give this a try. But if you find yourself needing more control then consider moving the logic to your views instead... ## Page titles using class-based views Let's create a view mixin that injects a `title` into the template context: ```python # (Plain) class PageTitleViewMixin: title = "" def get_title(self): """ Return the class title attr by default, but you can override this method to further customize """ return self.title def get_template_context(self): context = super().get_template_context() context["title"] = self.get_title() return context ``` ```python # (Django) class PageTitleViewMixin: title = "" def get_title(self): """ Return the class title attr by default, but you can override this method to further customize """ return self.title def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["title"] = self.get_title() return context ``` Then use `{{ title }}` in your `base.html`: ```html {{ title }} ``` By using both a `title` class attribute *and* a `get_title` method, it will be easy to set a "static" title for a view: ```python class BillingView(PageTitleViewMixin, TemplateView): template_name = "billing.html" title = "Billing" ``` But also do something more dynamic: ```python class ProjectView(PageTitleViewMixin, DetailView): def get_title(self): return self.object.name ``` You could further extend this to add a suffix to the title automatically: ```python # (Plain) class PageTitleViewMixin: ... def get_template_context(self): context = super().get_template_context() context["title"] = self.get_title() + " - My App" return context ``` ```python # (Django) class PageTitleViewMixin: ... def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["title"] = self.get_title() + " - My App" return context ``` **Bonus!** You could also raise an exception on empty titles, so you don't forget to set the title for every view: ```python # (Plain) class PageTitleViewMixin: ... def get_template_context(self): context = super().get_template_context() title = self.get_title() if not title: raise ValueError("Page title should not be empty") context["title"] = title + " - My App" return context ``` ```python # (Django) class PageTitleViewMixin: ... def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) title = self.get_title() if not title: raise ValueError("Page title should not be empty") context["title"] = title + " - My App" return context ```