Discussion: Managing <head> properties

Here’s a proposal (django-components) for the API for configuring <head>. It’s inspired by unhead. I wonder if you had similar issues with populating the <head> tag, or other suggestions?

-–

For context, when you render your templates / HTML, you usually populate the <head> to include CSS, metadata like page title, or SEO metadata, and more.

When you render the entire page as a single template, you can just update the directly, because you know exactly what to put there.

But when you break the template down into smaller reusable parts, it gets trickier. Maybe there’s a “ProfileCard” component, and you want to set the page title and SEO metadata based on the contents of the user profile.

Currently you’d have to lift the metadata up

user = Users.object.get(pk=id)
context = Context({
    "user": user,
    "user_name": user.name
})

template = Template("""
<html>
  <head>
    <meta property="og:title" content="{{ user_name }}" />
    <meta property="og:type" content="profile" />
  </head>
  <body>
    {% component "ProfileCard" user=user / %}
  </body>
</html>
""")

Downsides:

  • You have to repeat this for each page where you want to use `ProfileCard`
  • If your colleague replaces `ProfileCard` with something else in the future, they might forget to update the metadata

Instead, the proposal is to define the metadata next to what they belong to. In django-components you define templates as classes, so it’s on this class where you’d define the head metadata:

class ProfileCard(Component):
    class Kwargs:
        user: User

    class Head:
        title = "User profile"
        # Or dynamically
        title = lambda c: f"User profile: {c.kwargs.user.name}"
        meta = [
            {"property": "og:title", content="User profile"},
            {"property": "og:type", content="profile"},
        ]

This way, whenever you would render ProfileCard in a template, the would be automatically set to contain this metadata.

Then, the page template could be simplified to:

<html>
  <body>
    {% component "ProfileCard" user=user / %}
  </body>
</html>

Have you seen django-meta, “Pluggable app to allow Django developers to quickly add meta tags and OpenGraph, Twitter, and Google Plus properties to their HTML responses.”? Does it solve any of the issues you’re looking to solve?

Thanks, didn’t know about django-meta. I did a quick search before, but I searched for “django head”, so that package didn’t show up.

I’ll still probably go ahead and implement it in django-components (DJC). As mentioned here, re-implementing this in DJC will allow to have first class support for metadata and fragments. So that when you insert an HTML fragment into a page, and that fragment defined some metadata like title, then the page title would be automatically updated.

PS: Edited the original post to clarify that the proposal is for django-components.