Flutter Lesson 8 : From Static UI to User Interaction
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Input Widgets & Buttons Explained with One Practical App
Until now, our Flutter apps were great at showing information — text, images, layouts. But real apps don't just display things. They listen to users and respond to actions.
In this lesson, we'll move from static screens to interactive Flutter apps. We'll let users type input, tap buttons, and instantly see results on the screen. No theory overload, just one clean, practical example with fully runnable Flutter code.
Input Widgets in Flutter: What They Are & Why They Matter
So far, everything we built in Flutter was one-way communication, the app showed something, and the user just looked at it. Input widgets change that. They allow two-way communication between the user and the app.
What are Input Widgets?
Input widgets are widgets that let users enter data or make a choice inside your app.
Common examples you'll see in real apps:
- Typing a name or email
- Entering a password
- Searching for content
- Writing a message or feedback
In Flutter, these inputs are also widgets, just like Text, Image, or Container.
Common Input Widgets in Flutter
For this lesson, we'll focus on the most important one:
TextField→ lets the user type text
(We'll cover advanced ones like TextFormField, validation, checkboxes, and switches in later lessons.)
Why Input Widgets Are So Important
Think of input widgets as the ears of your app:
- Without them, your app can't hear the user
- With them, your app becomes interactive and useful
Examples where input widgets are essential:
- Login & signup screens
- Search bars
- Chat applications
- Forms and surveys
In the next section, we'll take our first input widget — TextField and see how Flutter actually reads what the user types, using a very simple and practical example.
TextField in Flutter: Letting Users Type
The most commonly used input widget in Flutter is TextField.
It's the widget that shows a text box and allows users to type something inside your app.
But here's an important question:
If a user types text, where does that text go?
How does Flutter remember it?
This is where TextEditingController comes in.
What is a TextField?
TextFielddisplays an input box on the screen- Users can type letters, numbers, or symbols
- By itself,
TextFieldonly shows UI, it does not store data in a variable automatically
So we need a way to control and read what the user types.
TextEditingController: The Brain Behind TextField
Think of TextEditingController as a notebook:
- Whatever the user types is written in that notebook
- We can read from it anytime
- We can also clear or change the text programmatically
Key points:
- One controller is usually linked to one
TextField - The controller lives inside a
StatefulWidget - We access user input using
controller.text
Basic TextField Example
TextEditingController nameController = TextEditingController();
TextField(
controller: nameController,
decoration: InputDecoration(
labelText: "Enter your name",
),
)
controllerconnects the TextField to our codelabelTexttells the user what to type- The typed value is available using
nameController.text
Right now, the user can type but nothing happens yet. In the next section, we'll add buttons and see how a button press can read this input and trigger an action.
Buttons in Flutter: Triggering Actions
Now that the user can type something, we need a way for them to tell the app what to do next.
This is where buttons come in.
Buttons are how users trigger actions in an app:
- Submit a form
- Search for something
- Save data
- Confirm an action
Common Buttons in Flutter
Flutter provides multiple button widgets, but the most commonly used ones are:
ElevatedButton→ main action button (we'll use this)TextButton→ low-priority actionsOutlinedButton→ secondary actions
For this lesson, we'll focus on ElevatedButton, since it's what you'll use most often in real apps.
How a Button Works
A button has one important property:
onPressed
This is a function that runs when the user taps the button.
Example:
ElevatedButton(
onPressed: () {
print("Button pressed");
},
child: Text("Click Me"),
)
- If
onPressedisnull, the button is disabled - If
onPressedhas a function, the button becomes clickable
Connecting Button with User Input
Now let's connect the button with the TextField we created earlier.
Basic idea:
- User types text into
TextField - Text is stored in
TextEditingController - User presses button
- Button reads
controller.text - App performs some action
But there's still one missing piece…
Even if we read the text, how do we update the UI to show something new?
That's exactly what we'll learn next using setState().
Connecting Input & Button Using setState()
At this point, our app can:
- take input from the user (
TextField) - detect a button tap (
ElevatedButton)
But there's still a problem.
The app knows something changed, but the screen doesn't update automatically.
This is where setState() comes in.
What is setState()? (Simple Explanation)
Think of setState() as telling Flutter:
"Hey Flutter, some data has changed.
Please redraw the screen using the new values.
Without setState():
- values may change in code
- UI stays the same
With setState():
- Flutter rebuilds the widget
- updated data appears on screen instantly
How setState() Fits into Our Example
Here's the flow we want:
- User types their name
- User presses the button
- App reads the input
- App updates a message
- UI refreshes and shows the message
We'll store the message in a variable and update it using setState().
Small Logic Example
String greetingMessage = "";
void generateGreeting() {
setState(() {
greetingMessage = "Hello!";
});
}
greetingMessageholds what we want to displaysetState()updates the value- Flutter rebuilds the screen automatically
Why setState() Is So Important
- It's the simplest way to manage UI updates
- Perfect for small apps and learning
- Helps you understand how Flutter reacts to data changes
Now that we understand TextField, Button, and setState(), we're ready to combine everything into one complete, runnable Flutter app.
Full Practical Example: A Simple Greeting App
Now let's put everything together and build one small Flutter app that:
- takes input from the user
- reacts to a button press
- updates the UI instantly
This single example will cover input widgets, buttons, and state updates — exactly how you'll use them in real apps.
What This App Does
- User types their name
- User taps a button
- App displays a greeting message
- If input is empty, it shows a helpful message instead
Complete Runnable Flutter Code
You can copy-paste this code and run it directly.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: GreetingApp(),
);
}
}
class GreetingApp extends StatefulWidget {
const GreetingApp({super.key});
@override
State<GreetingApp> createState() => _GreetingAppState();
}
class _GreetingAppState extends State<GreetingApp> {
final TextEditingController nameController = TextEditingController();
String greetingMessage = "";
void generateGreeting() {
setState(() {
if (nameController.text.isEmpty) {
greetingMessage = "Please enter your name";
} else {
greetingMessage = "Hello, ${nameController.text}! 👋";
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Input Widgets & Buttons"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: "Enter your name",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: generateGreeting,
child: const Text("Generate Greeting"),
),
const SizedBox(height: 20),
Text(
greetingMessage,
style: const TextStyle(fontSize: 20),
textAlign: TextAlign.center,
),
],
),
),
);
}
}
What's Happening Behind the Scenes
TextFieldcollects user inputTextEditingControllerstores the typed textElevatedButtontriggers an actionsetState()updates the message- Flutter rebuilds the UI automatically

Breaking Down the Code
Let's now understand what we just built — slowly and clearly, without assuming any prior knowledge.
1. Starting the App
void main() {
runApp(const MyApp());
}- Every Flutter app starts here
runApp()tells Flutter which widget to show firstMyAppis our root widget
2. MaterialApp: App Foundation
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: GreetingApp(),
);
MaterialAppprovides: themes, navigation, basic app behaviorhomeis the first screen users seeGreetingAppis where all our logic lives
3. Why StatefulWidget?
class GreetingApp extends StatefulWidget
- Our app changes when the user interacts
- The greeting message updates
- That means we need state
StatefulWidgetallows UI to change dynamically
4. Controller & State Variables
final TextEditingController nameController = TextEditingController();
String greetingMessage = "";
nameControllerstores what the user typesgreetingMessagestores what we want to show on screen- When
greetingMessagechanges, the UI should update
5. Button Logic
void generateGreeting() {
setState(() {
if (nameController.text.isEmpty) {
greetingMessage = "Please enter your name";
} else {
greetingMessage = "Hello, ${nameController.text}! 👋";
}
});
}- Button calls this function
- We read the user input using
nameController.text setState()updates the UI- Flutter redraws the screen automatically
6. Building the UI
TextField(
controller: nameController,
)
- User types text here
- Controller stores it
ElevatedButton(
onPressed: generateGreeting,
)
- Button triggers logic
Text(greetingMessage)
- Shows the result
- Updates automatically when state changes
Why This Pattern Matters
This same pattern is used everywhere in Flutter:
- Forms
- Login screens
- Search features
- Chat input boxes
Common Beginner Mistakes
Before we close, here are a few small but important mistakes beginners often make when working with input and buttons:
- Using
StatelessWidgetwhen the UI needs to change - Forgetting to wrap updates inside
setState() - Creating
TextEditingControllerinsidebuild() - Leaving
onPressedasnulland wondering why the button doesn't work - Not handling empty user input
Avoiding these will save you hours of confusion early on.
Lesson Summary
In this lesson, we took our first real step toward interactive Flutter apps.
You learned how to:
- take input from users using
TextField - read that input using
TextEditingController - trigger actions with buttons
- update the UI using
setState()
With just these basics, you can already build:
- simple forms
- search inputs
- login screens
- and interactive app features
Do comment and share with others to support us and check our previous lessons here:
List: Flutter Lessons | Curated by YogiCode | MediumFlutter Lessons · 7 stories on Medium
medium.com