When to Use
Decision guidance for choosing the right component. When two components look similar, this guide helps you pick the correct one.
Badge vs Status vs Category
All three render as small labels but serve different purposes.
| Component | Use For | Example |
|---|---|---|
Badge ws_badge() |
Generic metadata labels, counts, small tags | ws_badge('NEW', ['variant' => 'new']) |
Status ws_status() |
State indicators with semantic colors (success, warning, error, info) | ws_status('Completed', 'success') |
Category ws_category() |
Content type labels with custom colors matching the category palette | ws_category('Ideation', '#F59E0B') |
Duration ws_duration() |
Time durations with clock icon | ws_duration('45 min') |
info
ws_status(), ws_category(), and ws_duration() are all convenience wrappers around ws_badge(). They set the right variant and styling automatically.Alert vs Toast
| Component | Use For | Persistence | Position |
|---|---|---|---|
Alert ws_alert() |
Contextual messages that relate to page content — warnings, errors, info banners | Persistent (stays in page flow) | Inline with content |
Toast wsToastSuccess() |
Feedback from user actions — save confirmations, error responses, status changes | Auto-dismiss (3–5 seconds) | Fixed overlay (bottom-right) |
Use Alert for:
Form validation summaries, permission warnings, feature announcements, important notices that need to stay visible.
Use Toast for:
"Saved!", "Copied to clipboard", "Item added to collection", "Error: try again" — transient feedback the user can miss.
Card vs Feature Card vs Listing Card
| Component | Use For | Key Difference |
|---|---|---|
Card ws_card_start() |
Generic content containers — wraps any content with border, padding, optional hover | No predefined layout; you build the inside |
Feature Card ws_feature_card() |
Marketing feature/benefit grids — icon + title + description | Fixed icon-title-description structure |
Listing Card ws_listing_card() |
Content library items — workshops, exercises, icebreakers | Has category icon, duration, footer actions, links to detail page |
Section Header vs Hero
| Component | Use For | Scale |
|---|---|---|
Hero ws_hero() |
Page-level hero with badge, title, subtitle, buttons, stats, and optional image | Full-width, top of page only |
Section Header ws_section_header() |
Section titles within a page — features, content areas, form sections | Contained width, repeated within page |
Use Hero for:
Landing page tops, app homepage, any page that needs a prominent call-to-action area.
Use Section Header for:
"Features" section headings, "Related Workshops" headers, form group labels — anything mid-page.
Input vs Form Row
| Component | Use For |
|---|---|
Input ws_input() |
The raw field element. Has its own label option for simple cases. Use standalone when you need just a field. |
Form Row ws_form_row() |
A layout wrapper. Use when building multi-field forms that need consistent spacing, external labels, helper text, or error messages. Wraps any field (input, select, textarea). |
Modal (Center) vs Modal (Drawer)
| Variant | Use For |
|---|---|
Center Modal variant: 'center' |
Confirmations, alerts, small forms, focused content. User must acknowledge before continuing. |
Drawer variant: 'drawer' |
Side panels for settings, filters, detail views. Can be used alongside main content. |
Progress vs Skeleton
| Component | Use For |
|---|---|
Progress ws_progress() |
Known progress percentage (uploads, form completion, step progress). Shows a determinate bar or indeterminate spinner. |
Skeleton ws_skeleton() |
Content loading placeholders. Shows the shape of incoming content (text lines, avatars, cards) while data loads. |