DEV Community

Cover image for How to Create Reusable Custom Widgets for Your Flutter Projects 🛠️
Bestaoui Aymen
Bestaoui Aymen

Posted on

How to Create Reusable Custom Widgets for Your Flutter Projects 🛠️

One of Flutter’s biggest strengths is its widget-based architecture. Everything in Flutter — from buttons to layouts — is a widget. But if you’re building apps regularly, you’ll quickly notice a pattern: you keep writing the same UI code again and again.

That’s where custom reusable widgets come in. They make your code cleaner, reduce duplication, and ensure consistency across your project. In this blog, we’ll explore how to create reusable widgets in Flutter — step by step.

Why Reusable Widgets Matter 🤔

  • Consistency → Same UI style across multiple screens.
  • Maintainability → Change code in one place, update everywhere.
  • Productivity → Write once, use everywhere.
  • Scalability → Makes your app easier to grow and refactor.

Example 1: A Custom Button Widget 🔘

Instead of rewriting ElevatedButton with styling each time, wrap it into a reusable widget.

import 'package:flutter/material.dart';

class AppButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  final Color color;

  const AppButton({
    Key? key,
    required this.label,
    required this.onPressed,
    this.color = Colors.blue,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: ElevatedButton.styleFrom(
        backgroundColor: color,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12),
        ),
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
      ),
      onPressed: onPressed,
      child: Text(
        label,
        style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

📌 Usage:

AppButton(
  label: "Get Started",
  color: Colors.green,
  onPressed: () => print("Clicked!"),
)
Enter fullscreen mode Exit fullscreen mode

Example 2: Custom Input Field ✏️

TextFields are common, but they often need custom styling.

class AppTextField extends StatelessWidget {
  final String hint;
  final TextEditingController controller;
  final bool isPassword;

  const AppTextField({
    Key? key,
    required this.hint,
    required this.controller,
    this.isPassword = false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: controller,
      obscureText: isPassword,
      decoration: InputDecoration(
        hintText: hint,
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
        ),
        contentPadding: const EdgeInsets.all(16),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

📌 Usage:

AppTextField(
  hint: "Enter your email",
  controller: TextEditingController(),
)
Enter fullscreen mode Exit fullscreen mode

Example 3: Combining Widgets Into a Card 📦

Reusable widgets aren’t just for single components — you can build complex UI blocks.

class InfoCard extends StatelessWidget {
  final String title;
  final String subtitle;
  final IconData icon;

  const InfoCard({
    Key? key,
    required this.title,
    required this.subtitle,
    required this.icon,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: ListTile(
        leading: Icon(icon, size: 40, color: Colors.blue),
        title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Text(subtitle),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

📌 Usage:

InfoCard(
  title: "Profile",
  subtitle: "View and edit your profile",
  icon: Icons.person,
)
Enter fullscreen mode Exit fullscreen mode

Pro Tips for Creating Reusable Widgets 💡

  • Keep them flexible → Use parameters for customization.
  • Follow naming conventions → AppButton, AppCard, etc.
  • Use composition → Build big widgets by combining small ones.
  • Avoid over-engineering → Don’t create a widget for every line of code.
  • Centralize them → Store your reusable widgets in a /widgets folder.

By doing this, you’ll write less code, ship faster, and your apps will look much more polished. 🚀

Top comments (0)