8.4 KiB
Call-to-Action (CTA) Guidelines
This document outlines the standardized patterns for buttons, links, and action elements in ThrillWiki.
Button Hierarchy
Primary Actions
Use for the main action on a page or in a section:
<button class="btn btn-primary">Save Park</button>
<a href="/create/" class="btn btn-primary">Create New</a>
When to use:
- Form submissions
- Main page actions
- Completing a flow
Secondary Actions
Use for important but non-primary actions:
<button class="btn btn-outline">Preview</button>
<button class="btn btn-secondary">Save Draft</button>
When to use:
- Alternative actions
- Non-destructive secondary options
- Cancel with importance
Tertiary Actions
Use for low-emphasis actions:
<button class="btn btn-ghost">Cancel</button>
<a href="/back/" class="btn btn-link">Go Back</a>
When to use:
- Cancel buttons
- Navigation links
- Dismissive actions
Destructive Actions
Use for actions that delete or remove data:
<button class="btn btn-destructive">Delete Park</button>
When to use:
- Delete operations
- Remove actions
- Destructive confirmations
Button Sizes
<!-- Small - for compact UIs -->
<button class="btn btn-primary btn-sm">Small</button>
<!-- Default -->
<button class="btn btn-primary">Default</button>
<!-- Large - for prominent CTAs -->
<button class="btn btn-primary btn-lg">Large</button>
Button States
Loading State
<button class="btn btn-primary" disabled>
<i class="fas fa-spinner fa-spin mr-2"></i>
Saving...
</button>
Disabled State
<button class="btn btn-primary" disabled>
Submit
</button>
With Icon
<button class="btn btn-primary">
<i class="fas fa-plus mr-2"></i>
Add Park
</button>
<button class="btn btn-outline">
Download
<i class="fas fa-download ml-2"></i>
</button>
Action Bar Component
Use the action bar for consistent button placement:
{% include 'components/ui/action_bar.html' with
primary_action_text='Save Changes'
primary_action_icon='fas fa-save'
secondary_action_text='Preview'
tertiary_action_text='Cancel'
tertiary_action_url='/parks/'
%}
Alignment Options
{# Right-aligned (default) #}
{% include 'components/ui/action_bar.html' with align='right' ... %}
{# Left-aligned #}
{% include 'components/ui/action_bar.html' with align='left' ... %}
{# Space-between (cancel left, actions right) #}
{% include 'components/ui/action_bar.html' with align='between' ... %}
{# Center-aligned #}
{% include 'components/ui/action_bar.html' with align='center' ... %}
Placement Guidelines
Page Headers
Primary CTA in page header, aligned right:
{% include 'components/layout/page_header.html' with
title='Parks'
primary_action_url='/parks/create/'
primary_action_text='Add Park'
primary_action_icon='fas fa-plus'
%}
Card Actions
Actions in card footer, right-aligned:
<div class="card">
<div class="card-body">
<!-- Content -->
</div>
<div class="card-footer flex justify-end gap-2">
<button class="btn btn-ghost btn-sm">Cancel</button>
<button class="btn btn-primary btn-sm">Save</button>
</div>
</div>
Form Actions
Form buttons at bottom, with cancel on left or right based on flow:
<!-- Standard form (cancel left, submit right) -->
<div class="flex justify-between mt-6">
<a href="/cancel/" class="btn btn-ghost">Cancel</a>
<button type="submit" class="btn btn-primary">Save</button>
</div>
<!-- Simple form (all right-aligned) -->
<div class="flex justify-end gap-3 mt-6">
<button type="button" class="btn btn-ghost">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
Modal Actions
Actions in modal footer, right-aligned:
<div class="modal-footer">
<button @click="showModal = false" class="btn btn-ghost">
Cancel
</button>
<button class="btn btn-primary">
Confirm
</button>
</div>
Inline Actions
For table rows or list items:
<div class="flex items-center gap-2">
<button class="btn btn-ghost btn-sm">
<i class="fas fa-edit"></i>
</button>
<button class="btn btn-ghost btn-sm text-destructive">
<i class="fas fa-trash"></i>
</button>
</div>
Link vs Button
Use Links For:
- Navigation to other pages
- Opening in new tabs
- Bookmarkable destinations
<a href="/parks/123/" class="btn btn-primary">View Park</a>
Use Buttons For:
- Form submissions
- JavaScript actions
- State changes
- Toggles
<button type="submit" class="btn btn-primary">Save</button>
<button @click="showModal = true" class="btn btn-outline">Open Modal</button>
Icon Guidelines
Icon Position
- Left icon: For actions (Add, Create, Save)
- Right icon: For navigation (Next, Go, External link)
<!-- Action with left icon -->
<button class="btn btn-primary">
<i class="fas fa-plus mr-2"></i>
Add Park
</button>
<!-- Navigation with right icon -->
<a href="/next/" class="btn btn-outline">
Next Step
<i class="fas fa-arrow-right ml-2"></i>
</a>
Common Icon Mappings
| Action | Icon |
|---|---|
| Create/Add | fa-plus |
| Edit | fa-edit or fa-pen |
| Delete | fa-trash |
| Save | fa-save |
| Cancel | fa-times |
| Search | fa-search |
| Filter | fa-filter |
| Download | fa-download |
| Upload | fa-upload |
| Settings | fa-cog |
| Back | fa-arrow-left |
| Next | fa-arrow-right |
| External Link | fa-external-link-alt |
Confirmation Patterns
Inline Confirmation (Low Risk)
<button hx-delete="/items/123/"
hx-confirm="Delete this item?">
Delete
</button>
Modal Confirmation (High Risk)
<button @click="showDeleteModal = true" class="btn btn-destructive">
Delete Park
</button>
{% include 'components/modals/modal_confirm.html' with
modal_id='delete-confirm'
show_var='showDeleteModal'
title='Delete Park'
message='This will permanently delete the park and all associated data. This action cannot be undone.'
confirm_text='Delete'
confirm_variant='destructive'
confirm_hx_delete='/parks/123/'
%}
Responsive Behavior
Mobile Stacking
Buttons stack vertically on mobile:
<div class="flex flex-col sm:flex-row gap-3">
<button class="btn btn-ghost order-2 sm:order-1">Cancel</button>
<button class="btn btn-primary order-1 sm:order-2">Save</button>
</div>
Icon-Only on Mobile
<button class="btn btn-outline">
<i class="fas fa-filter"></i>
<span class="hidden sm:inline ml-2">Filter</span>
</button>
Full-Width on Mobile
<button class="btn btn-primary w-full sm:w-auto">
Save Changes
</button>
Accessibility
Button Labels
Always provide accessible labels:
<!-- Icon-only buttons need aria-label -->
<button class="btn btn-ghost" aria-label="Edit park">
<i class="fas fa-edit" aria-hidden="true"></i>
</button>
<!-- Or use visually hidden text -->
<button class="btn btn-ghost">
<i class="fas fa-edit" aria-hidden="true"></i>
<span class="sr-only">Edit park</span>
</button>
Focus States
All buttons must have visible focus states:
.btn:focus {
outline: none;
ring: 2px;
ring-offset: 2px;
ring-color: var(--ring);
}
Keyboard Navigation
Ensure buttons are keyboard accessible:
<!-- Use native button elements -->
<button class="btn btn-primary">Click Me</button>
<!-- If using div/span, add role and tabindex -->
<div role="button" tabindex="0" class="btn btn-primary"
@keydown.enter="handleClick"
@keydown.space.prevent="handleClick">
Click Me
</div>
HTMX Integration
Loading Indicators
Show loading state during requests:
<button hx-post="/save/"
hx-indicator="this"
class="btn btn-primary">
<span class="htmx-indicator hidden">
<i class="fas fa-spinner fa-spin mr-2"></i>
</span>
Save
</button>
Disable During Request
<button hx-post="/save/"
hx-disabled-elt="this"
class="btn btn-primary">
Save
</button>
Success Feedback
# In view
from apps.core.htmx_utils import htmx_success
def save_item(request):
# ... save logic ...
return htmx_success('Item saved successfully!')