Components
Components are the core building block of django-palette. Learn how to create and use them effectively.
What is a Component?
A component is a reusable piece of UI defined once and rendered multiple times with different data. It’s similar to a function in programming - you define it once, then call it with different arguments.
Basic Structure:
{% palette_component component_name %}
<!-- HTML structure with blocks -->
{% palette_block block_name %}
Default content
{% endpalette_block %}
{% endpalette_component %}
Then render it:
{% palette_ui file="path/to/template.html" component="component_name" with var1=value1 %}
Why Use Components?
Don’t Repeat Yourself (DRY)
Define a card once, use it 10 times:
{% palette_ui file="palette/components/card.html" component="card" with title="Users" value="1,234" %}
{% palette_ui file="palette/components/card.html" component="card" with title="Orders" value="567" %}
{% palette_ui file="palette/components/card.html" component="card" with title="Revenue" value="$89,000" %}
Consistency
All instances look and behave the same way.
Maintainability
Change the component once, all instances are updated.
Flexibility
Override specific parts when needed without duplicating code.
Creating Your First Component
Let’s create a simple card component.
Step 1: Create the Template File
Create templates/components/card.html:
{% load palette %}
{% palette_component card %}
<div class="card border-0 shadow-sm">
<div class="card-body">
{% palette_block content %}
<h5 class="card-title">{{ title }}</h5>
<p class="card-text">{{ description }}</p>
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Step 2: Include in Your Base Template
Include it in your base template (e.g., templates/admin/base_site.html):
{% include "components/card.html" %}
Step 3: Use the Component
In any template:
{% load palette %}
{% include "components/card.html" %}
{% palette_ui file="palette/components/card.html" component="card" with title="My Card" description="This is a card" %}
That’s it! Your component is now reusable.
Component Design Patterns
Pattern 1: Simple Display Card
A card that displays information:
{% palette_component info_card %}
<div class="card">
<div class="card-body">
{% palette_block header %}
<h5>{{ title }}</h5>
{% endpalette_block %}
{% palette_block body %}
<p>{{ content }}</p>
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Usage:
{% palette_ui file="palette/components/card.html" component="info_card" with title="Welcome" content="Hello, user!" %}
Pattern 2: Statistics Card
Display metrics or statistics:
{% palette_component stat_card %}
<div class="card text-center border-0">
<div class="card-body">
{% palette_block metric %}
<h2 class="display-4 text-primary">{{ value }}</h2>
{% endpalette_block %}
{% palette_block label %}
<p class="text-muted">{{ label }}</p>
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Usage:
{% palette_ui file="palette/components/card.html" component="stat_card" with value="1,234" label="Total Users" %}
Pattern 3: Action Card
A card with buttons or actions:
{% palette_component action_card %}
<div class="card">
<div class="card-body">
{% palette_block title %}
<h5>{{ title }}</h5>
{% endpalette_block %}
{% palette_block content %}
<p>{{ content }}</p>
{% endpalette_block %}
{% palette_block actions %}
<a href="{{ url }}" class="btn btn-primary">{{ button_text }}</a>
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Usage:
{% palette_ui file="palette/components/card.html" component="action_card" with title="Create New User" content="Add a new user to the system" button_text="Create User" url="/admin/auth/user/add/" %}
Pattern 4: List Item Component
Items within a list:
{% palette_component list_item %}
<div class="list-group-item">
<div class="d-flex justify-content-between">
{% palette_block main %}
<div>
<h6>{{ title }}</h6>
<small class="text-muted">{{ subtitle }}</small>
</div>
{% endpalette_block %}
{% palette_block meta %}
<span class="badge">{{ status }}</span>
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Usage:
{% palette_ui file="palette/components/card.html" component="list_item" with title="User Name" subtitle="Email" status="Active" %}
Best Practices
1. Name Components Semantically
Good names:
- card - Generic card
- stat_card - Statistics display
- user_profile - User profile
- action_button - Action button
Bad names:
- component1 - Not descriptive
- tmp - Temporary names
- foo - Meaningless
2. Use Clear Block Names
Good block names:
- header - Header section
- content - Main content
- footer - Footer section
- actions - Action buttons
- metadata - Additional info
3. Provide Sensible Defaults
Every block should have useful default content:
{% palette_block "content" %}
<p>Default content</p>
{% endpalette_block %}
4. Use Variables Effectively
Pass all data as variables, don’t hardcode:
<!-- Good -->
{% palette_ui file="palette/components/card.html" component="card" with title=my_title content=my_content %}
<!-- Bad -->
{% palette_ui file="palette/components/card.html" component="card" with title="Hard coded" %}
5. Keep Components Focused
Each component should do one thing well:
<!-- Good: Card component doing card things -->
{% palette_component card %}
<div class="card">
<!-- card HTML -->
</div>
{% endpalette_component %}
<!-- Bad: Card component doing too much -->
{% palette_component card %}
<div class="card">
<!-- card HTML -->
<table><!-- table inside card --></table>
<form><!-- form inside card --></form>
</div>
{% endpalette_component %}
6. Make Components Reusable
Design components for multiple use cases:
{% palette_component alert %}
<div class="alert alert-{{ type }}">
{% palette_block icon %}
<i class="bi bi-{{ icon }}"></i>
{% endpalette_block %}
{% palette_block message %}
<strong>{{ title }}</strong>
<p>{{ message }}</p>
{% endpalette_block %}
</div>
{% endpalette_component %}
Then use it for any alert:
{% palette_ui file="palette/components/alert.html" component="alert" with type="info" icon="info-circle" title="Info" message="This is information" %}
{% palette_ui file="palette/components/alert.html" component="alert" with type="success" icon="check-circle" title="Success" message="Operation successful" %}
{% palette_ui file="palette/components/alert.html" component="alert" with type="danger" icon="x-circle" title="Error" message="Something went wrong" %}
Organization
Directory Structure:
templates/
├── admin/
│ ├── base_site.html
│ └── ... other admin templates
├── components/
│ ├── card.html
│ ├── stat_card.html
│ ├── alert.html
│ ├── list_item.html
│ └── ... other components
└── ... other templates
Include All Components
In your base template:
{% include "components/card.html" %}
{% include "components/stat_card.html" %}
{% include "components/alert.html" %}
{% include "components/list_item.html" %}
Advanced Techniques
Nesting Components
Use components inside other components:
{% palette_component dashboard %}
<div class="dashboard">
{% palette_block stats %}
{% palette_ui file="palette/components/card.html" component="stat_card" with value="100" label="Stat 1" %}
{% palette_ui file="palette/components/card.html" component="stat_card" with value="200" label="Stat 2" %}
{% palette_ui file="palette/components/card.html" component="stat_card" with value="300" label="Stat 3" %}
{% endpalette_block %}
</div>
{% endpalette_component %}
Conditional Content
Use Django conditionals inside components:
{% palette_component user_card %}
<div class="card">
<div class="card-body">
{% palette_block name %}
{{ user.get_full_name }}
{% endpalette_block %}
{% palette_block actions %}
{% if user.is_staff %}
<a href="..." class="btn btn-danger">Demote</a>
{% else %}
<a href="..." class="btn btn-info">Promote</a>
{% endif %}
{% endpalette_block %}
</div>
</div>
{% endpalette_component %}
Loops in Components
Iterate within components:
{% palette_component member_list %}
<ul class="list-group">
{% palette_block items %}
{% for member in members %}
{% palette_ui file="palette/components/card.html" component="list_item" with title=member.name subtitle=member.email %}
{% endfor %}
{% endpalette_block %}
</ul>
{% endpalette_component %}
Complex Blocks
Blocks can contain complex HTML:
{% palette_block footer %}
<div class="card-footer">
<div class="row">
<div class="col">
<span>{{ created_at|date:"Y-m-d" }}</span>
</div>
<div class="col text-end">
<a href="{{ edit_url }}" class="btn btn-sm btn-outline-primary">Edit</a>
</div>
</div>
</div>
{% endpalette_block %}
Real-World Examples
See Examples for complete, production-ready component examples.