Skip to content

Commit aad9022

Browse files
add more documentation
1 parent e7c82fc commit aad9022

File tree

9 files changed

+948
-228
lines changed

9 files changed

+948
-228
lines changed

README.md

Lines changed: 25 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,23 @@ In `button.html`, create a simple HTML button. Use `{{ slot }}` to indicate wher
7373
```htmldjango
7474
{# templates/bird/button.html #}
7575
<button>
76-
{{ slot }}
76+
{{ slot }}
7777
</button>
7878
```
7979

8080
To use your component in a Django template, use the `{% bird %}` templatetag. The content between `{% bird %}` and `{% endbird %}` becomes the `{{ slot }}` content.
8181

8282
```htmldjango
8383
{% bird button %}
84-
Click me!
84+
Click me!
8585
{% endbird %}
8686
```
8787

8888
django-bird automatically recognizes components in the bird directory, so no manual registration is needed. When Django processes the template, django-bird replaces the `{% bird %}` tag with the component's HTML, inserting the provided content into the slot, resulting in:
8989
9090
```html
9191
<button>
92-
Click me!
92+
Click me!
9393
</button>
9494
```
9595
@@ -108,240 +108,37 @@ For a full overview of the features and configuration options, please refer to t
108108
109109
## Motivation
110110
111-
## Roadmap
111+
<!-- docs-motivation-begin -->
112+
Several excellent libraries for creating components in Django exist:
112113
113-
Below are a bunch of features I'd like to bring to django-bird.
114+
- [django-components](https://github.com/EmilStenstrom/django-components)
115+
- [django-cotton](https://github.com/wrabit/django-cotton)
116+
- [django-unicorn](https://github.com/adamghill/django-unicorn)
117+
- [django-viewcomponent](https://github.com/rails-inspire-django/django-viewcomponent)
118+
- [django-web-components](https://github.com/Xzya/django-web-components)
119+
- [slippers](https://github.com/mixxorz/slippers)
114120
115-
I have included code snippets where applicable, but they are back-of-the-napkin sketches of potential APIs -- subject to change if and when the feature is actually introduced.
121+
In particular, django-components is full-featured and will take you far, while django-unicorn offers a novel approach to adding interactivity to Django projects without a full JavaScript framework.
116122
117-
### Static Asset Collection
123+
> [!NOTE]
124+
> Also worth mentioning is [django-template-partials](https://github.com/carltongibson/django-template-partials) from Carlton Gibson. While not a full component library, it allows defining reusable chunks in a Django template, providing a lightweight approach to reusability.
118125
119-
This is table stakes for a modern Django template component library. The goal is to allow you to define CSS and JS for a component and have it loaded automatically when you use that component.
126+
**So, why another Django component library?**
120127
121-
Unlike django-components, which uses the Django forms library pattern with a `class Media` declaration, the idea is to allow defining styles and scripts within a single component file, or adjacent to a component. django-bird would then collect and compile these assets, streamlining the whole process.
128+
The libraries mentioned above are excellent in their own right, each solving specific problems in innovative ways. Most focus on defining components on the Python side, which works for many use cases. For those focusing on the HTML and Django template side, they have made significant strides in improving the developer experience. However, as a developer with strong opinions (sometimes loosely held 😄) about API design, I wanted a different approach.
122129
123-
Here's a potential example of how you might define a button component with inline styles and scripts:
130+
After watching Caleb Porzio's [2024 Laracon US talk](https://www.youtube.com/watch?v=31pBMi0UdYE) introducing [Flux](https://fluxui.dev), I could not shake the desire to bring something similar to Django. While there are plenty of libraries such as Shoelace or UI kits designed for use in any web application, and tools like SaaS Pegasus for whole Django project generation, I couldn't find a well-polished component library solely dedicated to Django templates with the level of polish that Flux has for Laravel.
124131
125-
```htmldjango
126-
{# templates/bird/button.html #}
127-
<button>
128-
{{ slot }}
129-
</button>
130-
<style>
131-
button {
132-
background-color: red;
133-
padding: 10px 20px;
134-
color: white;
135-
border: none;
136-
cursor: pointer;
137-
}
138-
</style>
139-
<script>
140-
$bird.addEventListener('click', () => {
141-
alert('This specific button was clicked!');
142-
});
143-
</script>
144-
```
145-
146-
The `$bird` variable in the JavaScript is a potential special identifier that could be used to scope the script to the specific component instance.
147-
148-
Alternatively, you could potentially separate the styles and scripts into their own files:
149-
150-
```htmldjango
151-
{# templates/bird/button.html #}
152-
<button>
153-
{{ slot }}
154-
</button>
155-
```
156-
157-
```css
158-
/* templates/bird/button.css */
159-
button {
160-
background-color: red;
161-
padding: 10px 20px;
162-
color: white;
163-
border: none;
164-
cursor: pointer;
165-
}
166-
```
167-
168-
```javascript
169-
// templates/bird/button.js
170-
$bird.addEventListener('click', () => {
171-
alert('This specific button was clicked!');
172-
});
173-
```
174-
175-
To use this component and include its assets in your template, the API might look something like this:
176-
177-
```htmldjango
178-
<html>
179-
<head>
180-
{% django_bird_css %}
181-
</head>
182-
<body>
183-
{% bird button %}
184-
Click me
185-
{% endbird %}
186-
187-
{% django_bird_js %}
188-
</body>
189-
</html>
190-
```
191-
192-
In this conceptual setup, `{% django_bird_css %}` and `{% django_bird_js %}` would automatically include the collected and compiled CSS and JavaScript for all components used in the template.
193-
194-
To give you an idea of what the final compiled output might look like, here's a hypothetical example of the HTML that could be generated:
195-
196-
```htmldjango
197-
<html>
198-
<head>
199-
<style>
200-
[data-bird-id="button-1"] {
201-
background-color: red;
202-
padding: 10px 20px;
203-
color: white;
204-
border: none;
205-
cursor: pointer;
206-
}
207-
</style>
208-
</head>
209-
<body>
210-
<button data-bird-id="button-1">
211-
Click me
212-
</button>
213-
214-
<script>
215-
(function() {
216-
const $bird = document.querySelector('[data-bird-id="button-1"]');
217-
$bird.addEventListener('click', () => {
218-
alert('This specific button was clicked!');
219-
});
220-
})();
221-
</script>
222-
</body>
223-
</html>
224-
```
225-
226-
### Component Islands
227-
228-
Ever since I tried Astro and discovered their concept of "Islands" (which they popularized but didn't invent), I've wanted to bring this to Django.
229-
230-
If you're new to component islands, think of it as fancy lazy-loading. You can set different triggers for when a component's JS assets load (on page load, on idle, on scroll into view). When that event fires, only the necessary assets are loaded.
231-
232-
There's a neat library from the 11ty team called is-land that could work well here. I'll probably start by integrating it directly, but after looking at their source code, I might end up bringing it in and customizing it for django-bird's specific needs.
233-
234-
Here's how the API for component islands might look in django-bird:
235-
236-
```htmldjango
237-
{% bird button on="load" %}
238-
This button loads... on load
239-
{% endbird %}
240-
241-
{% bird button on="idle" %}
242-
This button loads after page load
243-
{% endbird %}
244-
245-
{% bird button on="visible" %}
246-
This button loads when scrolled into view
247-
{% endbird %}
248-
```
249-
250-
In this example, we're using an `on` attribute to specify when each button's JavaScript should be loaded and executed. This approach could significantly improve page load times and performance, especially for pages with many interactive components.
251-
252-
### Custom HTML Tag
253-
254-
I'm a huge fan of the approaches taken by libraries like [django-cotton](https://github.com/wrabit/django-cotton), [dj-angles](https://github.com/adamghill/dj-angles), and Laravel's [Flux](https://fluxui.dev). They let you use custom HTML-like elements that compile down to native templatetags during loading.
255-
256-
This gives you the full power of Django's template language, but in a much nicer package. Compare [this django-allauth template](https://github.com/pennersr/django-allauth/blob/f03ff4dd48e5b1680a57dca56617bf94c928f2cf/allauth/templates/account/email.html) with [these django-cotton examples](https://github.com/wrabit/django-cotton#walkthrough). The allauth template, while powerful, is a mess of tags that barely resembles HTML. The cotton templates, on the other hand, look like clean, custom web elements.
257-
258-
After working with devs from the JavaScript world and using a handful of JavaScript frameworks myself, Django templates can feel ancient compared to JSX. A custom HTML tag approach could offer a more familiar and readable syntax for component-based development in Django, bridging the gap between traditional Django templates and modern frontend practices.
259-
260-
Here's a comparison of how a button component might be used with the current django-bird syntax and a potential custom HTML tag syntax:
261-
262-
```htmldjango
263-
{% bird button %}
264-
Click me
265-
{% endbird %}
266-
267-
<bird:button>
268-
Click me
269-
</bird:button>
270-
```
271-
272-
### Scoped CSS Styles
273-
274-
I love how Svelte and other JS frameworks let you use a simple `<style>` tag with broad selectors (`p` instead of `.card-body`, `button` instead of `.submit-btn`), then scope those styles to just that component. While I'm a Tailwind CSS fan, having this escape hatch for quick style tweaks would be fantastic.
275-
276-
Here's how a component with scoped styles might look in django-bird:
277-
278-
```htmldjango
279-
{# templates/bird/button.html #}
280-
<button>
281-
{{ slot }}
282-
</button>
283-
<style>
284-
button {
285-
background-color: red;
286-
}
287-
</style>
288-
```
289-
290-
You would use this component in your template like this:
291-
292-
```htmldjango
293-
<html>
294-
<head>
295-
{% django_bird_css %}
296-
</head>
297-
<body>
298-
{% bird button %}
299-
Click me
300-
{% endbird %}
301-
</body>
302-
</html>
303-
```
304-
305-
And here's a potential example of how django-bird might compile this to ensure the styles are scoped to just this component:
132+
Initially, I considered contributing to existing libraries or wrapping one to add the functionality I wanted. However, I decided to create a new library for several reasons:
306133
307-
```htmldjango
308-
<html>
309-
<head>
310-
<style>
311-
#bird-12fdsa33 {
312-
button {
313-
background-color: red;
314-
}
315-
}
316-
</style>
317-
</head>
318-
<body>
319-
<button id="bird-12fdsa33">
320-
Click me
321-
</button>
322-
</body>
323-
</html>
324-
```
134+
1. I wanted to respect the hard work of existing maintainers and avoid burdening them with features that may not align with their project's goals.
135+
2. While wrapping an existing library might have been technically feasible and okay license-wise, it didn't feel right to build an entire component system on top of someone else's work, especially for a project I might want to develop independently in the future.
136+
3. Building something new gives me the freedom to fully control the direction and architecture, without being constrained by design choices made in other libraries.
137+
4. Healthy competition among libraries helps drive innovation, and I see this as an opportunity to contribute to the broader Django ecosystem.
138+
5. Recent libraries like [django-cotton](https://github.com/wrabit/django-cotton) and [dj-angles](https://github.com/adamghill/dj-angles) are pushing Django templates in new and exciting directions and I wanted to join in on the fun. 😄
139+
<!-- docs-motivation-end -->
325140

326-
### Integration with Tailwind CSS
327-
328-
Hot 🔥 take: if you're using Tailwind, you should ditch most of Tailwind's atomic classes and write your styles in a CSS file (shocking, I know!), but process it with Tailwind. This gives you modern CSS power without the atomic class juggling, plus you still get to use Tailwind's awesome design system -- which in my mind is _the_ reason to use Tailwind CSS. I could take or leave the atomic styles, but that design system I cannot develop without.
329-
330-
I'd love for django-bird components to support this workflow, letting you write clean, Tailwind-processed styles right in your components.
331-
332-
Here's how a button component using Tailwind's design system might look in django-bird:
333-
334-
```htmldjango
335-
{# templates/bird/button.html #}
336-
<button>
337-
{{ slot }}
338-
</button>
339-
<style>
340-
button {
341-
background-color: theme("colors.red.500");
342-
}
343-
</style>
344-
```
141+
See the [ROADMAP](ROADMAP.md) for planned features and future direction of django-bird.
345142

346143
## License
347144

0 commit comments

Comments
 (0)