Skip to Content
naked_ui

Bring the look.
The behavior is handled.

Headless Flutter primitives with semantics, keyboard support, focus, overlays, and observable interaction state—without a single opinion about how your interface should look.

NakedButton(
  onPressed: onSave,
  builder: (context, state, child) {
    final color = state.when(
      pressed: const Color(0xFF1D4ED8),
      hovered: const Color(0xFF2563EB),
      orElse: const Color(0xFF3B82F6),
    );

    return AnimatedContainer(
      duration: const Duration(milliseconds: 160),
      padding: const EdgeInsets.symmetric(
        horizontal: 20,
        vertical: 12,
      ),
      decoration: BoxDecoration(
        color: color,
        borderRadius: BorderRadius.circular(12),
      ),
      child: const Text('Save changes'),
    );
  },
)
state.idle

Pointer, keyboard, and focus all feed the same typed snapshot.

14Headless primitives
0Preset styles
1Builder-first pattern
BSD-3Open-source license

A component library should make behavior boring without making your product generic. Naked UI separates the two.

Behavior without a brand

The hard interaction work, already handled.

Naked UI gives each control the behavior users expect, then exposes the state your own widgets need to render it well.

Semantics are part of the primitive

Screen-reader roles and control state live beside the behavior instead of being rebuilt in every visual component.

State you can actually observe

Builders receive typed snapshots for hover, focus, press, drag, selection, and disabled states—ready for your styles and animations.

Keyboard conventions

Activation, arrow-key navigation, roving focus, and traversal behavior follow the control you chose.

Focus and overlays

Dialogs, menus, selects, tooltips, and popovers handle anchoring, dismissal, and focus lifecycle.

Zero visual lock-in

Return ordinary Flutter widgets from the builder. Use your tokens, painters, animations, or styling system.

14 primitives

Choose the behavior. Keep the design language.

Every primitive uses the same builder-first idea, from a button to a focus-trapped dialog. Open any component to see its complete API and accessibility guidance.

One repeatable pattern

Wrap your visuals. Read the state. Ship the control.

Your design-system widget remains an ordinary Flutter widget. Naked UI sits at the interaction boundary and keeps behavior, semantics, and state in one predictable place.

  • Start with your own visual component
  • Wrap it in the matching Naked primitive
  • Render interaction state in the builder
  • Keep labels, contrast, and content in your design system
design_system_button.dart
class DesignSystemButton extends StatelessWidget {
  const DesignSystemButton({
    super.key,
    required this.label,
    required this.onPressed,
  });

  final String label;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return NakedButton(
      onPressed: onPressed,
      builder: (context, state, child) {
        return AppButtonSurface(
          label: label,
          hovered: state.isHovered,
          pressed: state.isPressed,
          focused: state.isFocused,
        );
      },
    );
  }
}
FAQ

Questions, answered.

Does Naked UI include any visual styling?

No. The primitives own interaction behavior, state, semantics, focus, and overlay mechanics. Their builders return the Flutter widgets that define your colors, spacing, typography, shape, motion, and layout.

Do I need Mix or another styling package?

No. Naked UI depends on Flutter and works with ordinary widgets, Theme extensions, custom painters, Mix, or any other styling approach you already use.

What accessibility work is handled for me?

Each primitive supplies control-appropriate semantics and interaction behavior such as keyboard activation, roving focus, focus trapping, or screen-reader state. You still own accessible labels, readable contrast, touch-target sizing, and the meaning of your custom content.

How do I choose between Toggle, Switch, Checkbox, and Radio?

Use Switch for an immediate on/off setting, Checkbox for independent choices, Radio for one choice in a group, and Toggle for a pressable selected state or toggle group. The component docs include selection and semantics guidance for each.

Is the API stable?

Naked UI is currently published as a beta. Pin the version you adopt, review the changelog when upgrading, and cover your design-system wrappers with widget tests while the API continues to mature.

Can I use it in a commercial app?

Yes. Naked UI is open source under the BSD 3-Clause license.

Bring the design. Keep the behavior.

Add Naked UI, wrap one control you already own, and stop rebuilding the interaction layer every time the visuals change.

flutter pub add naked_ui