Component Development Quick Start
What You Need to Know
MintyFlask components combine semantic CSS classes with Jinja2 macros to create reusable, configurable UI elements. Think of them as building blocks you can use across your site.
Two types of components:
- CSS Components - Semantic classes (
.card-base,.btn-base) - Macro Components - Jinja2 templates with logic
Most of the time, you'll use existing CSS components and occasionally create macros to orchestrate them.
The Core Component Pattern
CSS Component (Foundation)
/* Semantic classes in @layer components */
@layer components {
.card-base {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
}
.card-title {
font-size: var(--text-xl);
font-weight: 600;
margin-bottom: var(--spacing-sm);
}
}
Using in Templates
<!-- Direct usage -->
<div class="card-base">
<h3 class="card-title">My Card</h3>
<p class="card-description">Card content here...</p>
</div>
Macro Component (Optional Layer)
{# macros.html #}
{% macro simple_card(title, content) %}
<div class="card-base">
<h3 class="card-title">{{ title }}</h3>
<p class="card-description">{{ content }}</p>
</div>
{% endmacro %}
{# In your template #}
{% from "macros.html" import simple_card %}
{{ simple_card("My Card", "Card content here...") }}
Using Existing CSS Components
MintyFlask provides CSS component classes you can use directly.
Cards
<!-- Basic card -->
<div class="card-base card-intent-content card-size-md">
<div class="card-header">
<h3 class="card-title">Card Title</h3>
</div>
<div class="card-body">
<p class="card-description">Card content...</p>
</div>
<div class="card-footer">
<div class="card-actions">
<button class="btn-base btn-intent-primary btn-size-sm">Action</button>
</div>
</div>
</div>
Buttons
<!-- Primary button -->
<button class="btn-base btn-intent-primary btn-size-md">Click Me</button>
<!-- Secondary button with icon -->
<button class="btn-base btn-intent-secondary btn-size-sm btn-icon-left">
<svg><!-- icon --></svg>
With Icon
</button>
Badges
<!-- Info badge -->
<span class="badge-base badge-intent-info badge-size-sm"> New </span>
<!-- Warning badge -->
<span class="badge-base badge-intent-warning badge-size-md"> Beta </span>
Component Naming Pattern
All components follow a consistent pattern:
{component}-{element}--{modifier}
Examples:
.card-base # Base component
.card-title # Component element
.card-intent-primary # Intent modifier
.card-size-lg # Size modifier
The pattern:
- Base class -
.card-base,.btn-base,.badge-base - Element classes -
.card-title,.card-body,.btn-icon - Intent modifiers -
.card-intent-primary,.btn-intent-secondary - Size modifiers -
.card-size-sm,.btn-size-lg - State modifiers -
.btn-style-ghost,.card-clickable
Creating Your First Macro
Let's create a reusable alert component.
Step 1: Use Existing CSS Components
<!-- This works, but repetitive -->
<div class="card-base card-intent-warning card-size-md">
<div class="card-body"><strong>Warning:</strong> This is important!</div>
</div>
Step 2: Create a Macro
{# components/alerts.html #}
{% macro alert(message, type="info") %}
<div class="card-base card-intent-{{ type }} card-size-md" role="alert">
<div class="card-body">
{% if type == "warning" %}
<strong>Warning:</strong>
{% elif type == "error" %}
<strong>Error:</strong>
{% elif type == "success" %}
<strong>Success:</strong>
{% endif %}
{{ message }}
</div>
</div>
{% endmacro %}
Step 3: Use Your Macro
{# In your template #}
{% from "components/alerts.html" import alert %}
{{ alert("This is important!", type="warning") }}
{{ alert("Everything worked!", type="success") }}
{{ alert("Something went wrong.", type="error") }}
Creating Mixin Components
When building a mixin (like a blog feature), create CSS components:
/* mixins/blog/static/css/blog.css */
@layer components {
/* Post card base */
.blog-post-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
}
/* Post card elements */
.blog-post-title {
font-size: var(--text-xl);
font-weight: 600;
margin-bottom: var(--spacing-sm);
}
.blog-post-excerpt {
color: var(--color-text-secondary);
margin-bottom: var(--spacing-md);
}
/* Post card meta */
.blog-post-meta {
display: flex;
gap: var(--spacing-md);
font-size: var(--text-sm);
color: var(--color-text-tertiary);
}
}
Template usage:
<article class="blog-post-card">
<h2 class="blog-post-title">
<a href="/post/slug">Post Title</a>
</h2>
<p class="blog-post-excerpt">Brief summary of the post...</p>
<div class="blog-post-meta">
<time>November 25, 2024</time>
<span>5 min read</span>
</div>
</article>
Component Variants
Use modifier classes for variations:
<!-- Size variants -->
<button class="btn-base btn-intent-primary btn-size-sm">Small</button>
<button class="btn-base btn-intent-primary btn-size-md">Medium</button>
<button class="btn-base btn-intent-primary btn-size-lg">Large</button>
<!-- Intent variants -->
<div class="card-base card-intent-content">Content Card</div>
<div class="card-base card-intent-feature">Feature Card</div>
<div class="card-base card-intent-info">Info Card</div>
<!-- Combined variants -->
<button class="btn-base btn-intent-secondary btn-size-lg btn-style-ghost">
Ghost Button
</button>
Quick Component Examples
Hero Section
<div class="hero-section">
<h1 class="text-3xl font-bold mb-4">Welcome</h1>
<p class="text-lg text-slate-600 dark:text-stone-400 mb-6">
Get started with MintyFlask
</p>
<button class="btn-base btn-intent-primary btn-size-lg btn-icon-right">
Get Started
<svg class="w-5 h-5"><!-- arrow icon --></svg>
</button>
</div>
Navigation Links
<nav class="flex gap-4">
<a
href="/about"
class="btn-base btn-intent-secondary btn-size-sm btn-style-ghost"
>
About
</a>
<a
href="/contact"
class="btn-base btn-intent-secondary btn-size-sm btn-style-ghost"
>
Contact
</a>
<a href="/blog" class="btn-base btn-intent-primary btn-size-sm"> Blog </a>
</nav>
Info Box
<div class="card-base card-intent-info card-size-md">
<div class="card-header">
<h3 class="card-title">Did You Know?</h3>
</div>
<div class="card-body">
<p class="card-description">
MintyFlask uses semantic CSS components for consistency.
</p>
</div>
</div>
Dark Mode Support
All components automatically support dark mode through CSS variables:
@layer components {
.blog-post-card {
background: var(--color-surface);
border-color: var(--color-border);
color: var(--color-text-primary);
}
/* Variables change automatically in dark mode */
/* No extra code needed! */
}
Just ensure you use CSS custom properties instead of hardcoded colours.
Common Patterns
Pattern 1: Direct CSS Usage
<!-- Best for simple, one-off components -->
<div class="card-base card-intent-content card-size-md">
<div class="card-body">
<h3 class="card-title">Simple Card</h3>
</div>
</div>
Pattern 2: Macro Wrapper
<!-- Best for repetitive components with logic -->
{% macro feature_card(title, description, icon) %}
<div class="card-base card-intent-feature card-size-lg">
<div class="card-header">
<div class="text-4xl mb-4">{{ icon }}</div>
<h3 class="card-title">{{ title }}</h3>
</div>
<div class="card-body">
<p class="card-description">{{ description }}</p>
</div>
</div>
{% endmacro %}
Pattern 3: Partial Include
<!-- Best for complex, reusable layouts -->
{% for post in posts %} {% include "partials/post-card.html" %} {% endfor %}
When to Create a Macro
Create a macro when:
- Component is used in multiple places
- Component has conditional logic
- Component needs configuration parameters
- You want consistent structure
Don't create a macro when:
- Component is used once
- Simple CSS classes are sufficient
- No logic or parameters needed
Troubleshooting
Component styles not applying
Check:
- Is the CSS file imported in
input.css? - Are styles in the correct
@layer? - Are you using the right class names?
/* Make sure CSS is imported */
@layer components {
@import "../../mixins/blog/static/css/blog.css";
}
Macro not found
Check:
- Is import path correct?
- Did you add
with contextif using Flask functions?
{# Wrong #}
{% from "alerts.html" import alert %}
{# Right #}
{% from "components/alerts.html" import alert with context %}
Variables not working
Check:
- Are you using CSS custom properties?
- Are variables defined in
:rootor.dark?
/* Wrong */
.card {
color: #333;
}
/* Right */
.card {
color: var(--color-text-primary);
}
Next Steps
You now know how to use and create components. For more details:
- Component Development User Guide - Advanced patterns and techniques
- CSS Architecture Quick Start - Understanding the layer system
Summary
Remember:
- Use semantic CSS -
.card-base,.btn-base,.badge-base - Combine with modifiers -
.card-intent-primary,.btn-size-lg - Create macros for logic - When components need parameters or conditions
- Use CSS variables - Always use
var(--token)not hardcoded values - Prefix mixin components -
.blog-card, not.card
With these patterns, you can build consistent, maintainable components across your site.