cmx_onboarding 0.0.1 copy "cmx_onboarding: ^0.0.1" to clipboard
cmx_onboarding: ^0.0.1 copied to clipboard

A highly customizable Flutter onboarding package with 16 built-in UI templates, themeable indicators and buttons, per-page styling, and full controller support.

example/lib/main.dart

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

void main() => runApp(const DemoApp());

class DemoApp extends StatelessWidget {
  const DemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'cmx_onboarding demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: const Color(0xFF6750A4),
      ),
      home: const TemplateGallery(),
    );
  }
}

class TemplateGallery extends StatelessWidget {
  const TemplateGallery({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('cmx_onboarding templates')),
      body: ListView.separated(
        padding: const EdgeInsets.all(16),
        itemCount: OnboardTemplate.values.length,
        separatorBuilder: (_, __) => const SizedBox(height: 12),
        itemBuilder: (context, i) {
          final template = OnboardTemplate.values[i];
          return Card(
            child: ListTile(
              leading: CircleAvatar(
                backgroundColor: _accentFor(template),
                child: Text('${i + 1}',
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w700,
                    )),
              ),
              title: Text(_humanize(template.name)),
              subtitle: Text(_descriptionFor(template)),
              trailing: const Icon(Icons.chevron_right),
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (_) => DemoScreen(template: template),
                  ),
                );
              },
            ),
          );
        },
      ),
    );
  }

  Color _accentFor(OnboardTemplate t) {
    switch (t) {
      case OnboardTemplate.vibrant:
        return const Color(0xFFFFC107);
      case OnboardTemplate.pastel:
        return const Color(0xFFFFB7C5);
      case OnboardTemplate.darkPro:
        return const Color(0xFF111827);
      case OnboardTemplate.editorial:
        return const Color(0xFF7C3AED);
      default:
        return const Color(0xFF6750A4);
    }
  }

  String _humanize(String s) {
    final result = StringBuffer();
    for (var i = 0; i < s.length; i++) {
      final c = s[i];
      if (i > 0 && c == c.toUpperCase()) result.write(' ');
      result.write(i == 0 ? c.toUpperCase() : c);
    }
    return result.toString();
  }

  String _descriptionFor(OnboardTemplate t) {
    switch (t) {
      case OnboardTemplate.classic:
        return 'Image top, text bottom, dots, CTAs';
      case OnboardTemplate.parallax:
        return 'Background drifts at a different speed';
      case OnboardTemplate.fade:
        return 'Pages crossfade — no swipe';
      case OnboardTemplate.zoom:
        return 'Active page scales in';
      case OnboardTemplate.cardStack:
        return 'Stacked cards reveal one at a time';
      case OnboardTemplate.splitScreen:
        return 'Hero on top, white panel below';
      case OnboardTemplate.fullscreen:
        return 'Full-bleed background, text overlay';
      case OnboardTemplate.minimal:
        return 'Big icon + title only';
      case OnboardTemplate.glassmorphism:
        return 'Frosted glass card on a gradient';
      case OnboardTemplate.story:
        return 'Instagram-style auto-progressing';
      case OnboardTemplate.slideUp:
        return 'Text slides up from bottom';
      case OnboardTemplate.lottie:
        return 'Lottie animations per page';
      case OnboardTemplate.editorial:
        return 'Bold headline, tilted card, circular CTA';
      case OnboardTemplate.vibrant:
        return 'Solid bold color, mascot, full-width pill';
      case OnboardTemplate.pastel:
        return 'Pastel bg, avatars + square arrow';
      case OnboardTemplate.darkPro:
        return 'Dark, dual CTA (Sign In + Get Started)';
    }
  }
}

class DemoScreen extends StatelessWidget {
  final OnboardTemplate template;
  const DemoScreen({super.key, required this.template});

  @override
  Widget build(BuildContext context) {
    switch (template) {
      case OnboardTemplate.editorial:
        return _EditorialDemo();
      case OnboardTemplate.vibrant:
        return _VibrantDemo();
      case OnboardTemplate.pastel:
        return _PastelDemo();
      case OnboardTemplate.darkPro:
        return _DarkProDemo();
      default:
        return _GenericDemo(template: template);
    }
  }
}

// ----- Generic demo used by the original 12 templates -----
class _GenericDemo extends StatelessWidget {
  final OnboardTemplate template;
  const _GenericDemo({required this.template});

  static const _pages = [
    OnboardPage(
      title: 'Discover',
      description:
          'Find products and ideas tailored to what you care about.',
      image: Icon(Icons.explore_outlined,
          size: 120, color: Colors.white),
      backgroundColor: Color(0xFF6750A4),
    ),
    OnboardPage(
      title: 'Connect',
      description:
          'Reach friends, family, and a community that gets you.',
      image: Icon(Icons.people_outline, size: 120, color: Colors.white),
      backgroundColor: Color(0xFF1E88E5),
    ),
    OnboardPage(
      title: 'Create',
      description:
          'Bring your ideas to life with tools that work the way you do.',
      image: Icon(Icons.brush_outlined, size: 120, color: Colors.white),
      backgroundColor: Color(0xFF43A047),
    ),
    OnboardPage(
      title: 'Get Started',
      description: 'Tap below to dive in. It only takes a moment.',
      image: Icon(Icons.rocket_launch_outlined,
          size: 120, color: Colors.white),
      backgroundColor: Color(0xFFE53935),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Onboardly(
        template: template,
        pages: _pages,
        indicatorType: OnboardIndicatorType.expandingDot,
        activeColor: Colors.white,
        inactiveColor: Colors.white38,
        foregroundColor: Colors.white,
        onDone: () => _close(context, 'Done!'),
        onSkip: () => _close(context, 'Skipped'),
      ),
    );
  }
}

// ----- Editorial demo (ref 2) -----
class _EditorialDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Onboardly(
        template: OnboardTemplate.editorial,
        pages: const [
          OnboardPage(
            tag: 'Step 1',
            title: 'Empower yourself\nwith quick knowledge',
            subtitle: 'Bite-size lessons every day',
            description:
                'Browse handpicked reads from authors, creators and experts in your pocket.',
            image: Icon(Icons.menu_book_rounded,
                size: 80, color: Colors.white),
            backgroundColor: Color(0xFF7C3AED),
          ),
          OnboardPage(
            tag: 'Step 2',
            title: 'Elevate your reading\nwith quick insights',
            subtitle: 'Hand-picked recommendations',
            description: 'Curated content tuned for what you love.',
            image: Icon(Icons.lightbulb_rounded,
                size: 80, color: Colors.white),
            backgroundColor: Color(0xFFE11D48),
          ),
          OnboardPage(
            tag: 'Step 3',
            title: 'Stay motivated\nand achieve goals',
            subtitle: "We'll keep you on track",
            description: 'Daily streaks, gentle reminders, no spam.',
            image: Icon(Icons.emoji_events_rounded,
                size: 80, color: Colors.white),
            backgroundColor: Color(0xFF0EA5E9),
          ),
        ],
        theme: const OnboardTheme(
          primaryColor: Color(0xFF111111),
          onPrimaryColor: Colors.white,
          secondaryColor: Color(0xFFE4E4E7),
          surfaceColor: Colors.white,
          onSurfaceColor: Color(0xFF111111),
          primaryButtonShape: OnboardButtonShape.circle,
        ),
        headerType: OnboardHeaderType.none,
        indicatorType: OnboardIndicatorType.expandingDot,
        nextLabel: 'Next',
        doneLabel: 'Start',
        onDone: () => _close(context, 'Editorial done'),
        onSkip: () => _close(context, 'Skipped'),
      ),
    );
  }
}

// ----- Vibrant demo (ref 3) -----
class _VibrantDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Onboardly(
        template: OnboardTemplate.vibrant,
        pages: const [
          OnboardPage(
            title: 'Speak\nwith confidence',
            description: 'Master conversation skills with daily prompts.',
            image: Icon(Icons.record_voice_over_rounded,
                size: 140, color: Color(0xFF111111)),
            backgroundColor: Color(0xFFFFD93D),
          ),
          OnboardPage(
            title: 'Learn anytime,\neasily anywhere',
            description: 'Bite-sized lessons crafted for busy people.',
            image: Icon(Icons.translate_rounded,
                size: 140, color: Color(0xFF111111)),
            backgroundColor: Color(0xFFC4B5FD),
          ),
          OnboardPage(
            title: 'Lessons that\nwork for you',
            description: 'AI-tuned content matches your learning style.',
            image: Icon(Icons.psychology_rounded,
                size: 140, color: Color(0xFF111111)),
            backgroundColor: Color(0xFFFB923C),
          ),
        ],
        theme: OnboardTheme.vibrant,
        indicatorType: OnboardIndicatorType.none,
        nextLabel: 'Get Started',
        doneLabel: 'Get Started',
        headerType: OnboardHeaderType.skip,
        onDone: () => _close(context, 'Vibrant done'),
        onSkip: () => _close(context, 'Skipped'),
      ),
    );
  }
}

// ----- Pastel demo (ref 4) -----
class _PastelDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Onboardly(
        template: OnboardTemplate.pastel,
        pages: const [
          OnboardPage(
            title: 'We will\ntake care',
            subtitle: 'of tickets, transfers and a cool place to stay',
            image: Icon(Icons.luggage_rounded,
                size: 140, color: Color(0xFF8B4513)),
            backgroundColor: Color(0xFFFFD93D),
          ),
          OnboardPage(
            title: 'Relax\n& enjoy',
            subtitle: 'Sunbathe, swim, eat and drink deliciously',
            image: Icon(Icons.beach_access_rounded,
                size: 140, color: Color(0xFF1E40AF)),
            backgroundColor: Color(0xFF7DD3FC),
          ),
          OnboardPage(
            title: 'Flexible\npayment',
            subtitle: 'credit card and transfer, cryptocurrency',
            image: Icon(Icons.payments_rounded,
                size: 140, color: Color(0xFFBE185D)),
            backgroundColor: Color(0xFFFBCFE8),
          ),
        ],
        theme: const OnboardTheme(
          primaryColor: Color(0xFF111111),
          secondaryColor: Color(0xFF111111),
          onSurfaceColor: Color(0xFF111111),
          skipColor: Color(0xFF111111),
        ),
        headerType: OnboardHeaderType.skip,
        brandLogo: const _MiniLogo(),
        indicatorType: OnboardIndicatorType.line,
        onDone: () => _close(context, 'Pastel done'),
        onSkip: () => _close(context, 'Skipped'),
      ),
    );
  }
}

// ----- DarkPro demo (ref 5) -----
class _DarkProDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Onboardly(
        template: OnboardTemplate.darkPro,
        pages: const [
          OnboardPage(
            title: 'Gym workout generator',
            description:
                'Get workouts with real-time tracking, heart-rate monitoring and personalised experience.',
            image: Icon(Icons.fitness_center_rounded,
                size: 140, color: Color(0xFF60A5FA)),
          ),
          OnboardPage(
            title: 'Your Workout Plan',
            description:
                'Personalised plans, real-time tracking and motivating reminders.',
            image: Icon(Icons.timer_outlined,
                size: 140, color: Color(0xFF60A5FA)),
          ),
          OnboardPage(
            title: 'About You',
            subtitle: 'What is your name?',
            description:
                "We'll personalise your journey using your inputs.",
            image: Icon(Icons.person_outline_rounded,
                size: 140, color: Color(0xFF60A5FA)),
          ),
        ],
        theme: OnboardTheme.dark,
        headerType: OnboardHeaderType.skip,
        brandLogo: const Text(
          'fitonist',
          style: TextStyle(
            color: Colors.white,
            fontSize: 18,
            fontWeight: FontWeight.w800,
            letterSpacing: 1,
          ),
        ),
        indicatorType: OnboardIndicatorType.dot,
        nextLabel: 'Get Started',
        doneLabel: 'Get Started',
        secondaryLabel: 'Sign In',
        onSecondaryAction: () => _close(context, 'Sign in tapped'),
        onDone: () => _close(context, 'DarkPro done'),
        onSkip: () => _close(context, 'Skipped'),
      ),
    );
  }
}

class _MiniLogo extends StatelessWidget {
  const _MiniLogo();
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 32,
      height: 32,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
      ),
      child: const Center(
        child: Text('B',
            style: TextStyle(
              fontWeight: FontWeight.w900,
              color: Colors.black,
            )),
      ),
    );
  }
}

void _close(BuildContext context, String msg) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(msg), duration: const Duration(seconds: 1)),
  );
  Navigator.of(context).pop();
}
2
likes
150
points
32
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A highly customizable Flutter onboarding package with 16 built-in UI templates, themeable indicators and buttons, per-page styling, and full controller support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, lottie

More

Packages that depend on cmx_onboarding