Files
thrillwiki_django_no_react/docs/ux/cta-guidelines.md

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>
  • 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!')