CSS-Only

Widget

Draggable and resizable dashboard widget container with container queries for responsive content. Supports size variants, interactive states, and performance-optimized drag/resize operations.

Example

Sales Overview

Widget content goes here. The container uses CSS container queries to adapt to its own size, not the viewport.

Quick Stats

Small widget with compact padding.

<div class="omni-widget">
  <div class="omni-widget-header">
    <h3 class="omni-widget-title">Sales Overview</h3>
    <div class="omni-widget-actions">
      <button class="omni-button" data-type="icon" aria-label="Settings">...</button>
    </div>
  </div>
  <div class="omni-widget-content">
    Widget content...
  </div>
  <div class="omni-widget-footer">
    Last updated: 2 hours ago
  </div>
</div>

Structure

A widget consists of four main parts:

Header (Required)

Contains the widget title and optional action buttons. Includes a drag handle for repositioning.

<div class="omni-widget-header">
  <h3 class="omni-widget-title">Widget Title</h3>
  <div class="omni-widget-actions">
    <!-- Action buttons -->
  </div>
  <div class="omni-widget-handle" aria-label="Drag widget"></div>
</div>

Content (Required)

Main content area with automatic scrolling when content overflows.

<div class="omni-widget-content">
  <!-- Your content here -->
</div>

Footer (Optional)

Bottom section for metadata or additional actions.

<div class="omni-widget-footer">
  Last updated: 2 hours ago
</div>

Resize Handle (Optional)

Bottom-right corner handle for resizing the widget.

<div class="omni-widget-resize" aria-label="Resize widget"></div>

Sizes

Use data-size to adjust widget padding and typography:

Small Widget

Compact padding for dense dashboards.

Medium Widget (Default)

Balanced padding for most use cases.

Large Widget

Spacious padding for prominent widgets.

<div class="omni-widget" data-size="sm">...</div>
<div class="omni-widget">...</div> <!-- md (default) -->
<div class="omni-widget" data-size="lg">...</div>

States

Interactive States

Use data-state to indicate widget interaction states:

Dragging

Applied when the widget is being dragged. Elevates z-index and adds visual feedback.

<div class="omni-widget" data-state="dragging">...</div>

Resizing

Applied when the widget is being resized.

<div class="omni-widget" data-state="resizing">...</div>

Loading

Loading Data...

<div class="omni-widget" data-state="loading">...</div>

Error

Error Loading Data

Failed to load widget data. Please try again.
<div class="omni-widget" data-state="error">...</div>

Grid Helper States

Placeholder

Shows where a widget will be dropped in a grid layout.

<div class="omni-widget" data-state="placeholder">...</div>

Collision

Indicates a widget would overlap with another in the grid.

<div class="omni-widget" data-state="collision">...</div>

Dashboard Mode

Enable edit mode by adding data-dashboard-mode="editing" to a parent container. This shows drag and resize handles on hover.

<div class="dashboard-container" data-dashboard-mode="editing">
  <div class="omni-widget">
    <div class="omni-widget-header">
      <h3 class="omni-widget-title">Widget Title</h3>
      <div class="omni-widget-actions">...</div>
      <div class="omni-widget-handle" aria-label="Drag widget"></div>
    </div>
    <div class="omni-widget-content">...</div>
    <div class="omni-widget-resize" aria-label="Resize widget"></div>
  </div>
</div>

Container Queries

Widgets use CSS container queries to adapt their content based on the widget's own size, not the viewport. This allows widgets to be truly responsive regardless of where they're placed.

Automatic Breakpoints

  • Small (< 300px): Compact padding, smaller typography
  • Medium (default): Standard layout
  • Large (> 500px): Spacious padding, larger typography
/* Example: Custom container query styles */
@container widget (max-width: 300px) {
  .custom-content { font-size: 0.875rem; }
}

@container widget (min-width: 500px) {
  .custom-content { font-size: 1.125rem; }
}

API Reference

Data Attributes

Attribute Values Default Description
data-size sm, md, lg md Widget padding and typography size
data-state dragging, resizing, loading, error, placeholder, collision Interactive and visual state
data-dashboard-mode editing Applied to parent container to enable edit mode
draggable true, false HTML5 drag and drop support

CSS Custom Properties

Property Description
--omni-widget-header-padding Header padding (changes with data-size)
--omni-widget-content-padding Content padding (changes with data-size)
--omni-widget-title-size Title font size (changes with data-size)
--omni-widget-footer-padding Footer padding (changes with data-size)
--omni-widget-footer-font-size Footer font size (changes with data-size)
--omni-widget-actions-gap Gap between action buttons
--omni-widget-resize-size Resize handle dimensions

Classes

Class Description
.omni-widget Main widget container
.omni-widget-header Header section with title and actions
.omni-widget-title Widget title (h3 recommended)
.omni-widget-actions Container for action buttons
.omni-widget-handle Drag handle (shown in edit mode)
.omni-widget-content Main content area with auto-scroll
.omni-widget-footer Optional footer section
.omni-widget-resize Resize handle (shown in edit mode)

JavaScript Integration

The widget component provides CSS structure and visual styling. JavaScript is required for:

  • Drag and drop functionality
  • Resize operations
  • Grid positioning and collision detection
  • State management (dragging, resizing, etc.)
  • Persistence of widget positions and sizes
Note: OmniUI provides the CSS foundation. JavaScript implementation is up to your application's needs. Common approaches include HTML5 Drag & Drop API, pointer events, or third-party libraries.

Accessibility

  • Use semantic HTML: <h3> for widget titles
  • Provide aria-label for drag and resize handles
  • Include focus management in JavaScript implementation
  • Ensure keyboard navigation for drag/drop operations
  • Use appropriate ARIA attributes for dynamic state changes
  • Respect prefers-reduced-motion for animations
  • Provide alternative interaction methods for users who cannot drag
  • Announce state changes to screen readers (loading, error, etc.)

Performance

The widget component includes built-in performance optimizations:

  • backface-visibility: hidden for smooth transforms
  • will-change: transform for hardware acceleration during drag
  • Container queries for efficient responsive behavior
  • Minimal reflows with flexbox layout
  • Disabled pointer events on children during drag for better performance
Best Practice: Limit the number of simultaneous will-change properties. Only apply during active drag/resize operations.

Components Used

Other OmniUI components demonstrated on this page: