django-components: Deprecate `component_block` in favour of `component`
The only difference between component
and component_block
is that component
doesn’t require an ending tag. But component_block
is more popular (I think) and the structures you can build with it are much more complex. In those cases, it would be nicer (and clearer, and require less typing) if you could just use {% component_block %} all the time.
Idea: Require {% component %}
to have an ending tag, and make both tags behave exactly the same. Deprecate component_block
.
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 3
- Comments: 37 (23 by maintainers)
Commits related to this issue
- Merge pull request #376 from EmilStenstrom/simplify-api Rename component_block to compnent (Fixes #232) — committed to dylanjcastillo/django-components by EmilStenstrom 4 months ago
I’m still deciding how I feel about this. All in all I agree with the idea of designing for new users, or at least in such as way feels familiar for Django developers.
The benefit of going from two tags to a single tag is clear: it’s one less thing to learn.
By contrast, playing devil’s advocate, I can see a few issues with it:
More typing in the case of simple, slotless components. I believe there are many such cases (such as in the ‘button’ example below). How would existing users feel about having to add extra closing tags all over the place for the exact same effect?
For instance, this—
—becomes this:
We now have a pair of opening and closing tags without any content in between. This is odd seeing as the very raison d’être of tag pairs is to surround other template content. At least, that’s the only use case you’ll encounter in the Django docs. Empty tag pairs are in a sense visual noise.
One design I can think of that addresses this emptiness – at the cost of ergonomics – is to move component arguments/context vars into the block (just as ‘fill’ tags are now). Our example above, for example, would turn into something like this (with or without closing ‘arg’ tags).
Either
Or
Obviously, this isn’t much better in terms of the amount of typing required and the visual space taken up by the component. It’s probably in every respect worse. =p
As for a self-closing
{% component ... / %}
shorthand variant – an example of which might be this:– I see a few issues:
/
, might not stand out enough, making it harder to parse templates that make use of both variants – kind of like reading nested bracketed expressions containing a missing closing bracket somewhere.Nevertheless, I believe users will expect a more compact/shorthand version, since this is something that is supported by (among other)…
I’m not that fond of {% Box %} because it feels too magical. I care a lot about how people that have no idea what django-components is, react to seeing it for the first time. If there’s a component in the name, that gives a nice hint that probably they should look in the components dir. Which dir? Well, there’s a name there directly after the component name…
@EmilStenstrom Interesting idea in the sense of ‘one less tag to be aware of’. On the other hand, it’s less typing if you don’t need any of the slot-related features. I think it’s for this reason that, for example, Vue.js allows both open and self-closing variants of components.
Here’s an idea: let’s see how many hits we get for each of the tags in Github’s code search and treat that as an estimate of their relative popularity?
@timothyis That sounds a lot like Django Slippers! I think it’s a pretty neat design. What I like less about it is that behind the scenes it leads to a vast proliferation of dynamically created template tags.
I’ve been thinking more about this. I think we’re making things too hard on ourselves. I still think just having a component tag that requires a endcomponent tag is the best way forward. This is an easy fix, if we ignore backwards compatibility. And since this is pre-1.0 software, I think we can break compatibility. I think it’s worth it.
So. New plan:
component_block
tag spit out an error saying thatcomponent
should be used instead.component
tag is missing an end tag.Agreed that 1) sends mixed messages. So it’s out. That leaves 3) and 2).
The problem with 3) is that if you miss that there’s a new setting, you might not get a grace period at all. You just get the breakage, and no new features until we ship 1.0 instead.
That’s why I like 2): I breaks things right away, but then gives the user a simple workaround.
Design thoughts:
So the final command would be “./manage.py components upgrade close-component-tags <glob pattern>”.
Thoughts?
Oof, this turned into quite the essay. ✍️ Apologies. TL;DR I vote component/endcomponent and nothing else.
This was already pretty clear, but thanks for the overview. Handy to have an example of everything in one place!
I have mixed feelings about this. On the one hand, I can definitely see where you’re coming from. On the other, I see a few potential issues.
Impressions during usage
To get a feel for the new tag style, I tried it out it in an artifically complex template with embedded components inside fill tags and slot tags, inside components etc., and with mixed closed and unclosed usages. My initial impressions:
Based on the exercise above, my conclusions would be that, yes, we can implement a single component tag; yes, one could get used to reading/writing templates with them, although I’m sorry to see default tags wiped off the table; and finally, crap, we’re going to have either open PRs with djhtml and other tools, or learn the hard way that there’s a good reason why tags that have dual open and self-closing usages are uncommon in Django – not to mention non-existent in HTML, and sort-of-maybe-possible in XML.
Potential issues
Abstractly, there are a few inter-related themes we should pay attention to:
Concretely, in addition to what I observe above, these are my concerns:
On backwards compatibility
This seems to be a running theme in this thread. Now, normally, I’d absolutely 100% agree with the necessity of backwards compatibility. We know better than to piss off our relatively small user base. However, in light of PR #221, big changes are coming: users are going to have to make substantial changes to their templates anyway. Under the present circumstances, I’d argue it’s worth biting the bullet just this once™️ if it means getting this right.
What now?
Unless someone can point to an example of a widely adopted Django tag that has dual open–void usages, I feel some reluctance about adopting the proposed design. I realize it might sound needlessly limiting to say Django tags must be restricted to one usage only, but I believe not doing so might break the assumptions most users have about how Django tags work. Having said that, this does indeed feel like our most backward compatible design as well as the most (IMO) aesthetically pleasing.
My vote would still going to having component be an open tag requiring a closing endcomponent tag and supporting the self-closing/void case by means of a
/
(forward slash) suffix. Unfortunately, this still breaks djhtml, which only looks at the tag + the presence of an ‘end’ prefix…Which leads me to conclude, reluctantly, that the least surprising, most idiomatic, most intercompatible, most future-proof (for e.g. default fills), and potentially more readable option is simply to have component/endcomponent. Full stop.
I mean, I personally prefer this…
… over this…
@timothyis I think you might be onto something. Here’s a summary of what we have so far:
{% component "Heading1" text="Hello world" / %}
{% component "Heading1" text="Hello world" end %}
{% component "Heading1" text="Hello world" with %}
@EmilStenstrom, seeing as your original idea was to make the open–close tag pair the base case (i.e. the first thing new users learn), I’m going to guess you’re less a fan of
with
?I wonder if
end
might be more agreeable? e.g.,Since this follows the Django pattern of using
only
at least, so keywords are a thing.And then this matches the wording/context of
This could also be the other way around (taking GitHub’s Primer example), and using a keyword when there is a block (https://github.com/primer/view_components/blob/main/app/components/primer/button_component.html.erb#L2), e.g.,
And then the non-block variant without the
with
keyword would just stop parsing at the end of the tag.To me, it’s more important that it’s understandable, especially for people seeing the code for the first time. Sure, I think we can add some shortcuts for advanced users, but I think the defaults should be understandable by any Django developer, I think that’s a great target to have in mind.
Is this really so bad? Much simpler not having to care about the two different tags.