CINXE.COM
Interactivity | Flutter
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Interactivity | Flutter</title><link rel="icon" href="/assets/images/branding/flutter/icon/64.png" eleventy:ignore><link rel="apple-touch-icon" href="/assets/images/branding/flutter/logo/flutter-logomark-320px.png" eleventy:ignore><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#ffffff"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><meta name="google-site-verification" content="HFqxhSbf9YA_0rBglNLzDiWnrHiK_w4cqDh2YD2GEY4"><script>!function(e,t,a,n){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var g=t.getElementsByTagName(a)[0],m=t.createElement(a);m.async=!0,m.src="https://www.googletagmanager.com/gtm.js?id=GTM-ND4LWWZ",g.parentNode.insertBefore(m,g)}(window,document,"script","dataLayer")</script><script>!function(e,a,t,n,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=a.createElement(t),s=a.getElementsByTagName(t)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga"),ga("create","UA-67589403-1","auto"),ga("send","pageview")</script><meta name="description" content="How to implement a stateful widget that responds to taps."><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content="@flutterdev"><meta property="og:title" content="Add interactivity to your Flutter app"><meta property="og:url" content="https://docs.flutter.dev/ui/interactivity"><meta property="og:description" content="How to implement a stateful widget that responds to taps."><meta property="og:image" content="https://docs.flutter.dev/assets/images/flutter-logo-sharing.png" eleventy:ignore><link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" rel="stylesheet"><script>window.__CALLBACKS=[]</script><link rel="stylesheet" href="/assets/css/main.css?v=4"></head><body><section id="cookie-notice"><div class="container"><p>docs.flutter.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic. <a href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a>.</p><button id="cookie-consent" class="filled-button">OK, got it</button></div></section><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-ND4LWWZ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="site-banner" role="alert"><p>Flutter 3.29 is here with a bouquet of performance and fidelity improvements for your apps! <a href="https://medium.com/flutter/whats-new-in-flutter-3-29-f90c380c2317">Learn more</a><br></p></div><header class="site-header"><a href="#document-title" id="skip-to-main" class="filled-button" tabindex="1">Skip to main content</a><nav class="navbar"><div id="site-switcher" class="dropdown"><button class="dropdown-button site-wordmark" aria-expanded="false" aria-controls="site-switcher-menu" aria-label="Switch between Flutter and Dart sites"><img src="/assets/images/branding/flutter/logo/default.svg" alt="Flutter logo" width="28"> <span>Flutter</span> <span class="subtype">Docs</span> <span class="material-symbols" aria-hidden="true">unfold_more</span></button><div class="dropdown-content" id="site-switcher-menu"><nav class="dropdown-menu" role="menu"><ul><li role="presentation"><a href="https://flutter.dev" class="site-wordmark" role="menuitem" title="Flutter homepage" aria-label="Go to the Flutter homepage"><img src="/assets/images/branding/flutter/logo/default.svg" alt="Flutter logo" width="28"> <span>Flutter</span></a></li><li role="presentation"><a href="https://docs.flutter.dev" class="site-wordmark current-site" role="menuitem" aria-current="true" title="Flutter docs homepage" aria-label="Go to the Flutter docs homepage"><img src="/assets/images/branding/flutter/logo/default.svg" alt="Flutter logo" width="28"> <span>Flutter</span> <span class="subtype">Docs</span></a></li><li role="presentation"><a href="https://api.flutter.dev" class="site-wordmark" role="menuitem" title="Flutter API reference" aria-label="Go to the Flutter API reference"><img src="/assets/images/branding/flutter/logo/default.svg" alt="Flutter logo" width="28"> <span>Flutter</span> <span class="subtype">API</span></a></li><li aria-hidden="true" class="dropdown-divider" role="separator"></li><li role="presentation"><a href="https://dart.dev" class="site-wordmark" role="menuitem" title="Dart homepage" aria-label="Go to the Dart homepage"><img src="/assets/images/branding/dart/logo.svg" alt="Dart logo" width="28" height="28"> <span>Dart</span></a></li><li role="presentation"><a href="https://dartpad.dev" class="site-wordmark" role="menuitem" title="DartPad playground" aria-label="Go to the DartPad playground"><img src="/assets/images/branding/dart/logo.svg" alt="Dart logo" width="28" height="28"> <span>DartPad</span></a></li><li role="presentation"><a href="https://pub.dev" class="site-wordmark" role="menuitem" title="pub.dev homepage" aria-label="Go to the pub.dev homepage"><img src="/assets/images/branding/dart/logo.svg" alt="Dart logo" width="28" height="28"> <span>pub.dev</span></a></li></ul></nav></div></div><div class="navbar-contents"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="https://flutter.dev">Homepage</a></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev/community">Community</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev">Packages</a></li><li class="nav-item"><a class="nav-link" href="https://api.flutter.dev">API reference</a></li></ul><form action="/search/" class="site-header__search"><input class="site-header__searchfield search-field" type="search" name="q" id="q" autocomplete="off" placeholder="Search" aria-label="Search"></form><a href="/search" id="fallback-search-button" class="icon-button" aria-label="Navigate to the docs search page." title="Navigate to the docs search page."><span class="material-symbols" aria-hidden="true">search</span> </a><a id="call-to-action" class="filled-button" href="/get-started/install/">Get started</a> <button id="menu-toggle" class="icon-button" type="button" aria-controls="sidenav" aria-label="Toggle navigation" title="Toggle navigation"><span class="material-symbols" aria-hidden="true">menu</span></button></div></nav></header><div id="site-below-header"><div id="site-main-row"><div id="sidenav" class="site-sidebar"><nav><ul><li class="nav-header">Get started</li><li class="nav-item"><a class="nav-link" href="/get-started/install"><div><span>Set up Flutter</span></div></a></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-3" role="button" aria-expanded="false" aria-controls="sidenav-3"><span>Learn Flutter</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-3"><li class="nav-item"><a class="nav-link" href="/get-started/learn-flutter"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/codelab"><div><span>Write your first app</span></div></a></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#sidenav-3-3" role="button" aria-expanded="true" aria-controls="sidenav-3-3"><span>Learn the fundamentals</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="sidenav-3-3"><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/dart"><div><span>Intro to Dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/widgets"><div><span>Widgets</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/layout"><div><span>Layout</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/state-management"><div><span>State management</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/user-input"><div><span>Handling user input</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/networking"><div><span>Networking and data</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/local-caching"><div><span>Local data and caching</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-3-4" role="button" aria-expanded="false" aria-controls="sidenav-3-4"><span>From another platform?</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-3-4"><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/android-devs"><div><span>Flutter for Android devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/compose-devs"><div><span>Flutter for Jetpack Compose devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/swiftui-devs"><div><span>Flutter for SwiftUI devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/uikit-devs"><div><span>Flutter for UIKit devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/react-native-devs"><div><span>Flutter for React Native devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/web-devs"><div><span>Flutter for web devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/xamarin-forms-devs"><div><span>Flutter for Xamarin.Forms devs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/declarative"><div><span>Introduction to declarative UI</span></div></a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/dart-swift-concurrency"><div><span>Flutter versus Swift concurrency</span></div></a></li></ul></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/codelabs"><div><span>Codelabs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook"><div><span>Cookbook</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://github.com/flutter/samples" target="_blank" rel="noopener"><div><span>Demos and samples</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-4" role="button" aria-expanded="false" aria-controls="sidenav-4"><span>Stay up to date</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-4"><li class="nav-item"><a class="nav-link" href="/release/upgrade"><div><span>Upgrade</span></div></a></li><li class="nav-item"><a class="nav-link" href="/release/archive"><div><span>SDK archive</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/release/whats-new"><div><span>What's new</span></div></a></li><li class="nav-item"><a class="nav-link" href="/release/release-notes"><div><span>Release notes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes"><div><span>Breaking changes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/release/compatibility-policy"><div><span>Compatibility policy</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-5" role="button" aria-expanded="false" aria-controls="sidenav-5"><span>App solutions</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5"><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-1" role="button" aria-expanded="false" aria-controls="sidenav-5-1"><span>AI</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-1"><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-1-1" role="button" aria-expanded="false" aria-controls="sidenav-5-1-1"><span>AI Toolkit guide</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-1-1"><li class="nav-item"><a class="nav-link" href="/ai-toolkit"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ai-toolkit/user-experience"><div><span>User experience</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ai-toolkit/feature-integration"><div><span>Feature integration</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ai-toolkit/custom-llm-providers"><div><span>Custom LLM providers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ai-toolkit/chat-client-sample"><div><span>Chat client sample</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=1AuzJEiHjO4" target="_blank" rel="noopener"><div><span>Build with Google AI Dart SDK (video)</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-2" role="button" aria-expanded="false" aria-controls="sidenav-5-2"><span>Firebase & Firestore</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter" target="_blank" rel="noopener"><div><span>Discover Firebase for Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=wUSkeTaBonA" target="_blank" rel="noopener"><div><span>Get to know Firebase for Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener"><div><span>Add a user authentication flow to a Flutter app using FirebaseUI</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-get-to-know-web" target="_blank" rel="noopener"><div><span>Get to know Firebase for web</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-3" role="button" aria-expanded="false" aria-controls="sidenav-5-3"><span>Games</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-3"><li class="nav-item"><a class="nav-link" href="/resources/games-toolkit"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/achievements-leaderboard"><div><span>Add achievements and leaderboards</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/build-leaderboards-with-firestore#0" target="_blank" rel="noopener"><div><span>Build leaderboards with Firestore</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads"><div><span>Add advertising</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/firestore-multiplayer"><div><span>Add multiplayer support</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener"><div><span>Add in-app purchases</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener"><div><span>Add user authentication</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/crashlytics/get-started?platform=flutter" target="_blank" rel="noopener"><div><span>Debug using Crashlytics</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-flame-brick-breaker" target="_blank" rel="noopener"><div><span>Intro to Flame with Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-4" role="button" aria-expanded="false" aria-controls="sidenav-5-4"><span>Monetization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-4"><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-4-1" role="button" aria-expanded="false" aria-controls="sidenav-5-4-1"><span>Advertising</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-4-1"><li class="nav-item"><a class="nav-link" href="/resources/ads-overview"><div><span>Ads overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads"><div><span>Add advertising</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-ads-in-flutter" target="_blank" rel="noopener"><div><span>Add AdMob ads to your Flutter app</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-inline-ads-in-flutter" target="_blank" rel="noopener"><div><span>Add an AdMob banner and native inline ads</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/admob/flutter/mediation" target="_blank" rel="noopener"><div><span>Google AdMob mediation</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/interactive_media_ads" target="_blank" rel="noopener"><div><span>Interactive Media Ads SDK</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-4-2" role="button" aria-expanded="false" aria-controls="sidenav-5-4-2"><span>In-app purchases</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-4-2"><li class="nav-item"><a class="nav-link" href="/resources/in-app-purchases-overview"><div><span>In-app purchases overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener"><div><span>Add in-app purchases</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-4-3" role="button" aria-expanded="false" aria-controls="sidenav-5-4-3"><span>Payments</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-4-3"><li class="nav-item"><a class="nav-link" href="/resources/payments-overview"><div><span>Payments overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/pay" target="_blank" rel="noopener"><div><span>Google pay package</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-5" role="button" aria-expanded="false" aria-controls="sidenav-5-5"><span>Maps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-5"><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/google-maps-in-flutter" target="_blank" rel="noopener"><div><span>Add Google maps to a Flutter app</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/maps/flutter-package" target="_blank" rel="noopener"><div><span>Google Maps package</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-6" role="button" aria-expanded="false" aria-controls="sidenav-5-6"><span>News</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/resources/news-toolkit"><div><span>Build a news app</span></div></a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-header">User interface</li><li class="nav-item"><a class="nav-link" href="/ui"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/widgets"><div><span>Widget catalog</span></div></a></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-10" role="button" aria-expanded="false" aria-controls="sidenav-10"><span>Layout</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-10"><li class="nav-item"><a class="nav-link" href="/ui/layout"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/tutorial"><div><span>Build a layout</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-10-3" role="button" aria-expanded="false" aria-controls="sidenav-10-3"><span>Lists & grids</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-10-3"><li class="nav-item"><a class="nav-link" href="/cookbook/lists/basic-list"><div><span>Create and use lists</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/horizontal-list"><div><span>Create a horizontal list</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/grid-lists"><div><span>Create a grid view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/mixed-list"><div><span>Create lists with different types of items</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/spaced-items"><div><span>Create lists with spaced items</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/long-lists"><div><span>Work with long lists</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-10-4" role="button" aria-expanded="false" aria-controls="sidenav-10-4"><span>Scrolling</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-10-4"><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling/slivers"><div><span>Use slivers to achieve fancy scrolling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/floating-app-bar"><div><span>Place a floating app bar above a list</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/parallax-scrolling"><div><span>Create a scrolling parallax effect</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-11" role="button" aria-expanded="false" aria-controls="sidenav-11"><span>Adaptive & responsive design</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-11"><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/general"><div><span>General approach</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/safearea-mediaquery"><div><span>SafeArea & MediaQuery</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/large-screens"><div><span>Large screens & foldables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/input"><div><span>User input & accessibility</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/capabilities"><div><span>Capabilities & policies</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/platform-adaptations"><div><span>Automatic platform adaptations</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/best-practices"><div><span>Best practices</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/more-info"><div><span>Additional resources</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-12" role="button" aria-expanded="false" aria-controls="sidenav-12"><span>Design & theming</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-12"><li class="nav-item"><a class="nav-link" href="/cookbook/design/themes"><div><span>Share styles with themes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/design/material"><div><span>Material design</span></div></a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes/material-3-migration"><div><span>Migrate to Material 3</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-12-4" role="button" aria-expanded="false" aria-controls="sidenav-12-4"><span>Text</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-12-4"><li class="nav-item"><a class="nav-link" href="/ui/design/text/typography"><div><span>Fonts & typography</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/fonts"><div><span>Use a custom font</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/package-fonts"><div><span>Export fonts from a package</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/google_fonts" target="_blank" rel="noopener"><div><span>Google Fonts package</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-12-5" role="button" aria-expanded="false" aria-controls="sidenav-12-5"><span>Custom graphics</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-12-5"><li class="nav-item"><a class="nav-link" href="/ui/design/graphics/fragment-shaders"><div><span>Use custom fragment shaders</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#sidenav-13" role="button" aria-expanded="true" aria-controls="sidenav-13"><span>Interactivity</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="sidenav-13"><li class="nav-item"><a class="nav-link active" href="/ui/interactivity"><div><span>Add interactivity to your app</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-13-2" role="button" aria-expanded="false" aria-controls="sidenav-13-2"><span>Gestures</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-13-2"><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/handling-taps"><div><span>Handle taps</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures/drag-outside"><div><span>Drag an object outside an app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/drag-a-widget"><div><span>Drag a UI element within an app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/ripples"><div><span>Add Material touch ripples</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/dismissible"><div><span>Implement swipe to dismiss</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-13-3" role="button" aria-expanded="false" aria-controls="sidenav-13-3"><span>Input & forms</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-13-3"><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-input"><div><span>Create and style a text field</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/retrieve-input"><div><span>Retrieve the value of a text field</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-field-changes"><div><span>Handle changes to a text field</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/focus"><div><span>Manage focus in text fields</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/validation"><div><span>Build a form with validation</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/snackbars"><div><span>Display a snackbar</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/actions-and-shortcuts"><div><span>Implement actions & shortcuts</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/focus"><div><span>Manage keyboard focus</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-14" role="button" aria-expanded="false" aria-controls="sidenav-14"><span>Assets & media</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-14"><li class="nav-item"><a class="nav-link" href="/ui/assets/assets-and-images"><div><span>Add assets and images</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/network-image"><div><span>Display images from the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/fading-in-images"><div><span>Fade in images with a placeholder</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/play-video"><div><span>Play and pause a video</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/assets/asset-transformation"><div><span>Transform assets at build time</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-15" role="button" aria-expanded="false" aria-controls="sidenav-15"><span>Navigation & routing</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-15"><li class="nav-item"><a class="nav-link" href="/ui/navigation"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/tabs"><div><span>Add tabs to your app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/navigation-basics"><div><span>Navigate to a new screen and back</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/passing-data"><div><span>Send data to a new screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/returning-data"><div><span>Return data from a screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/drawer"><div><span>Add a drawer to a screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/deep-linking"><div><span>Set up deep linking</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-app-links"><div><span>Set up app links for Android</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-universal-links"><div><span>Set up universal links for iOS</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/url-strategies"><div><span>Configure web URL strategies</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-16" role="button" aria-expanded="false" aria-controls="sidenav-16"><span>Animations & transitions</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-16"><li class="nav-item"><a class="nav-link" href="/ui/animations"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/tutorial"><div><span>Tutorial</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/implicit-animations"><div><span>Implicit animations</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/animated-container"><div><span>Animate the properties of a container</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/opacity-animation"><div><span>Fade a widget in and out</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/hero-animations"><div><span>Hero animations</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/page-route-animation"><div><span>Animate a page route transition</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/physics-simulation"><div><span>Animate using a physics simulation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/staggered-animations"><div><span>Staggered animations</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/staggered-menu-animation"><div><span>Create a staggered menu animation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/overview"><div><span>API overview</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-17" role="button" aria-expanded="false" aria-controls="sidenav-17"><span>Accessibility & internationalization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-17"><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/accessibility"><div><span>Accessibility</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/internationalization"><div><span>Internationalization</span></div></a></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-header">Beyond UI</li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-20" role="button" aria-expanded="false" aria-controls="sidenav-20"><span>Data & backend</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20"><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-20-1" role="button" aria-expanded="false" aria-controls="sidenav-20-1"><span>State management</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20-1"><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/intro"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/declarative"><div><span>Think declaratively</span></div></a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/ephemeral-vs-app"><div><span>Ephemeral vs app state</span></div></a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/simple"><div><span>Simple app state management</span></div></a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/options"><div><span>Options</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-20-2" role="button" aria-expanded="false" aria-controls="sidenav-20-2"><span>Networking & http</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/networking"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/fetch-data"><div><span>Fetch data from the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/authenticated-requests"><div><span>Make authenticated requests</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/send-data"><div><span>Send data to the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/update-data"><div><span>Update data over the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/delete-data"><div><span>Delete data on the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/web-sockets"><div><span>Communicate with WebSockets</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-20-3" role="button" aria-expanded="false" aria-controls="sidenav-20-3"><span>Serialization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20-3"><li class="nav-item"><a class="nav-link" href="/data-and-backend/serialization/json"><div><span>JSON serialization</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/background-parsing"><div><span>Parse JSON in the background</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-20-4" role="button" aria-expanded="false" aria-controls="sidenav-20-4"><span>Persistence</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20-4"><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/key-value"><div><span>Store key-value data on disk</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/reading-writing-files"><div><span>Read and write files</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/sqlite"><div><span>Persist data with SQLite</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-20-5" role="button" aria-expanded="false" aria-controls="sidenav-20-5"><span>Firebase</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-20-5"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter/setup" target="_blank" rel="noopener"><div><span>Add Firebase to your Flutter app</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/google-apis"><div><span>Google APIs</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-21" role="button" aria-expanded="false" aria-controls="sidenav-21"><span>App architecture</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-21"><li class="nav-item"><a class="nav-link" href="/app-architecture"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/concepts"><div><span>Architecture concepts</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/guide"><div><span>Guide to app architecture</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-21-4" role="button" aria-expanded="false" aria-controls="sidenav-21-4"><span>Architecture case study</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-21-4"><li class="nav-item"><a class="nav-link" href="/app-architecture/case-study"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/case-study/ui-layer"><div><span>UI layer</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/case-study/data-layer"><div><span>Data layer</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/case-study/dependency-injection"><div><span>Dependency injection</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/case-study/testing"><div><span>Testing each layer</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/app-architecture/recommendations"><div><span>Recommendations</span></div></a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/design-patterns"><div><span>Design patterns</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-22" role="button" aria-expanded="false" aria-controls="sidenav-22"><span>Platform integration</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22"><li class="nav-item"><a class="nav-link" href="/reference/supported-platforms"><div><span>Supported platforms</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/desktop"><div><span>Build desktop apps with Flutter</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/platform-channels"><div><span>Write platform-specific code</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-4" role="button" aria-expanded="false" aria-controls="sidenav-22-4"><span>Android</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-4"><li class="nav-item"><a class="nav-link" href="/platform-integration/android/install-android"><div><span>Add Android as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/splash-screen"><div><span>Add a splash screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/predictive-back"><div><span>Add predictive back</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/c-interop"><div><span>Bind to native code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/platform-views"><div><span>Host a native Android view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/call-jetpack-apis"><div><span>Calling JetPack APIs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/compose-activity"><div><span>Launch a Jetpack Compose activity</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/restore-state-android"><div><span>Restore state on Android</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/chromeos"><div><span>Target ChromeOS with Android</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-5" role="button" aria-expanded="false" aria-controls="sidenav-22-5"><span>iOS</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-5"><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/install-ios"><div><span>Add iOS as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-latest"><div><span>Flutter on latest iOS</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/apple-frameworks"><div><span>Leverage Apple's system libraries</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/launch-screen"><div><span>Add a launch screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-app-clip"><div><span>Add iOS App Clip support</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/app-extensions"><div><span>Add iOS app extensions</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/c-interop"><div><span>Bind to native code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/platform-views"><div><span>Host a native iOS view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-debugging"><div><span>Enable debugging on iOS</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/restore-state-ios"><div><span>Restore state on iOS</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-6" role="button" aria-expanded="false" aria-controls="sidenav-22-6"><span>Linux</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-6"><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/install-linux"><div><span>Add Linux as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/building"><div><span>Build a Linux app</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-7" role="button" aria-expanded="false" aria-controls="sidenav-22-7"><span>macOS</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-7"><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/install-macos"><div><span>Add macOS as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/building"><div><span>Build a macOS app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/c-interop"><div><span>Bind to native code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/platform-views"><div><span>Host a native macOS view</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-8" role="button" aria-expanded="false" aria-controls="sidenav-22-8"><span>Web</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-8"><li class="nav-item"><a class="nav-link" href="/platform-integration/web"><div><span>Web support in Flutter</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/install-web"><div><span>Add web as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/building"><div><span>Build a web app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/wasm"><div><span>Compile to WebAssembly</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/initialization"><div><span>Customize app initialization</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web"><div><span>Add Flutter to any web app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-content-in-flutter"><div><span>Web content in Flutter</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/renderers"><div><span>Web renderers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-images"><div><span>Display images on the web</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/faq"><div><span>Web FAQ</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-22-9" role="button" aria-expanded="false" aria-controls="sidenav-22-9"><span>Windows</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-22-9"><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/install-windows"><div><span>Add Windows as build target</span></div></a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/building"><div><span>Build a Windows app</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-23" role="button" aria-expanded="false" aria-controls="sidenav-23"><span>Packages & plugins</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-23"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/using-packages"><div><span>Use packages & plugins</span></div></a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/developing-packages"><div><span>Develop packages & plugins</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-23-3" role="button" aria-expanded="false" aria-controls="sidenav-23-3"><span>Swift Package Manager</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-23-3"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-app-developers"><div><span>For app developers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-plugin-authors"><div><span>For plugin authors</span></div></a></li></ul></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/favorites"><div><span>Flutter Favorites</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/flutter" target="_blank" rel="noopener"><div><span>Package repository</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-24" role="button" aria-expanded="false" aria-controls="sidenav-24"><span>Testing & debugging</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-24"><li class="nav-header">Testing</li><li class="nav-item"><a class="nav-link" href="/testing/overview"><div><span>Overview</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-24-3" role="button" aria-expanded="false" aria-controls="sidenav-24-3"><span>Unit testing</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-24-3"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/introduction"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/mocking"><div><span>Mock dependencies</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-24-4" role="button" aria-expanded="false" aria-controls="sidenav-24-4"><span>Widget testing</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-24-4"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/introduction"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/finders"><div><span>Find widgets</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/scrolling"><div><span>Simulate scrolling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/tap-drag"><div><span>Simulate user interaction</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-24-5" role="button" aria-expanded="false" aria-controls="sidenav-24-5"><span>Integration testing</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-24-5"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/introduction"><div><span>Introduction</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/integration-tests"><div><span>Write and run an integration test</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/profiling"><div><span>Profile an integration test</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/testing/testing-plugins"><div><span>Test a plugin</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/plugins-in-tests"><div><span>Handle plugin code in tests</span></div></a></li><li class="nav-header">Debugging</li><li class="nav-item"><a class="nav-link" href="/testing/debugging"><div><span>Debugging tools</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/code-debugging"><div><span>Debug your app programmatically</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/native-debugging"><div><span>Use a native language debugger</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/common-errors"><div><span>Common Flutter errors</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/errors"><div><span>Handle errors</span></div></a></li><li class="nav-item"><a class="nav-link" href="/cookbook/maintenance/error-reporting"><div><span>Report errors to a service</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-25" role="button" aria-expanded="false" aria-controls="sidenav-25"><span>Performance & optimization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-25"><li class="nav-item"><a class="nav-link" href="/perf"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/impeller"><div><span>Impeller</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/best-practices"><div><span>Performance best practices</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/app-size"><div><span>App size</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/deferred-components"><div><span>Deferred components</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/rendering-performance"><div><span>Rendering performance</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/ui-performance"><div><span>Performance profiling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/web-performance"><div><span>Performance profiling for web</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/metrics"><div><span>Performance metrics</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/isolates"><div><span>Concurrency and isolates</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/faq"><div><span>Performance FAQ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/perf/appendix"><div><span>Appendix</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-26" role="button" aria-expanded="false" aria-controls="sidenav-26"><span>Deployment</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-26"><li class="nav-item"><a class="nav-link" href="/deployment/obfuscate"><div><span>Obfuscate Dart code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/flavors"><div><span>Create app flavors for Android</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/flavors-ios"><div><span>Create app flavors for iOS and macOS</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/android"><div><span>Build and release an Android app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/ios"><div><span>Build and release an iOS app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/macos"><div><span>Build and release a macOS app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/linux"><div><span>Build and release a Linux app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/windows"><div><span>Build and release a Windows app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/web"><div><span>Build and release a web app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/deployment/cd"><div><span>Set up continuous deployment</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-27" role="button" aria-expanded="false" aria-controls="sidenav-27"><span>Add to an existing app</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-27"><li class="nav-item"><a class="nav-link" href="/add-to-app"><div><span>Introduction</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-27-2" role="button" aria-expanded="false" aria-controls="sidenav-27-2"><span>Add to an Android app</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-27-2"><li class="nav-item"><a class="nav-link" href="/add-to-app/android/project-setup"><div><span>Set up Android project</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-screen"><div><span>Add a single Flutter screen</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-fragment"><div><span>Add a Flutter Fragment</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-view"><div><span>Add a Flutter View</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/plugin-setup"><div><span>Use a Flutter plugin</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-27-3" role="button" aria-expanded="false" aria-controls="sidenav-27-3"><span>Add to an iOS app</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-27-3"><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/project-setup"><div><span>Set up iOS project</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/add-flutter-screen"><div><span>Add a single Flutter screen</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web"><div><span>Add to a web app</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/debugging"><div><span>Debug embedded Flutter module</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/multiple-flutters"><div><span>Add multiple Flutter instances</span></div></a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/performance"><div><span>Loading sequence and performance</span></div></a></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-29" role="button" aria-expanded="false" aria-controls="sidenav-29"><span>Tools & editors</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-29"><li class="nav-item"><a class="nav-link" href="/tools/android-studio"><div><span>Android Studio & IntelliJ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code"><div><span>Visual Studio Code</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-29-3" role="button" aria-expanded="false" aria-controls="sidenav-29-3"><span>DevTools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-29-3"><li class="nav-item"><a class="nav-link" href="/tools/devtools"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/android-studio"><div><span>Run from Android Studio & IntelliJ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/vscode"><div><span>Run from VS Code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cli"><div><span>Run from command line</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/inspector"><div><span>Flutter inspector</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/legacy-inspector"><div><span>Legacy Flutter inspector</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/performance"><div><span>Performance view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cpu-profiler"><div><span>CPU Profiler view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/memory"><div><span>Memory view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/console"><div><span>Debug console view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/network"><div><span>Network view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/debugger"><div><span>Debugger</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/logging"><div><span>Logging view</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/app-size"><div><span>App size tool</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/extensions"><div><span>DevTools extensions</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/deep-links"><div><span>Validate deep links</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/release-notes"><div><span>Release notes</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/sdk"><div><span>SDK overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pubspec"><div><span>Flutter's pubspec options</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/flutter-fix"><div><span>Automated fixes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/formatting"><div><span>Code formatting</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-30" role="button" aria-expanded="false" aria-controls="sidenav-30"><span>Flutter concepts</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-30"><li class="nav-item"><a class="nav-link" href="/resources/architectural-overview"><div><span>Architectural overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/inside-flutter"><div><span>Inside Flutter</span></div></a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/constraints"><div><span>Understanding constraints</span></div></a></li><li class="nav-item"><a class="nav-link" href="/testing/build-modes"><div><span>Flutter's build modes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/hot-reload"><div><span>Hot reload</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#sidenav-31" role="button" aria-expanded="false" aria-controls="sidenav-31"><span>Resources</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-31"><li class="nav-item"><a class="nav-link" href="/resources/faq"><div><span>FAQ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/books"><div><span>Books</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/videos"><div><span>Videos</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/courses"><div><span>Courses</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/bootstrap-into-dart"><div><span>Learn Dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/support"><div><span>Get support</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-31-8" role="button" aria-expanded="false" aria-controls="sidenav-31-8"><span>Contribute</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-31-8"><li class="nav-item"><a class="nav-link" href="/resources/bug-reports"><div><span>Create useful bug reports</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://github.com/flutter/flutter/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener"><div><span>Contribute to Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/design-docs"><div><span>Discover proposed features</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-31-9" role="button" aria-expanded="false" aria-controls="sidenav-31-9"><span>Reference</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="sidenav-31-9"><li class="nav-item"><a class="nav-link" href="/dash"><div><span>Who is Dash?</span></div></a></li><li class="nav-item"><a class="nav-link" href="/reference/widgets"><div><span>Widget index</span></div></a></li><li class="nav-item"><a class="nav-link" href="/reference/flutter-cli"><div><span>flutter CLI</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://api.flutter.dev" target="_blank" rel="noopener"><div><span>API docs</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li></ul></li></ul></nav></div><main class="site-content"><div id="site-toc--side" class="site-toc"><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry nav-item"><a class="nav-link" href="#stateful-and-stateless-widgets">Stateful and stateless widgets</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#creating-a-stateful-widget">Creating a stateful widget</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#step-0-get-ready">Step 0: Get ready</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#step-1-decide-which-object-manages-the-widgets-state">Step 1: Decide which object manages the widget's state</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#step-2-subclass-statefulwidget">Step 2: Subclass StatefulWidget</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#step-3-subclass-state">Step 3: Subclass State</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#step-4-plug-the-stateful-widget-into-the-widget-tree">Step 4: Plug the stateful widget into the widget tree</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#problems">Problems?</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#managing-state">Managing state</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#the-widget-manages-its-own-state">The widget manages its own state</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-parent-widget-manages-the-widgets-state">The parent widget manages the widget's state</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#a-mix-and-match-approach">A mix-and-match approach</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#other-interactive-widgets">Other interactive widgets</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#standard-widgets">Standard widgets</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#material-components">Material Components</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#resources">Resources</a></li></ul></div><article><header class="site-content__title"><h1 id="document-title">Add interactivity to your Flutter app</h1><nav class="breadcrumbs" aria-label="breadcrumb"><ol vocab="https://schema.org/" typeof="BreadcrumbList"><li class="breadcrumb-item" property="itemListElement" typeof="ListItem"><a href="/ui" property="item" typeof="WebPage"><span property="name">UI</span></a><meta property="position" content="0"><span class="material-symbols child-icon" aria-hidden="true">chevron_right</span></li><li class="breadcrumb-item active" property="itemListElement" typeof="ListItem" aria-current="page"><a href="/ui/interactivity" property="item" typeof="WebPage"><span property="name">Interactivity</span></a><meta property="position" content="1"></li></ol></nav></header><div id="site-toc--inline" class="site-toc toc-collapsible toc-collapsed"><header class="site-toc__title">Contents <span class="site-toc--inline__toggle toc-toggle-down" title="Expand table of contents"><i class="material-symbols" aria-hidden="true">keyboard_arrow_down</i></span> <span class="site-toc--inline__toggle toc-toggle-up" title="Collapse table of contents"><i class="material-symbols" aria-hidden="true">keyboard_arrow_up</i></span></header><ul class="section-nav"><li class="toc-entry"><a href="#stateful-and-stateless-widgets">Stateful and stateless widgets</a></li><li class="toc-entry"><a href="#creating-a-stateful-widget">Creating a stateful widget</a><ul><li class="toc-entry"><a href="#step-0-get-ready">Step 0: Get ready</a></li><li class="toc-entry"><a href="#step-1-decide-which-object-manages-the-widgets-state">Step 1: Decide which object manages the widget's state</a></li><li class="toc-entry"><a href="#step-2-subclass-statefulwidget">Step 2: Subclass StatefulWidget</a></li><li class="toc-entry"><a href="#step-3-subclass-state">Step 3: Subclass State</a></li><li class="toc-entry"><a href="#step-4-plug-the-stateful-widget-into-the-widget-tree">Step 4: Plug the stateful widget into the widget tree</a></li><li class="toc-entry"><a href="#problems">Problems?</a></li></ul></li><li class="toc-entry"><a href="#managing-state">Managing state</a><ul><li class="toc-entry"><a href="#the-widget-manages-its-own-state">The widget manages its own state</a></li><li class="toc-entry"><a href="#the-parent-widget-manages-the-widgets-state">The parent widget manages the widget's state</a></li><li class="toc-entry"><a href="#a-mix-and-match-approach">A mix-and-match approach</a></li></ul></li><li class="toc-entry"><a href="#other-interactive-widgets">Other interactive widgets</a><ul><li class="toc-entry"><a href="#standard-widgets">Standard widgets</a></li><li class="toc-entry"><a href="#material-components">Material Components</a></li></ul></li><li class="toc-entry"><a href="#resources">Resources</a></li></ul><span class="site-toc--inline__toggle toc-toggle-more-items" title="Expand table of contents"><i class="material-symbols" aria-hidden="true">more_horiz</i></span></div><aside class="alert alert-secondary"><div class="alert-header"><span>What you'll learn</span></div><div class="alert-content"><ul><li>How to respond to taps.</li><li>How to create a custom widget.</li><li>The difference between stateless and stateful widgets.</li></ul></div></aside><p>How do you modify your app to make it react to user input? In this tutorial, you'll add interactivity to an app that contains only non-interactive widgets. Specifically, you'll modify an icon to make it tappable by creating a custom stateful widget that manages two stateless widgets.</p><p>The <a href="/ui/layout/tutorial">building layouts tutorial</a> showed you how to create the layout for the following screenshot.</p><figure class=""><div class="site-figure-container"><img src="/assets/images/docs/ui/layout/lakes.jpg" class="site-mobile-screenshot border" alt="The layout tutorial app" style=""><figcaption class="figure-caption">The layout tutorial app</figcaption></div></figure><p>When the app first launches, the star is solid red, indicating that this lake has previously been favorited. The number next to the star indicates that 41 people have favorited this lake. After completing this tutorial, tapping the star removes its favorited status, replacing the solid star with an outline and decreasing the count. Tapping again favorites the lake, drawing a solid star and increasing the count.</p><figure class=""><div class="site-figure-container"><img src="/assets/images/docs/ui/favorited-not-favorited.png" class="" alt="The custom widget you'll create" style=""></div></figure><p>To accomplish this, you'll create a single custom widget that includes both the star and the count, which are themselves widgets. Tapping the star changes state for both widgets, so the same widget should manage both.</p><p>You can get right to touching the code in <a href="#step-2">Step 2: Subclass StatefulWidget</a>. If you want to try different ways of managing state, skip to <a href="#managing-state">Managing state</a>.</p><div class="header-wrapper"><h2 id="stateful-and-stateless-widgets">Stateful and stateless widgets</h2><a class="heading-link" href="#stateful-and-stateless-widgets" aria-label="Link to 'Stateful and stateless widgets' section">#</a></div><p>A widget is either stateful or stateless. If a widget can change—when a user interacts with it, for example—it's stateful.</p><p>A <em>stateless</em> widget never changes. <a href="https://api.flutter.dev/flutter/widgets/Icon-class.html"><code>Icon</code></a>, <a href="https://api.flutter.dev/flutter/material/IconButton-class.html"><code>IconButton</code></a>, and <a href="https://api.flutter.dev/flutter/widgets/Text-class.html"><code>Text</code></a> are examples of stateless widgets. Stateless widgets subclass <a href="https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html"><code>StatelessWidget</code></a>.</p><p>A <em>stateful</em> widget is dynamic: for example, it can change its appearance in response to events triggered by user interactions or when it receives data. <a href="https://api.flutter.dev/flutter/material/Checkbox-class.html"><code>Checkbox</code></a>, <a href="https://api.flutter.dev/flutter/material/Radio-class.html"><code>Radio</code></a>, <a href="https://api.flutter.dev/flutter/material/Slider-class.html"><code>Slider</code></a>, <a href="https://api.flutter.dev/flutter/material/InkWell-class.html"><code>InkWell</code></a>, <a href="https://api.flutter.dev/flutter/widgets/Form-class.html"><code>Form</code></a>, and <a href="https://api.flutter.dev/flutter/material/TextField-class.html"><code>TextField</code></a> are examples of stateful widgets. Stateful widgets subclass <a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html"><code>StatefulWidget</code></a>.</p><p>A widget's state is stored in a <a href="https://api.flutter.dev/flutter/widgets/State-class.html"><code>State</code></a> object, separating the widget's state from its appearance. The state consists of values that can change, like a slider's current value or whether a checkbox is checked. When the widget's state changes, the state object calls <code>setState()</code>, telling the framework to redraw the widget.</p><div class="header-wrapper"><h2 id="creating-a-stateful-widget">Creating a stateful widget</h2><a class="heading-link" href="#creating-a-stateful-widget" aria-label="Link to 'Creating a stateful widget' section">#</a></div><aside class="alert alert-secondary"><div class="alert-header"><span>What's the point?</span></div><div class="alert-content"><ul><li>A stateful widget is implemented by two classes: a subclass of <code>StatefulWidget</code> and a subclass of <code>State</code>.</li><li>The state class contains the widget's mutable state and the widget's <code>build()</code> method.</li><li>When the widget's state changes, the state object calls <code>setState()</code>, telling the framework to redraw the widget.</li></ul></div></aside><p>In this section, you'll create a custom stateful widget. You'll replace two stateless widgets—the solid red star and the numeric count next to it—with a single custom stateful widget that manages a row with two children widgets: an <code>IconButton</code> and <code>Text</code>.</p><p>Implementing a custom stateful widget requires creating two classes:</p><ul><li>A subclass of <code>StatefulWidget</code> that defines the widget.</li><li>A subclass of <code>State</code> that contains the state for that widget and defines the widget's <code>build()</code> method.</li></ul><p>This section shows you how to build a stateful widget, called <code>FavoriteWidget</code>, for the lakes app. After setting up, your first step is choosing how state is managed for <code>FavoriteWidget</code>.</p><div class="header-wrapper"><h3 id="step-0-get-ready">Step 0: Get ready</h3><a class="heading-link" href="#step-0-get-ready" aria-label="Link to 'Step 0: Get ready' section">#</a></div><p>If you've already built the app in the <a href="/ui/layout/tutorial">building layouts tutorial</a>, skip to the next section.</p><ol><li>Make sure you've <a href="/get-started/install">set up</a> your environment.</li><li><a href="/get-started/test-drive">Create a new Flutter app</a>.</li><li>Replace the <code>lib/main.dart</code> file with <a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/step6/lib/main.dart"><code>main.dart</code></a>.</li><li>Replace the <code>pubspec.yaml</code> file with <a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/step6/pubspec.yaml"><code>pubspec.yaml</code></a>.</li><li>Create an <code>images</code> directory in your project, and add <a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/step6/images/lake.jpg"><code>lake.jpg</code></a>.</li></ol><p>Once you have a connected and enabled device, or you've launched the <a href="/get-started/install/macos/mobile-ios#configure-your-target-ios-device">iOS simulator</a> (part of the Flutter install) or the <a href="/get-started/install/windows/mobile?tab=virtual#configure-your-target-android-device">Android emulator</a> (part of the Android Studio install), you are good to go!</p><p><a id="step-1"></a></p><div class="header-wrapper"><h3 id="step-1-decide-which-object-manages-the-widgets-state">Step 1: Decide which object manages the widget's state</h3><a class="heading-link" href="#step-1-decide-which-object-manages-the-widgets-state" aria-label="Link to 'Step 1: Decide which object manages the widget's state' section">#</a></div><p>A widget's state can be managed in several ways, but in our example the widget itself, <code>FavoriteWidget</code>, will manage its own state. In this example, toggling the star is an isolated action that doesn't affect the parent widget or the rest of the UI, so the widget can handle its state internally.</p><p>Learn more about the separation of widget and state, and how state might be managed, in <a href="#managing-state">Managing state</a>.</p><p><a id="step-2"></a></p><div class="header-wrapper"><h3 id="step-2-subclass-statefulwidget">Step 2: Subclass StatefulWidget</h3><a class="heading-link" href="#step-2-subclass-statefulwidget" aria-label="Link to 'Step 2: Subclass StatefulWidget' section">#</a></div><p>The <code>FavoriteWidget</code> class manages its own state, so it overrides <code>createState()</code> to create a <code>State</code> object. The framework calls <code>createState()</code> when it wants to build the widget. In this example, <code>createState()</code> returns an instance of <code>_FavoriteWidgetState</code>, which you'll implement in the next step.</p> <?code-excerpt path-base="layout/lakes/interactive"?> <?code-excerpt "lib/main.dart (favorite-widget)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> FavoriteWidget</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> FavoriteWidget</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">FavoriteWidget</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_FavoriteWidgetState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><aside class="alert alert-info"><div class="alert-header"><i class="material-symbols" aria-hidden="true">info</i> <span>Note</span></div><div class="alert-content"><p>Members or classes that start with an underscore (<code>_</code>) are private. For more information, see <a href="https://dart.dev/language/libraries">Libraries and imports</a>, a section in the <a href="https://dart.dev/language">Dart language documentation</a>.</p></div></aside><p><a id="step-3"></a></p><div class="header-wrapper"><h3 id="step-3-subclass-state">Step 3: Subclass State</h3><a class="heading-link" href="#step-3-subclass-state" aria-label="Link to 'Step 3: Subclass State' section">#</a></div><p>The <code>_FavoriteWidgetState</code> class stores the mutable data that can change over the lifetime of the widget. When the app first launches, the UI displays a solid red star, indicating that the lake has "favorite" status, along with 41 likes. These values are stored in the <code>_isFavorited</code> and <code>_favoriteCount</code> fields:</p> <?code-excerpt "lib/main.dart (favorite-state-fields)" replace="/(bool|int) .*/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _FavoriteWidgetState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">FavoriteWidget</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">bool</span><span style="color:#222222"> _isFavorited = </span><span style="color:#0C7064">true</span><span style="color:#222222">;</span></mark></span> <span class="line"><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">int</span><span style="color:#222222"> _favoriteCount = </span><span style="color:#0C7064">41</span><span style="color:#222222">;</span></mark></span></code></pre></div></div><p>The class also defines a <code>build()</code> method, which creates a row containing a red <code>IconButton</code>, and <code>Text</code>. You use <a href="https://api.flutter.dev/flutter/material/IconButton-class.html"><code>IconButton</code></a> (instead of <code>Icon</code>) because it has an <code>onPressed</code> property that defines the callback function (<code>_toggleFavorite</code>) for handling a tap. You'll define the callback function next.</p> <?code-excerpt "lib/main.dart (favorite-state-build)" replace="/build|icon.*|onPressed.*|child: Text.*/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _FavoriteWidgetState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">FavoriteWidget</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#6E6E70"> // ···</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> </span><mark class="highlight"><span style="color:#6200EE">build</span></mark><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Row</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> mainAxisSize: </span><span style="color:#0468D7">MainAxisSize</span><span style="color:#222222">.min,</span></span> <span class="line"><span style="color:#222222"> children: [</span></span> <span class="line"><span style="color:#0468D7"> Container</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">0</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">IconButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">0</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> alignment: </span><span style="color:#0468D7">Alignment</span><span style="color:#222222">.center,</span></span> <span class="line"><span style="color:#222222"> </span><mark class="highlight"><span style="color:#222222">icon:</span></mark></span> <span class="line"><span style="color:#222222"> (_isFavorited</span></span> <span class="line"><span style="color:#222222"> ? </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.star)</span></span> <span class="line"><span style="color:#222222"> : </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.star_border)),</span></span> <span class="line"><span style="color:#222222"> color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.red[</span><span style="color:#0C7064">500</span><span style="color:#222222">],</span></span> <span class="line"><span style="color:#222222"> </span><mark class="highlight"><span style="color:#222222">onPressed: _toggleFavorite,</span></mark></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#0468D7"> SizedBox</span><span style="color:#222222">(width: </span><span style="color:#0C7064">18</span><span style="color:#222222">, child: </span><span style="color:#0468D7">SizedBox</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#222222">child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'</span><span style="color:#0C7064">$</span><span style="color:#222222">_favoriteCount</span><span style="color:#0C7064">'</span><span style="color:#222222">))),</span></mark></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // ···</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><aside class="alert alert-success"><div class="alert-header"><i class="material-symbols" aria-hidden="true">lightbulb</i> <span>Tip</span></div><div class="alert-content"><p>Placing the <code>Text</code> in a <a href="https://api.flutter.dev/flutter/widgets/SizedBox-class.html"><code>SizedBox</code></a> and setting its width prevents a discernible "jump" when the text changes between the values of 40 and 41 — a jump would otherwise occur because those values have different widths.</p></div></aside><p>The <code>_toggleFavorite()</code> method, which is called when the <code>IconButton</code> is pressed, calls <code>setState()</code>. Calling <code>setState()</code> is critical, because this tells the framework that the widget's state has changed and that the widget should be redrawn. The function argument to <code>setState()</code> toggles the UI between these two states:</p><ul><li>A <code>star</code> icon and the number 41</li><li>A <code>star_border</code> icon and the number 40</li></ul> <?code-excerpt "lib/main.dart (toggle-favorite)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> _toggleFavorite</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (_isFavorited) {</span></span> <span class="line"><span style="color:#222222"> _favoriteCount -= </span><span style="color:#0C7064">1</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> _isFavorited = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#BD2314">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#222222"> _favoriteCount += </span><span style="color:#0C7064">1</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> _isFavorited = </span><span style="color:#0C7064">true</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p><a id="step-4"></a></p><div class="header-wrapper"><h3 id="step-4-plug-the-stateful-widget-into-the-widget-tree">Step 4: Plug the stateful widget into the widget tree</h3><a class="heading-link" href="#step-4-plug-the-stateful-widget-into-the-widget-tree" aria-label="Link to 'Step 4: Plug the stateful widget into the widget tree' section">#</a></div><p>Add your custom stateful widget to the widget tree in the app's <code>build()</code> method. First, locate the code that creates the <code>Icon</code> and <code>Text</code>, and delete it. In the same location, create the stateful widget:</p> <?code-excerpt path-base=""?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">child: </span><span style="color:#0468D7">Row</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> children: [</span></span> <span class="line"><span style="color:#6E6E70"> // ...</span></span> <span class="line removed-line"><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span></span> <span class="line removed-line"><span style="color:#0468D7"> Icons</span><span style="color:#222222">.star,</span></span> <span class="line removed-line"><span style="color:#222222"> color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.red[</span><span style="color:#0C7064">500</span><span style="color:#222222">],</span></span> <span class="line removed-line"><span style="color:#222222"> ),</span></span> <span class="line removed-line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'41'</span><span style="color:#222222">),</span></span> <span class="line added-line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> FavoriteWidget</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222">),</span></span></code></pre></div></div><p>That's it! When you hot reload the app, the star icon should now respond to taps.</p><div class="header-wrapper"><h3 id="problems">Problems?</h3><a class="heading-link" href="#problems" aria-label="Link to 'Problems?' section">#</a></div><p>If you can't get your code to run, look in your IDE for possible errors. <a href="/testing/debugging">Debugging Flutter apps</a> might help. If you still can't find the problem, check your code against the interactive lakes example on GitHub.</p><ul><li><a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/interactive/lib/main.dart"><code>lib/main.dart</code></a></li><li><a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/interactive/pubspec.yaml"><code>pubspec.yaml</code></a></li><li><a href="https://github.com/flutter/website/tree/main/examples/layout/lakes/interactive/images/lake.jpg"><code>lakes.jpg</code></a></li></ul><p>If you still have questions, refer to any one of the developer <a href="https://flutter.dev/community">community</a> channels.</p><hr><p>The rest of this page covers several ways a widget's state can be managed, and lists other available interactive widgets.</p><div class="header-wrapper"><h2 id="managing-state">Managing state</h2><a class="heading-link" href="#managing-state" aria-label="Link to 'Managing state' section">#</a></div><aside class="alert alert-secondary"><div class="alert-header"><span>What's the point?</span></div><div class="alert-content"><ul><li>There are different approaches for managing state.</li><li>You, as the widget designer, choose which approach to use.</li><li>If in doubt, start by managing state in the parent widget.</li></ul></div></aside><p>Who manages the stateful widget's state? The widget itself? The parent widget? Both? Another object? The answer is... it depends. There are several valid ways to make your widget interactive. You, as the widget designer, make the decision based on how you expect your widget to be used. Here are the most common ways to manage state:</p><ul><li><a href="#self-managed">The widget manages its own state</a></li><li><a href="#parent-managed">The parent manages the widget's state</a></li><li><a href="#mix-and-match">A mix-and-match approach</a></li></ul><p>How do you decide which approach to use? The following principles should help you decide:</p><ul><li><p>If the state in question is user data, for example the checked or unchecked mode of a checkbox, or the position of a slider, then the state is best managed by the parent widget.</p></li><li><p>If the state in question is aesthetic, for example an animation, then the state is best managed by the widget itself.</p></li></ul><p>If in doubt, start by managing state in the parent widget.</p><p>We'll give examples of the different ways of managing state by creating three simple examples: TapboxA, TapboxB, and TapboxC. The examples all work similarly—each creates a container that, when tapped, toggles between a green or grey box. The <code>_active</code> boolean determines the color: green for active or grey for inactive.</p><div class="side-by-side text-center"><div class="text-center"><img src="/assets/images/docs/ui/tapbox-active-state.png" class="simple-border" width="150px" alt="Active state"> <img src="/assets/images/docs/ui/tapbox-inactive-state.png" class="simple-border" width="150px" alt="Inactive state"></div></div><p>These examples use <a href="https://api.flutter.dev/flutter/widgets/GestureDetector-class.html"><code>GestureDetector</code></a> to capture activity on the <code>Container</code>.</p><p><a id="self-managed" aria-hidden="true"></a></p><div class="header-wrapper"><h3 id="the-widget-manages-its-own-state">The widget manages its own state</h3><a class="heading-link" href="#the-widget-manages-its-own-state" aria-label="Link to 'The widget manages its own state' section">#</a></div><p>Sometimes it makes the most sense for the widget to manage its state internally. For example, <a href="https://api.flutter.dev/flutter/widgets/ListView-class.html"><code>ListView</code></a> automatically scrolls when its content exceeds the render box. Most developers using <code>ListView</code> don't want to manage <code>ListView</code>'s scrolling behavior, so <code>ListView</code> itself manages its scroll offset.</p><p>The <code>_TapboxAState</code> class:</p><ul><li>Manages state for <code>TapboxA</code>.</li><li>Defines the <code>_active</code> boolean which determines the box's current color.</li><li>Defines the <code>_handleTap()</code> function, which updates <code>_active</code> when the box is tapped and calls the <code>setState()</code> function to update the UI.</li><li>Implements all interactive behavior for the widget.</li></ul> <?code-excerpt path-base="ui/interactive/"?> <?code-excerpt "lib/self_managed.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// TapboxA manages its own state.</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//------------------------- TapboxA ----------------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> TapboxA</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> TapboxA</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">TapboxA</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_TapboxAState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _TapboxAState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">TapboxA</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> _active = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTap</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _active = !_active;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: _handleTap,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Container</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> width: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> height: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> decoration: </span><span style="color:#0468D7">BoxDecoration</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> color: _active ? </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.lightGreen[</span><span style="color:#0C7064">700</span><span style="color:#222222">] : </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.grey[</span><span style="color:#0C7064">600</span><span style="color:#222222">],</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> _active ? </span><span style="color:#0C7064">'Active'</span><span style="color:#222222"> : </span><span style="color:#0C7064">'Inactive'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> style: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> TextStyle</span><span style="color:#222222">(fontSize: </span><span style="color:#0C7064">32</span><span style="color:#222222">, color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.white),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//------------------------- MyApp ----------------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> MyApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MyApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Flutter Demo'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Flutter Demo'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Center</span><span style="color:#222222">(child: </span><span style="color:#0468D7">TapboxA</span><span style="color:#222222">()),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><hr><p><a id="parent-managed"></a></p><div class="header-wrapper"><h3 id="the-parent-widget-manages-the-widgets-state">The parent widget manages the widget's state</h3><a class="heading-link" href="#the-parent-widget-manages-the-widgets-state" aria-label="Link to 'The parent widget manages the widget's state' section">#</a></div><p>Often it makes the most sense for the parent widget to manage the state and tell its child widget when to update. For example, <a href="https://api.flutter.dev/flutter/material/IconButton-class.html"><code>IconButton</code></a> allows you to treat an icon as a tappable button. <code>IconButton</code> is a stateless widget because we decided that the parent widget needs to know whether the button has been tapped, so it can take appropriate action.</p><p>In the following example, TapboxB exports its state to its parent through a callback. Because TapboxB doesn't manage any state, it subclasses StatelessWidget.</p><p>The ParentWidgetState class:</p><ul><li>Manages the <code>_active</code> state for TapboxB.</li><li>Implements <code>_handleTapboxChanged()</code>, the method called when the box is tapped.</li><li>When the state changes, calls <code>setState()</code> to update the UI.</li></ul><p>The TapboxB class:</p><ul><li>Extends StatelessWidget because all state is handled by its parent.</li><li>When a tap is detected, it notifies the parent.</li></ul> <?code-excerpt "lib/parent_managed.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// ParentWidget manages the state for TapboxB.</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//------------------------ ParentWidget --------------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> ParentWidget</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> ParentWidget</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">ParentWidget</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_ParentWidgetState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _ParentWidgetState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">ParentWidget</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> _active = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTapboxChanged</span><span style="color:#222222">(</span><span style="color:#0468D7">bool</span><span style="color:#222222"> newValue) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _active = newValue;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> SizedBox</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">TapboxB</span><span style="color:#222222">(active: _active, onChanged: _handleTapboxChanged),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//------------------------- TapboxB ----------------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> TapboxB</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> TapboxB</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key, </span><span style="color:#BD2314">this</span><span style="color:#222222">.active = </span><span style="color:#0C7064">false</span><span style="color:#222222">, </span><span style="color:#BD2314">required</span><span style="color:#BD2314"> this</span><span style="color:#222222">.onChanged});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> bool</span><span style="color:#222222"> active;</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ValueChanged</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">> onChanged;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTap</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> onChanged</span><span style="color:#222222">(!active);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: _handleTap,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Container</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> width: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> height: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> decoration: </span><span style="color:#0468D7">BoxDecoration</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> color: active ? </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.lightGreen[</span><span style="color:#0C7064">700</span><span style="color:#222222">] : </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.grey[</span><span style="color:#0C7064">600</span><span style="color:#222222">],</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> active ? </span><span style="color:#0C7064">'Active'</span><span style="color:#222222"> : </span><span style="color:#0C7064">'Inactive'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> style: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> TextStyle</span><span style="color:#222222">(fontSize: </span><span style="color:#0C7064">32</span><span style="color:#222222">, color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.white),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><hr><p><a id="mix-and-match"></a></p><div class="header-wrapper"><h3 id="a-mix-and-match-approach">A mix-and-match approach</h3><a class="heading-link" href="#a-mix-and-match-approach" aria-label="Link to 'A mix-and-match approach' section">#</a></div><p>For some widgets, a mix-and-match approach makes the most sense. In this scenario, the stateful widget manages some of the state, and the parent widget manages other aspects of the state.</p><p>In the <code>TapboxC</code> example, on tap down, a dark green border appears around the box. On tap up, the border disappears and the box's color changes. <code>TapboxC</code> exports its <code>_active</code> state to its parent but manages its <code>_highlight</code> state internally. This example has two <code>State</code> objects, <code>_ParentWidgetState</code> and <code>_TapboxCState</code>.</p><p>The <code>_ParentWidgetState</code> object:</p><ul><li>Manages the <code>_active</code> state.</li><li>Implements <code>_handleTapboxChanged()</code>, the method called when the box is tapped.</li><li>Calls <code>setState()</code> to update the UI when a tap occurs and the <code>_active</code> state changes.</li></ul><p>The <code>_TapboxCState</code> object:</p><ul><li>Manages the <code>_highlight</code> state.</li><li>The <code>GestureDetector</code> listens to all tap events. As the user taps down, it adds the highlight (implemented as a dark green border). As the user releases the tap, it removes the highlight.</li><li>Calls <code>setState()</code> to update the UI on tap down, tap up, or tap cancel, and the <code>_highlight</code> state changes.</li><li>On a tap event, passes that state change to the parent widget to take appropriate action using the <a href="https://api.flutter.dev/flutter/widgets/State/widget.html"><code>widget</code></a> property.</li></ul> <?code-excerpt "lib/mixed.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//---------------------------- ParentWidget ----------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> ParentWidget</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> ParentWidget</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">ParentWidget</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_ParentWidgetState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _ParentWidgetState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">ParentWidget</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> _active = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTapboxChanged</span><span style="color:#222222">(</span><span style="color:#0468D7">bool</span><span style="color:#222222"> newValue) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _active = newValue;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> SizedBox</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">TapboxC</span><span style="color:#222222">(active: _active, onChanged: _handleTapboxChanged),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">//----------------------------- TapboxC ------------------------------</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> TapboxC</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> TapboxC</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key, </span><span style="color:#BD2314">this</span><span style="color:#222222">.active = </span><span style="color:#0C7064">false</span><span style="color:#222222">, </span><span style="color:#BD2314">required</span><span style="color:#BD2314"> this</span><span style="color:#222222">.onChanged});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> bool</span><span style="color:#222222"> active;</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ValueChanged</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">> onChanged;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">TapboxC</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_TapboxCState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _TapboxCState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">TapboxC</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> _highlight = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTapDown</span><span style="color:#222222">(</span><span style="color:#0468D7">TapDownDetails</span><span style="color:#222222"> details) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _highlight = </span><span style="color:#0C7064">true</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTapUp</span><span style="color:#222222">(</span><span style="color:#0468D7">TapUpDetails</span><span style="color:#222222"> details) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _highlight = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTapCancel</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> _highlight = </span><span style="color:#0C7064">false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _handleTap</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#222222"> widget.</span><span style="color:#6200EE">onChanged</span><span style="color:#222222">(!widget.active);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#6E6E70"> // This example adds a green border on tap down.</span></span> <span class="line"><span style="color:#6E6E70"> // On tap up, the square changes to the opposite state.</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTapDown: _handleTapDown, </span><span style="color:#6E6E70">// Handle the tap events in the order that</span></span> <span class="line"><span style="color:#222222"> onTapUp: _handleTapUp, </span><span style="color:#6E6E70">// they occur: down, up, tap, cancel</span></span> <span class="line"><span style="color:#222222"> onTap: _handleTap,</span></span> <span class="line"><span style="color:#222222"> onTapCancel: _handleTapCancel,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Container</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> width: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> height: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> decoration: </span><span style="color:#0468D7">BoxDecoration</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> color: widget.active ? </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.lightGreen[</span><span style="color:#0C7064">700</span><span style="color:#222222">] : </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.grey[</span><span style="color:#0C7064">600</span><span style="color:#222222">],</span></span> <span class="line"><span style="color:#222222"> border:</span></span> <span class="line"><span style="color:#222222"> _highlight</span></span> <span class="line"><span style="color:#222222"> ? </span><span style="color:#0468D7">Border</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.teal[</span><span style="color:#0C7064">700</span><span style="color:#222222">]!, width: </span><span style="color:#0C7064">10</span><span style="color:#222222">)</span></span> <span class="line"><span style="color:#222222"> : </span><span style="color:#0C7064">null</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> widget.active ? </span><span style="color:#0C7064">'Active'</span><span style="color:#222222"> : </span><span style="color:#0C7064">'Inactive'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> style: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> TextStyle</span><span style="color:#222222">(fontSize: </span><span style="color:#0C7064">32</span><span style="color:#222222">, color: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.white),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>An alternate implementation might have exported the highlight state to the parent while keeping the active state internal, but if you asked someone to use that tap box, they'd probably complain that it doesn't make much sense. The developer cares whether the box is active. The developer probably doesn't care how the highlighting is managed, and prefers that the tap box handles those details.</p><hr><div class="header-wrapper"><h2 id="other-interactive-widgets">Other interactive widgets</h2><a class="heading-link" href="#other-interactive-widgets" aria-label="Link to 'Other interactive widgets' section">#</a></div><p>Flutter offers a variety of buttons and similar interactive widgets. Most of these widgets implement the <a href="https://m3.material.io/styles">Material Design guidelines</a>, which define a set of components with an opinionated UI.</p><p>If you prefer, you can use <a href="https://api.flutter.dev/flutter/widgets/GestureDetector-class.html"><code>GestureDetector</code></a> to build interactivity into any custom widget. You can find examples of <code>GestureDetector</code> in <a href="#managing-state">Managing state</a>. Learn more about the <code>GestureDetector</code> in <a href="/cookbook/gestures/handling-taps">Handle taps</a>, a recipe in the <a href="/cookbook">Flutter cookbook</a>.</p><aside class="alert alert-success"><div class="alert-header"><i class="material-symbols" aria-hidden="true">lightbulb</i> <span>Tip</span></div><div class="alert-content"><p>Flutter also provides a set of iOS-style widgets called <a href="https://api.flutter.dev/flutter/cupertino/cupertino-library.html"><code>Cupertino</code></a>.</p></div></aside><p>When you need interactivity, it's easiest to use one of the prefabricated widgets. Here's a partial list:</p><div class="header-wrapper"><h3 id="standard-widgets">Standard widgets</h3><a class="heading-link" href="#standard-widgets" aria-label="Link to 'Standard widgets' section">#</a></div><ul><li><a href="https://api.flutter.dev/flutter/widgets/Form-class.html"><code>Form</code></a></li><li><a href="https://api.flutter.dev/flutter/widgets/FormField-class.html"><code>FormField</code></a></li></ul><div class="header-wrapper"><h3 id="material-components">Material Components</h3><a class="heading-link" href="#material-components" aria-label="Link to 'Material Components' section">#</a></div><ul><li><a href="https://api.flutter.dev/flutter/material/Checkbox-class.html"><code>Checkbox</code></a></li><li><a href="https://api.flutter.dev/flutter/material/DropdownButton-class.html"><code>DropdownButton</code></a></li><li><a href="https://api.flutter.dev/flutter/material/TextButton-class.html"><code>TextButton</code></a></li><li><a href="https://api.flutter.dev/flutter/material/FloatingActionButton-class.html"><code>FloatingActionButton</code></a></li><li><a href="https://api.flutter.dev/flutter/material/IconButton-class.html"><code>IconButton</code></a></li><li><a href="https://api.flutter.dev/flutter/material/Radio-class.html"><code>Radio</code></a></li><li><a href="https://api.flutter.dev/flutter/material/ElevatedButton-class.html"><code>ElevatedButton</code></a></li><li><a href="https://api.flutter.dev/flutter/material/Slider-class.html"><code>Slider</code></a></li><li><a href="https://api.flutter.dev/flutter/material/Switch-class.html"><code>Switch</code></a></li><li><a href="https://api.flutter.dev/flutter/material/TextField-class.html"><code>TextField</code></a></li></ul><div class="header-wrapper"><h2 id="resources">Resources</h2><a class="heading-link" href="#resources" aria-label="Link to 'Resources' section">#</a></div><p>The following resources might help when adding interactivity to your app.</p><p><a href="/cookbook/gestures">Gestures</a>, a section in the <a href="/cookbook">Flutter cookbook</a>.</p><dl><dt><a href="/ui#handling-gestures">Handling gestures</a></dt><dd>How to create a button and make it respond to input.</dd><dt><a href="/ui/interactivity/gestures">Gestures in Flutter</a></dt><dd>A description of Flutter's gesture mechanism.</dd><dt><a href="https://api.flutter.dev">Flutter API documentation</a></dt><dd>Reference documentation for all of the Flutter libraries.</dd><dt>Wonderous app <a href="https://wonderous.app//web">running app</a>, <a href="https://github.com/gskinnerTeam/flutter-wonderous-app">repo</a></dt><dd>Flutter showcase app with a custom design and engaging interactions.</dd><dt><a href="https://www.youtube.com/watch?v=dkyY9WCGMi0">Flutter's Layered Design</a> (video)</dt><dd>This video includes information about state and stateless widgets. Presented by Google engineer, Ian Hickson.</dd></dl><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects the latest stable version of Flutter. Page last updated on 2025-02-12.</span> <a href="https://github.com/flutter/website/tree/main/src/content/ui/interactivity/index.md" target="_blank" rel="noopener">View source</a> <span>or </span><a href="https://github.com/flutter/website/issues/new?template=1_page_issue.yml&&page-url=https://docs.flutter.dev/ui/interactivity/&page-source=https://github.com/flutter/website/tree/main/src/content/ui/interactivity/index.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></article></main></div><footer id="site-footer"><div class="footer-section footer-main"><a class="brand" href="https://flutter.dev"><img src="/assets/images/branding/flutter/logo+text/horizontal/white.svg" alt="Flutter logo" width="164"></a><div class="footer-social-links"><a class="icon-button" href="https://medium.com/flutter" target="_blank" rel="noopener" title="Flutter's Medium blog"><svg><use href="/assets/images/social/medium.svg#medium"></use></svg> </a><a class="icon-button" href="https://youtube.com/@flutterdev" target="_blank" rel="noopener" title="Flutter's YouTube"><svg><use href="/assets/images/social/youtube.svg#youtube"></use></svg> </a><a class="icon-button" href="https://github.com/flutter" target="_blank" rel="noopener" title="Flutter's GitHub"><svg><use href="/assets/images/social/github.svg#github"></use></svg> </a><a class="icon-button" href="https://bsky.app/profile/flutter.dev" target="_blank" rel="noopener" title="Flutter's Bluesky"><svg><use href="/assets/images/social/bluesky.svg#bluesky"></use></svg> </a><a class="icon-button" href="https://twitter.com/FlutterDev" target="_blank" rel="noopener" title="Flutter's X (Twitter)"><svg><use href="/assets/images/social/x.svg#x"></use></svg></a></div></div><div class="footer-section footer-tray"><div class="footer-licenses">Except as otherwise noted, this site is licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>, and code samples are licensed under the <a href="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</a>.</div><div class="footer-utility-links"><ul><li><a href="/tos" title="Terms of use">Terms</a></li><li><a href="/brand" title="Brand usage guidelines">Brand</a></li><li><a href="https://policies.google.com/privacy" target="_blank" rel="noopener" title="Privacy policy">Privacy</a></li><li><a href="/security" title="Security philosophy and practices">Security</a></li></ul></div></div></footer></div><script src="/assets/js/tabs.js?v=4"></script><script src="/assets/js/archive.js?v=4"></script><script src="/assets/js/main.js?v=4"></script></body></html>