Documents
Retention Category Badges: Display and Interactive Behavior
Retention Category Badges: Display and Interactive Behavior
Type
Document
Status
Published
Created
Feb 16, 2026
Updated
Feb 26, 2026
Updated by
Dosu Bot

Retention Category Badges: Display and Interactive Behavior#

Overview#

Retention category badges are visual indicators that display which retention policies apply to backup snapshots. They appear on snapshot timelines and backup details pages, providing users with at-a-glance information about which retention rules are keeping each snapshot.

Retention Categories and Visual Design#

Supported Categories#

The system supports six retention categories, each with distinct color coding:

  • last (latest snapshot): Blue with transparent background (bg-blue-500/20)
  • hourly: Cyan with transparent background (bg-cyan-500/20)
  • daily: Green with transparent background (bg-green-500/20)
  • weekly: Orange with transparent background (bg-orange-500/20)
  • monthly: Purple with transparent background (bg-purple-500/20)
  • yearly: Red with transparent background (bg-red-500/20)

The color scheme uses semi-transparent backgrounds with matching borders, ensuring badges remain visible in both light and dark themes while maintaining visual hierarchy.

Note on Color Consistency: Retention category badges maintain their distinct color palette independent from the application's status indicator colors. While the dashboard redesign updated success indicators from green (bg-green-500) to emerald (bg-emerald-500) for consistency across status displays, the daily retention badge intentionally retains the green color. This preserves the established retention category color scheme and ensures visual differentiation between retention badges (which indicate backup frequency categories) and status indicators (which indicate health states).

Badge Appearance#

Each badge is rendered with consistent styling:

  • Rounded corners for modern appearance
  • Small text size (text-xs) to minimize visual clutter
  • Colored border matching the category color with 30% opacity
  • Category label text with capitalized names ("Last", "Hourly", "Daily", etc.)

Interactive Behavior#

State Management#

The component uses React's useState hook to manage the visibility of the badge popover. This state management was introduced in PR #486 to solve critical mobile interaction issues.

The state management architecture uses a controlled component pattern:

const [open, setOpen] = useState(false);

This open state variable controls whether the popover displaying multiple badges is visible. The component passes both the state and its setter to the HoverCard component, enabling programmatic control over popover visibility.

Single vs. Multiple Badge Display#

The badge component intelligently adapts its display based on the number of retention categories:

Single Category: When a snapshot has only one retention category, the badge displays directly without any interaction required. This provides immediate visual feedback without requiring user action.

Multiple Categories: When multiple categories exist, the component:

  1. Shows a count badge (e.g., "2 tags", "3 tags") to conserve space
  2. Wraps it in an interactive HoverCard that can be triggered by hover or click
  3. Displays all individual badges in a flex-wrapped layout in the expanded view

This progressive disclosure pattern ensures the UI remains clean while providing access to detailed information on demand.

Cross-Device Interaction Handling#

The badge component supports both hover and click interactions, making it functional across all device types:

Desktop (Hover): The HoverCard component automatically shows the expanded badge list when users hover their mouse over the count badge. This provides instant feedback without requiring a click.

Mobile/Touch (Click): An onClick handler explicitly opens the popover when users tap the badge, addressing the hover problem on mobile devices. The handler sets the open state to true, triggering the popover to display.

Improved State Management (PR #486)#

Prior to PR #486, the badges relied solely on hover interactions, making them completely non-functional on touch-based mobile devices where hover events don't exist. The improvements included:

  1. Controlled State: Added open state and onOpenChange props to the HoverCard for programmatic control over visibility
  2. Click Handler: Implemented onClick to set open state to true, enabling tap interactions on mobile
  3. Accessibility: Added aria-label for screen readers announcing "View X retention categories"

These changes transformed the component from desktop-only to truly cross-platform, ensuring users on tablets and phones can access the same information as desktop users.

Category Ordering#

Categories are displayed in a specific retention hierarchy order:

  1. last
  2. hourly
  3. daily
  4. weekly
  5. monthly
  6. yearly

This ordering reflects the retention policy hierarchy from most frequent to least frequent, providing consistent and predictable badge ordering across the application.

Display on Snapshot Timeline#

Integration#

The SnapshotTimeline component displays retention badges for each snapshot in a horizontal scrollable timeline. This timeline provides a chronological view of all snapshots for a backup schedule.

Visual Layout#

Each snapshot card in the timeline includes:

The badges appear consistently positioned at the bottom of each snapshot card, creating a scannable visual pattern that helps users quickly identify which snapshots are retained by which policies.

Data Source#

The timeline receives snapshot data from the API via ListSnapshotsResponse, which includes the retentionCategories array for each snapshot. This data is fetched from the backend where restic's retention analysis determines which categories apply to each snapshot.

Display on Backup Details Page#

Page Structure#

The ScheduleDetailsPage displays the full backup schedule interface, providing comprehensive information about a single backup schedule. The page includes:

  • Schedule summary and controls (enable/disable, run now, etc.)
  • Notification configuration for backup events
  • Mirror repository configuration for replication
  • SnapshotTimeline with retention badges showing all snapshots
  • Snapshot file browser for exploring backup contents

Data Loading#

The page queries snapshots using React Query:

  • Fetches snapshots filtered by backup schedule ID
  • Includes retention categories in the response payload
  • Handles loading and error states gracefully
  • Uses React Query's caching to avoid redundant API calls

The snapshot data flows from the API through React Query into the SnapshotTimeline component, which then renders the RetentionCategoryBadges for each snapshot.

Component Implementation#

Component Props#

The RetentionCategoryBadges component accepts:

  • categories: Array of retention category strings (e.g., ["last", "daily"])
  • className: Optional CSS classes for custom styling and positioning

Rendering Logic#

The component follows a clear rendering flow:

  1. Returns null if no categories - no badges displayed for snapshots without retention categories
  2. Sorts categories by retention hierarchy - ensures consistent ordering
  3. Renders single badge directly if only one category - no interaction needed
  4. Renders interactive HoverCard for multiple categories - enables hover and click interactions

This conditional rendering ensures optimal UX by only introducing interaction complexity when necessary.

Evolution and Improvements#

Initial Implementation (PR #462)#

PR #462 introduced the retention category badges feature to provide visual indicators of retention policy status on snapshots. This initial implementation established the color-coded badge system and integrated it into the snapshot timeline.

Mobile Interaction Fix (PR #486)#

PR #486 addressed a critical usability issue where badges were non-functional on mobile devices due to hover-only interactions. This was a significant accessibility and UX problem, as mobile and tablet users represent a substantial portion of the user base.

The fix introduced proper state management and click handling for cross-device support:

  • Migrated from uncontrolled to controlled component pattern with explicit state management
  • Added onClick handler to trigger popover on touch devices
  • Enhanced accessibility with ARIA labels
  • Maintained backward compatibility with desktop hover interactions

This improvement demonstrates the importance of considering multiple interaction paradigms when building UI components that work across desktop and mobile devices.

Accuracy Improvement (PR #494)#

PR #494 improved the accuracy of retention category determination by:

  • Replacing manual retention calculations with restic's native forget --dry-run operation
  • Updating the "Latest" label to "Last" to align with restic's terminology
  • Adding caching for retention data to improve performance
  • Implementing parallel fetching of snapshots and retention categories

This change prioritized accuracy and consistency with restic's behavior over custom logic, ensuring the badges accurately reflect which snapshots would be kept during a retention operation.