Skip to main content

DISPONIBLE EN INGLES Y ESPAÑOL

(VERSION INGLES)

Flet Popup Menu

A customizable and ready-to-use popup menu component for Flet applications.
It provides edit/delete dialogs, dynamic form generation for editing items, API communication,
and a flexible callback system for UI updates across modules.


🚀 Installation

pip install flet_popupmenu

Import

from flet_popupmenu import PopupMenuButton

Use

  • Initialize function called "PopupMenuButton" whose arguments are:
def PopupMenuButton(
    page: ft.Page,
    id: int,
    item_to_edit: dict = None,
    alias: str = "item",
    request_url: dict = None,
    callback=None,
    callbacks: dict = {}
):

🔍 ARGUMENTS EXPLAINED

Below is exactly what each argument does, and which ones are optional.

🔵 Required Arguments

✔ page: ft.Page

Current Flet page — required for dialogs, updates, and UI rendering.

✔ id: int

Unique identifier of the item being edited or deleted.

🟡 Optional Arguments (EXPLAINED IN DETAIL)

🟡 item_to_edit: dict = None (optional)

If provided → the popup shows a form for editing the item.

If omitted → the “edit” option is disabled automatically.

Structure example:

item_to_edit = {
    "title":  { "value": "Task A", "type": "text" },
    "state":  {
        "value": 1,
        "type": "dropdown",
        "options": { 0: "Pending", 1: "Completed" }
    }
}

If your item has no editable fields → simply pass None

🟡 alias: str = "item" (optional)

Name used in dialog messages. Examples:

  • "Task"

  • "User"

  • "Product"

If not set → defaults to "item".

🟡 request_url: dict = None (optional but RECOMMENDED)

Defines URLs for:

  • deleting the item

  • editing the item

Structure:

request_url = {
    "delete": {
        "url": "https://api.com/items?id=3",
        "headers": headers
    },
    "edit": {
        "url": "https://api.com/items?id=3",
        "headers": headers
    }
}

If omitted:

  • delete button will do nothing

  • edit button will do nothing

  • no errors will be thrown

🟡 callback=None (optional)

Function executed after a successful delete/edit.

Use it for UI refresh:

callback = refresh_tasks

⚠️ IMPORTANT: The callback must NOT require arguments. It must be a simple callable:

def refresh_tasks():
    ...

🟡 callbacks: dict = {}   (optional, advanced)

Allows triggering multiple auxiliary functions across your app.

This is useful if deleting/editing a task also needs to:

  • reload categories

  • refresh dashboards

  • reload summary counters

callbacks={
    "load_categories": {
        "function": refresh_categories,
        "args": []
    },
    "update_dashboard": {
        "function": refresh_dashboard,
        "args": []
    }
}

If omitted → only the main callback (if any) will run.

🟡 Layout: dict = {}   (optional, advanced)

Allows setting layout of popup container. Values are: top, left, right, bottom, alignment, border_radius, bg_color

layout = {
    "top": int | 8,
    "left": int | 0,
    "right": int | 8,
    "bottom": int | 0,
    "alignment": "[top_right | top_center | top_left | right | center | left | bottom_right | bottom_center | bottom_left]" | ft.Alignment.top_right,
    "border_radius": int # In case exists, will set width amd heght as 40x40 to cover image according background
}

🌟 FULL EXAMPLE (RECOMMENDED)

🟦 STRUCTURE

2 files:

app.py         → main module
tasks.py       → module where PopupMenuButton is used

🟩 1️⃣ app.py — MAIN FILE (DEFINE CALLBACKS)

# app.py
import flet as ft
from tasks import render_tasks_list

# ------- CALLBACKS DEFINED HERE IN -------
def refresh_tasks():
    """
    Refreshes the task list. Gets executed after deleting/editing.
    IMPORTANT: Must not require args.
    """
    print("✔ refresh_tasks() executed (UI update here).")

def refresh_categories():
    """
    Example of a secondary function fired from callbacks argument.
    It can reload categories, counters, dashboards, etc.
    """
    print("✔ refresh_categories() executed (extra UI update).")


def main(page: ft.Page):
    page.title = "Callback Example"
    page.vertical_alignment = ft.MainAxisAlignment.START

    # ------- PASS CALLBACKS TO MODULE -------
    content = render_tasks_list(
        page=page,
        callback_main=refresh_tasks,
        callbacks_extra={
            "reload_categories": {
                "function": refresh_categories,
                "args": []
            }
        }
    )

    page.add(content)


ft.app(target=main)

🟩 2️⃣ tasks.py — Where is used PopupMenuButton (RECIVES CALLBACKS)

# tasks.py
import flet as ft
from flet_popupmenu import PopupMenuButton


def render_tasks_list(page: ft.Page, callback_main=None, callbacks_extra=None):
    """
    callback_main: main refresh function (optional)
    callbacks_extra: dict with extra functions to run (optional)
    """

    # Simulated API task
    task = {
        "id": 3,
        "title": "Example Task",
        "description": "This is a sample description",
        "state": 1,
    }

    # Editable fields
    item_to_edit = {
        "id": { "value": task["id"], "type": "identifier", "disabled": True },
        "title": { "value": task["title"], "type": "text" },
        "description": { "value": task["description"], "type": "text" },
        "state": {
            "value": task["state"],
            "type": "dropdown",
            "options": {
                0: "Pending",
                1: "Completed",
                2: "In progress"
            }
        }
    }

    # Example headers
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer <token>"
    }

    popup = PopupMenuButton(
        page=page,
        id=task["id"],
        item_to_edit=item_to_edit,
        alias="Task",
        request_url={
            "delete": {
                "url": f"https://example.com/tasks?id={task['id']}",
                "headers": headers
            },
            "edit": {
                "url": f"https://example.com/tasks?id={task['id']}",
                "headers": headers
            }
        },

        # 🔥 MAIN CALLBACK (typically refresh list)
        callback=callback_main,

        # 🔥 EXTRA CALLBACKS (optional)
        callbacks=callbacks_extra
    )

    return ft.Column(
        controls=[
            ft.Text("Task List Example", size=20, weight="bold"),
            ft.ListTile(
                leading=ft.Icon(ft.icons.TASK),
                title=ft.Text(task["title"]),
                subtitle=ft.Text(task["description"]),
                trailing=popup
            )
        ]
    )

🟧 What exacly happens when the user deletes or edits:

    1. Popup sends a delete or an edit request to your API
    2. If API responses OK → PopupMenuButton runs:

callback_main()
callbacks_extra["reload_categories"]["function"](*args)

It called by example:

✔ refresh_tasks() → to reload the list ✔ refresh_categories() → to update other system parts

    3. Defenitely, the UI turns into completelly optimized.

⭐ His finallity:

  • How to separate logic across multiple files

  • How to pass a function from the main file

  • How to receive and use it within the component

  • How to use advanced callbacks

  • How to write functions without arguments

  • How to refresh the UI after actions

⚠️ COMMON MISTAKES TO AVOID

  • Do not pass callbacks that expect parameters. All functions must be def func(): ...

  • Ensure your API ends with a valid JSON response.

  • If item_to_edit is None, editing will be disabled.

  • If request_url is None, delete/edit buttons will do nothing.

  • The options key is only for dropdowns.

🧾 License

MIT License.

❤️ Contributions Welcome

Open a pull request or issue on GitHub. Suggestions and improvements are welcome!


🚀 ¿Do you even want badges for PyPI too?

Can add:

  • ✔ PyPI version
  • ✔ Python versions
  • ✔ Wheel status
  • ✔ Download counts
  • ✔ License badge
  • ✔ Supported OS

Only say:

👉 “Put badges too

(VERSIÓN EN ESPAÑOL)

Menú Emergente Flet

Un componente de menú emergente personalizable y listo para usar para aplicaciones Flet.
Proporciona diálogos de edición/eliminación, generación dinámica de formularios para editar elementos, comunicación con API
y un sistema flexible de callbacks para actualizar la interfaz de usuario en todos los módulos.


🚀 Instalación

pip install flet_popupmenu

Importación

from flet_popupmenu import PopupMenuButton

Uso

  • Inicializa la función "PopupMenuButton" cuyos argumentos son:
def PopupMenuButton(
    page: ft.Page,
    id: int,
    item_to_edit: dict = None,
    alias: str = "item",
    request_url: dict = None,
    callback=None,
    callbacks: dict = {}
):

🔍 EXPLICACIÓN DE ARGUMENTOS

A continuación se detalla para qué sirve cada argumento y cuáles son opcionales.

🔵 Argumentos obligatorios

✔ page: ft.Page

Página actual de Flet — necesaria para diálogos, actualizaciones y renderizado de la UI.

✔ id: int

Identificador único del elemento a editar o eliminar.

🟡 Argumentos opcionales (EXPLICADOS EN DETALLE)

🟡 item_to_edit: dict = None (opcional)

Si se proporciona → el menú muestra un formulario para editar el elemento.

Si se omite → la opción “editar” se desactiva automáticamente.

Ejemplo de estructura:

item_to_edit = {
    "title":  { "value": "Tarea A", "type": "text" },
    "state":  {
        "value": 1,
        "type": "dropdown",
        "options": { 0: "Pendiente", 1: "Completada" }
    }
}

Si tu elemento no tiene campos editables → simplemente pasa None.

🟡 alias: str = "item" (opcional)

Nombre usado en los mensajes de diálogo. Ejemplos:

  • "Tarea"
  • "Usuario"
  • "Producto"

Si no se define → por defecto es "item".

🟡 request_url: dict = None (opcional pero RECOMENDADO)

Define URLs para:

  • eliminar el elemento
  • editar el elemento

Estructura:

request_url = {
    "delete": {
        "url": "https://api.com/items?id=3",
        "headers": headers
    },
    "edit": {
        "url": "https://api.com/items?id=3",
        "headers": headers
    }
}

Si se omite:

  • el botón eliminar no hará nada
  • el botón editar no hará nada
  • no se lanzarán errores

🟡 callback=None (opcional)

Función ejecutada tras eliminar/editar exitosamente.

Úsala para refrescar la UI:

callback = refresh_tasks

⚠️ IMPORTANTE: El callback NO debe requerir argumentos. Debe ser una función simple:

def refresh_tasks():
    ...

🟡 callbacks: dict = {}   (opcional, avanzado)

Permite disparar múltiples funciones auxiliares en tu app.

Útil si al eliminar/editar una tarea también necesitas:

  • recargar categorías
  • refrescar dashboards
  • recargar contadores resumen
callbacks={
    "load_categories": {
        "function": refresh_categories,
        "args": []
    },
    "update_dashboard": {
        "function": refresh_dashboard,
        "args": []
    }
}

Si se omite → solo se ejecuta el callback principal (si existe).

🌟 EJEMPLO COMPLETO (RECOMENDADO)

🟦 ESTRUCTURA

2 archivos:

app.py         → módulo principal
tasks.py       → módulo donde se usa PopupMenuButton

🟩 1️⃣ app.py — ARCHIVO PRINCIPAL (DEFINE CALLBACKS)

# app.py
import flet as ft
from tasks import render_tasks_list

# ------- CALLBACKS DEFINIDOS AQUÍ -------
def refresh_tasks():
    """
    Refresca la lista de tareas. Se ejecuta tras eliminar/editar.
    IMPORTANTE: No debe requerir argumentos.
    """
    print("✔ refresh_tasks() ejecutado (actualización de UI).")

def refresh_categories():
    """
    Ejemplo de función secundaria disparada desde callbacks.
    Puede recargar categorías, contadores, dashboards, etc.
    """
    print("✔ refresh_categories() ejecutado (actualización extra de UI).")


def main(page: ft.Page):
    page.title = "Ejemplo de Callback"
    page.vertical_alignment = ft.MainAxisAlignment.START

    # ------- PASA CALLBACKS AL MÓDULO -------
    content = render_tasks_list(
        page=page,
        callback_main=refresh_tasks,
        callbacks_extra={
            "reload_categories": {
                "function": refresh_categories,
                "args": []
            }
        }
    )

    page.add(content)


ft.app(target=main)

🟩 2️⃣ tasks.py — Donde se usa PopupMenuButton (RECIBE CALLBACKS)

# tasks.py
import flet as ft
from flet_popupmenu import PopupMenuButton


def render_tasks_list(page: ft.Page, callback_main=None, callbacks_extra=None):
    """
    callback_main: función principal de refresco (opcional)
    callbacks_extra: dict con funciones extra a ejecutar (opcional)
    """

    # Tarea simulada de API
    task = {
        "id": 3,
        "title": "Tarea Ejemplo",
        "description": "Esta es una descripción de muestra",
        "state": 1,
    }

    # Campos editables
    item_to_edit = {
        "id": { "value": task["id"], "type": "identifier", "disabled": True },
        "title": { "value": task["title"], "type": "text" },
        "description": { "value": task["description"], "type": "text" },
        "state": {
            "value": task["state"],
            "type": "dropdown",
            "options": {
                0: "Pendiente",
                1: "Completada",
                2: "En progreso"
            }
        }
    }

    # Ejemplo de headers
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer <token>"
    }

    popup = PopupMenuButton(
        page=page,
        id=task["id"],
        item_to_edit=item_to_edit,
        alias="Tarea",
        request_url={
            "delete": {
                "url": f"https://example.com/tasks?id={task['id']}",
                "headers": headers
            },
            "edit": {
                "url": f"https://example.com/tasks?id={task['id']}",
                "headers": headers
            }
        },

        # 🔥 CALLBACK PRINCIPAL (normalmente refresca la lista)
        callback=callback_main,

        # 🔥 CALLBACKS EXTRA (opcional)
        callbacks=callbacks_extra
    )

    return ft.Column(
        controls=[
            ft.Text("Ejemplo de Lista de Tareas", size=20, weight="bold"),
            ft.ListTile(
                leading=ft.Icon(ft.icons.TASK),
                title=ft.Text(task["title"]),
                subtitle=ft.Text(task["description"]),
                trailing=popup
            )
        ]
    )

🟧 ¿Qué ocurre exactamente al eliminar o editar?

    1. El popup envía una petición de eliminación o edición a tu API
    2. Si la API responde OK → PopupMenuButton ejecuta:

callback_main()
callbacks_extra["reload_categories"]["function"](*args)

Ejemplo de llamada:

✔ refresh_tasks() → para recargar la lista
✔ refresh_categories() → para actualizar otras partes del sistema

    3. Finalmente, la UI queda completamente optimizada.

⭐ Su finalidad:

  • Cómo separar la lógica en varios archivos
  • Cómo pasar una función desde el archivo principal
  • Cómo recibirla y usarla en el componente
  • Cómo usar callbacks avanzados
  • Cómo escribir funciones sin argumentos
  • Cómo refrescar la UI tras acciones

⚠️ ERRORES COMUNES A EVITAR

  • No pases callbacks que requieran parámetros. Todas las funciones deben ser def func(): ...
  • Asegúrate de que tu API devuelva una respuesta JSON válida.
  • Si item_to_edit es None, la edición estará deshabilitada.
  • Si request_url es None, los botones de eliminar/editar no harán nada.
  • La clave options solo es para dropdowns.

🧾 Licencia

Licencia MIT.

❤️ ¡Contribuciones bienvenidas!

Abre un pull request o issue en GitHub. ¡Se aceptan sugerencias y mejoras!


🚀 ¿Quieres también badges para PyPI?

Se pueden añadir:

  • ✔ Versión PyPI
  • ✔ Versiones de Python
  • ✔ Estado Wheel
  • ✔ Contador de descargas
  • ✔ Badge de licencia
  • ✔ SO soportados

Solo di:

👉 “Pon badges también”

Release files for flet-popupmenu 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flet-popupmenu 0.0.3
File Size Uploaded
flet_popupmenu-0.0.3.tar.gz 16.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flet-popupmenu 0.0.3
File Interpreter ABI Platform
flet_popupmenu-0.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 28.8 kB

Release files / flet_popupmenu-0.0.3.tar.gz

Download URL flet_popupmenu-0.0.3.tar.gz
Size 16.8 kB
Tags Source
SHA-256 checksum
How to use checksums
51f1ed508b3b240acb3ad4516da0f091d46d4862024925a9457f07ae848b6232
BLAKE2b-256 checksum
How to use checksums
bb458e892a4fa84c7345301cfacd99c44a36ed1edaf10f38a2e1557d0cb1cf6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release files / flet_popupmenu-0.0.3-py3-none-any.whl

Download URL flet_popupmenu-0.0.3-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6e45b5620841b12cc4108fcf3d3ffb03d9d017cf60fb928f8a6b6458f7fb705f
BLAKE2b-256 checksum
How to use checksums
edf65a53975e260c8819df8deae582e913e3836a867038c0c2e41784ebc3d51a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release history Release notifications | RSS feed

This release

0.0.3 This release

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page