Getting Started

Behavior-first, zero-styling Flutter components

The Naked UI library provides headless components that handle functionality, interaction, and accessibility without imposing any visual styling. This approach gives you full control over your design system while ensuring components work correctly and meet accessibility standards.

What is headless UI?

Headless components handle interaction behavior and accessibility without visual styling. They provide:

  • Keyboard navigation (pressing Tab, Enter, arrow keys)
  • Screen reader announcements
  • Mouse interactions (hover, click, drag)
  • Focus management
  • Touch gestures

Headless components provide behavior and accessibility without visual styling.

Standard UI library approach

Most UI libraries give you components that look like this:

// Standard UI library approach
ElevatedButton(
  onPressed: () {},
  child: const Text('Click me'), // Fixed appearance
)

Standard libraries limit customization to predefined themes and styles. Design flexibility is constrained.

The Naked UI approach

Naked UI provides custom styling through builders:

NakedButton(
  onPressed: () {},
  builder: (context, state, child) {
    // Custom styling based on state
    return Container(
      decoration: BoxDecoration(
        color: state.isPressed ? Colors.blue.shade700 : Colors.blue,
        borderRadius: BorderRadius.circular(8),
        // Customize any aspect of design
      ),
      child: const Text('Click me'),
    );
  },
)

Components handle behavior. Builders define appearance.

Key Features

  • Zero-styling: behavior only - you own presentation
  • Accessible: correct semantics and keyboard navigation
  • Observable state: hover, focus, press, drag, select
  • Composable: small, predictable APIs

Components

  • NakedButton - button interactions (hover, press, focus)
  • NakedCheckbox - toggle behavior and semantics
  • NakedRadio - single-select radio with group management
  • NakedSelect - dropdown/select with keyboard navigation
  • NakedSlider - value slider with drag + keys
  • NakedToggle - toggle button or switch behavior
  • NakedTabs - tablist + roving focus
  • NakedAccordion - expandable/collapsible sections
  • NakedMenu - anchored overlay menu
  • NakedDialog - modal dialog behavior + focus trap
  • NakedTooltip - anchored tooltip with lifecycle
  • NakedPopover - anchored, dismissible popover overlay

Getting Started

Installation

dependencies:
  naked_ui: ^latest_version  # https://pub.dev/packages/naked_ui

Then: flutter pub get

Import: import 'package:naked_ui/naked_ui.dart';

Basic implementation

Build a simple button:

import 'package:flutter/material.dart';
import 'package:naked_ui/naked_ui.dart';

NakedButton(
  onPressed: () => print('Hello World!'),
  builder: (context, state, child) {
    return Container(
      padding: const EdgeInsets.all(12),
      color: state.isPressed ? Colors.blue : Colors.grey,
      child: const Text('Submit'),
    );
  },
)

This button includes:

  • Press state color changes
  • Automatic keyboard navigation
  • Screen reader support
  • Mouse and touch interaction

The color changes when pressed due to the state.isPressed condition.

Implementation details

  1. NakedButton manages interaction behavior and accessibility
  2. builder function defines visual appearance based on state
  3. state.isPressed provides current press state
  4. Return any Widget for custom styling

Enhanced patterns

Multiple states: Use state.when() to handle pressed, hovered, and focused states

Animations: Wrap containers in AnimatedContainer for smooth transitions

Advanced styling: Add borders, shadows, gradients, or any visual elements

Check out our Button documentation for advanced examples and patterns.

Advanced state management

Common patterns for enhanced interactivity:

Multiple interaction states

Handle pressed, hovered, and focused states:

import 'package:flutter/material.dart';
import 'package:naked_ui/naked_ui.dart';

NakedButton(
  onPressed: () {},
  builder: (context, state, child) {
    // Method 1: Check each state individually
    Color buttonColor = Colors.grey;
    if (state.isPressed) buttonColor = Colors.blue.shade800;
    else if (state.isHovered) buttonColor = Colors.blue.shade600; 
    else if (state.isFocused) buttonColor = Colors.blue.shade400;

    // Method 2: Use state.when() for cleaner code
    final color = state.when(
      pressed: Colors.blue.shade800,    // Darkest when clicked
      hovered: Colors.blue.shade600,    // Medium when mouse over
      focused: Colors.blue.shade400,    // Light when keyboard focused
      orElse: Colors.grey,              // Default state
    );

    return Container(
      padding: const EdgeInsets.all(12),
      color: color,
      child: const Text('Interactive button'),
    );
  },
)

The state.when() method provides cleaner conditional logic.

Programmatic focus control

For precise focus management in forms or complex UIs:

import 'package:flutter/material.dart';
import 'package:naked_ui/naked_ui.dart';

final myFocusNode = FocusNode();

NakedButton(
  focusNode: myFocusNode,        // Use your own focus node
  autofocus: true,               // Focus automatically when built
  onPressed: () {
    myFocusNode.requestFocus();  // Focus programmatically
  },
  builder: (context, state, child) => YourCustomWidget(),
)

Component selection guide

All components follow the same builder pattern. Choose based on interaction requirements:

For user actions

  • Button - Any clickable action (submit, save, delete, etc.)
  • Toggle - On/off switches (dark mode, notifications)
  • Checkbox - Select multiple options from a list
  • Radio - Pick one option from a group

For user input

  • TextField - Text input (names, messages, search)
  • Select - Choose from a dropdown list (countries, categories)
  • Slider - Pick numeric values (volume, price range)

For organizing content

  • Tabs - Switch between different content sections
  • Accordion - Expandable sections (FAQ, settings groups)
  • Dialog - Modal windows (confirmations, forms)

For helpful overlays

  • Tooltip - Show help text on hover
  • Popover - Show additional info or controls
  • Menu - Context menus and dropdown actions

Getting started

Recommended approach: Begin with Button - the simplest component for learning the core patterns. Other components use the same builder-based approach.

Next steps: Review component-specific documentation for detailed implementation examples and API references.