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
Forge
```
But good page titles are incredibly useful!

Forgetting them can hurt both SEO and user experience.

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
{% 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
```