State Management & Interactive Styles
On this page
Introduction#
Interactive styles allow you to define how your UI reacts to user input without managing complex state variables. Instead of nesting multiple MouseRegion, GestureDetector, and Focus widgets, Wind provides a declarative way to handle states directly in your className string.
By using prefixes like hover:, focus:, and active:, you can build responsive, tactile interfaces that feel native to both web and mobile platforms.
How It Works#
core-concepts/state_management_overview
The live demo is not available for this example.
state_management_overview.dart
View source
Wind's parsing engine identifies state prefixes in your class string and stores them in a separate style map. When the widget's internal state changes (e.g., a user hovers over it), the widget rebuilds and applies the corresponding styles.
Consider this basic button example:
WButton(
onTap: () => print('Action triggered'),
className: 'bg-blue-500 hover:bg-blue-600 active:bg-blue-700 p-4 rounded-lg duration-200',
child: WText('Save Changes', className: 'text-white'),
)
In this case, the background color transitions smoothly between shades based on the interaction state.
Built-in State Prefixes#
Wind supports several interactive states out of the box. These are automatically managed when using interactive widgets:
- hover: Triggered when a pointer enters the widget bounds.
- focus: Triggered when the widget receives keyboard or input focus.
- active: Triggered while the widget is being pressed or tapped.
- disabled: Triggered when the widget's interactivity is disabled (e.g.,
onTapis null).
Quick Reference#
| Prefix | Trigger | Typical Use Case |
|---|---|---|
hover: |
Pointer entry | Changing background or elevation on desktop. |
focus: |
Keyboard focus | Showing a ring or border on input fields. |
active: |
Pointer press | Scaling down or darkening a button on tap. |
disabled: |
Interactivity off | Reducing opacity or greying out actions. |
Interactive Widgets#
Wind provides specific widgets designed to manage and propagate these states.
WAnchor: The Core Wrapper#
WAnchor is the low-level engine behind Wind's interactivity. It provides no visual styling itself; its sole purpose is to detect gestures and share that state with its child tree. This is useful for making entire cards or complex layouts interactive.
WAnchor(
onTap: () {},
child: WDiv(
className: 'bg-white hover:bg-slate-50 border p-6 rounded-xl duration-300',
children: [
WText('Interactive Card', className: 'group-hover:text-blue-600'),
],
),
)
WButton: The High-Level Action#
While WAnchor is for generic wrappers, WButton is optimized for actions. It includes built-in support for loading states, padding defaults, and button-specific accessibility.
WButton(
onTap: _submit,
className: 'bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white px-8 py-3 rounded',
child: Text('Submit'),
)
WInput: Focus States#
WInput manages its own focus state. It is common to use focus: prefixes here to highlight the active field or show a focus ring.
WInput(
placeholder: 'Search...',
className: 'border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 p-3 rounded-lg',
)
Custom States#
Sometimes you need to style a widget based on a state that isn't built-in, such as whether an item is "selected" or "loading". You can pass custom strings to the states parameter.
WDiv(
className: 'border-2 border-gray-200 selected:border-blue-500 bg-white selected:bg-blue-50 p-4',
states: isSelected ? {'selected'} : {},
child: WText('Selection Item'),
)
If the states set contains "selected", any class prefixed with selected: will be applied.
State Propagation#
Interactivity in Wind is shared through WindContext. When an ancestor widget like WAnchor changes state, it propagates that state to all children in its subtree.
Let's look at a nested example:
WAnchor(
onTap: () {},
child: WDiv(
className: 'p-4 bg-white hover:bg-gray-50',
children: [
WText('Title', className: 'font-bold hover:text-blue-600'),
WText('Description', className: 'text-gray-500'),
],
),
)
Even if the mouse is only hovering over the padding of the WDiv, the WText widget will receive the "hover" state and update its color accordingly.
Related Documentation#
- Responsive Design - Combining states with breakpoints.
- Dark Mode - Styling for night owls.
- WAnchor Widget - Technical reference for the anchor engine.