Building Flutter Apps in Python

Last Updated : 31 Jan, 2026

Flet is a Python library that allows developers to build real-time web, desktop, and mobile apps using Python, while Flutter handles the UI internally. In this article, we will learn how to create Flutter-like applications using the Flet library with only Python.

To start building apps with Flet, install the library using the following command in your terminal:

pip install flet

Below is an example that shows how a Flet application starts and runs.

Python
import flet as flt

def myapp(page: flt.Page):
    pass

flt.app(target=myapp)

Output

A blank app window opens with a default theme and a loading animation, because no UI elements are added yet.

BasicFletApp
Output

Explanation:

  • import flet as flt imports the Flet library.
  • myapp() is the main function where UI components will be added.
  • page represents the app window or screen.
  • flt.app(target=myapp) starts the Flet application using the given function.

Changing App Theme in Flet

Flet allows you to easily switch the app theme between Light and Dark mode. By default, Flet follows your device’s system theme. You can override this behavior by explicitly setting the theme in code.

Python
import flet as flt

def myapp(page: flt.Page):
    # Set theme mode (DARK or LIGHT)
    page.theme_mode = flt.ThemeMode.DARK  

    # Set window size
    page.window_height = 400
    page.window_width = 500

    # Set app title
    page.title = "GeeksApp using Flet"
    page.update()

flt.app(target=myapp)

Output

App opens with the selected theme applied

Explanation:

  • page.theme_mode controls the app theme.
  • ThemeMode.DARK forces dark mode (use ThemeMode.LIGHT for light mode).
  • page.window_height and page.window_width define the app window size.
  • page.update() applies all changes to the UI.

Adding Text to Your Flet App

Now let’s add some text elements to the app. In Flet, UI elements (called widgets) are added to the page using the page.add() method.

Python
import flet as flt

def myapp(page: flt.Page):
    page.theme_mode = flt.ThemeMode.LIGHT
    page.window_height = 400
    page.window_width = 500

    text = flt.TextField(
        label="Introductory Text",
        value="This App is made using Flet"
    )

    page.add(text)
    page.title = 'GeeksApp using Flet'
    page.update()

flt.app(target=myapp)

Output

A text field with a label and default text appears on the page.

Explanation:

  • TextField() creates an input box.
  • label appears at the top of the text field.
  • value is the default text shown inside the field.
  • page.add(text) displays the TextField on the app screen.

Important note

  1. When you use page.add(), Flet automatically updates the UI.
  2. If all changes are done using add(), calling page.update() is optional.
  3. For changes not added via add() (like page.title), it’s safer to call page.update().
  4. Using both add() and update() together is allowed and causes no errors.

Changing TextField Border Style

By default, a TextField in Flet uses an outline border. You can easily customize its appearance by changing the border property to remove the border or display only an underline.

Removing the border

Python
text = flt.TextField(
        label="Introductory Text",
        value="This App is made using Flet",
        border = flt.InputBorder.NONE
        )

Output

Removing the Border from the TextField

Using an underline border

Python
text = flt.TextField(
        label="Introductory Text",
        value="This App is made using Flet",
        border = flt.InputBorder.UNDERLINE
        )

Output

GeeksApp using Flet

Explanation:

  • InputBorder.OUTLINE (default) shows a full border.
  • InputBorder.NONE removes the border completely.
  • InputBorder.UNDERLINE shows only a bottom line under the text field.

Adding Simple Text (Without Input)

If you only want to display text (not accept input), use the Text() widget

Python
import flet as flt

def myapp(page: flt.Page):
    page.theme_mode = flt.ThemeMode.LIGHT
    page.window_height = 400
    page.window_width = 500

    page.add(
        flt.Text(
            "Hello Geeks",
            size=40,
            color=flt.Colors.GREEN,
            bgcolor=flt.Colors.YELLOW_300,
            weight=flt.FontWeight.BOLD,
        )
    )

    page.title = "GeeksApp using Flet"
    page.update()

flt.app(target=myapp)

Output

Hello Geeks

Explanation:

  • size sets the font size.
  • color sets the text color.
  • bgcolor sets the background color of the text.
  • Higher numbers in color shades (e.g., YELLOW_300) make the color appear deeper.
  • weight=FontWeight.BOLD makes the text bold.

Calculator using Flet

In this section, we will build a simple yet functional calculator application using the Flet library. This example demonstrates how common UI components like buttons, text, rows, and columns can be combined to create an interactive Flutter-like app using only Python.

Python
import flet
from flet import (
    Column,
    Container,
    ElevatedButton,
    Page,
    Row,
    Text,
    Colors,
    FilledButton,
)

class CalculatorApp(Container):
    def __init__(self):
        super().__init__()
        self.reset()
        self.result = Text(value="0", color=Colors.WHITE, size=22)
        self.content = self.build()

    def build(self):
        return Container(
            width=325,
            bgcolor=Colors.BLUE_900,
            border_radius=15,
            padding=20,
            content=Column(
                controls=[
                    Row(controls=[self.result], alignment="end"),

                    Row(controls=[
                        ElevatedButton("AC", bgcolor=Colors.YELLOW_400, color=Colors.BLACK, data="AC", on_click=self.on_button_clicked),
                        ElevatedButton("+/-", bgcolor=Colors.YELLOW_400, color=Colors.BLACK, data="+/-", on_click=self.on_button_clicked),
                        ElevatedButton("%", bgcolor=Colors.GREEN_900, color=Colors.WHITE, data="%", on_click=self.on_button_clicked),
                        ElevatedButton("/", bgcolor=Colors.GREEN_900, color=Colors.WHITE, data="/", on_click=self.on_button_clicked),
                    ]),

                    Row(controls=[
                        FilledButton("7", data="7", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("8", data="8", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("9", data="9", color=Colors.WHITE, on_click=self.on_button_clicked),
                        ElevatedButton("*", bgcolor=Colors.GREEN_900, color=Colors.WHITE, data="*", on_click=self.on_button_clicked),
                    ]),

                    Row(controls=[
                        FilledButton("4", data="4", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("5", data="5", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("6", data="6", color=Colors.WHITE, on_click=self.on_button_clicked),
                        ElevatedButton("-", bgcolor=Colors.GREEN_900, color=Colors.WHITE, data="-", on_click=self.on_button_clicked),
                    ]),

                    Row(controls=[
                        FilledButton("1", data="1", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("2", data="2", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("3", data="3", color=Colors.WHITE, on_click=self.on_button_clicked),
                        ElevatedButton("+", bgcolor=Colors.GREEN_900, color=Colors.WHITE, data="+", on_click=self.on_button_clicked),
                    ]),

                    Row(controls=[
                        FilledButton("0", data="0", color=Colors.WHITE, on_click=self.on_button_clicked),
                        FilledButton("00", data="00", color=Colors.WHITE, on_click=self.on_button_clicked),
                        ElevatedButton(".", bgcolor=Colors.AMBER_600, color=Colors.WHITE, data=".", on_click=self.on_button_clicked),
                        ElevatedButton("=", bgcolor=Colors.ORANGE, color=Colors.WHITE, data="=", on_click=self.on_button_clicked),
                    ]),
                ],
            ),
        )

    def on_button_clicked(self, e):
        data = e.control.data

        if self.result.value == "Error" or data == "AC":
            self.result.value = "0"
            self.reset()

        elif data in ("0","1","2","3","4","5","6","7","8","9",".","00"):
            if self.result.value == "0" or self.new_operand:
                self.result.value = data
                self.new_operand = False
            else:
                self.result.value += data

        elif data in ("+","-","*","/"):
            self.result.value = self.calculate(self.operand1, float(self.result.value), self.operator)
            self.operator = data
            self.operand1 = 0 if self.result.value == "Error" else float(self.result.value)
            self.new_operand = True

        elif data == "=":
            self.result.value = self.calculate(self.operand1, float(self.result.value), self.operator)
            self.reset()

        elif data == "%":
            self.result.value = str(float(self.result.value) / 100)
            self.reset()

        elif data == "+/-":
            val = float(self.result.value)
            self.result.value = str(-val if val > 0 else abs(val))

        self.update()

    def calculate(self, a, b, op):
        if op == "+": return self.format(a + b)
        if op == "-": return self.format(a - b)
        if op == "*": return self.format(a * b)
        if op == "/": return "Error" if b == 0 else self.format(a / b)

    def format(self, num):
        return str(int(num)) if num % 1 == 0 else str(num)

    def reset(self):
        self.operator = "+"
        self.operand1 = 0
        self.new_operand = True


def myCal(page: Page):
    page.title = "Basic Calculator using Flet"
    page.window_height = 375
    page.window_width = 350
    page.add(CalculatorApp())


flet.app(target=myCal)

Output

Calculator using Flet

Explanation:

  • Container creates the main calculator layout with background color, padding, and rounded corners.
  • Column and Row organize the display and buttons like a real calculator.
  • Text shows the current number or result on the screen.
  • FilledButton is used for number buttons (0–9, 00) with light blue styling.
  • ElevatedButton is used for operators and actions (+, -, *, /, =, AC).
  • data identifies which button is pressed.
  • on_button_clicked() handles input, operations, and resets.
  • calculate() performs arithmetic operations.
  • reset() clears values for the next calculation.
Comment