### Complete Minimal Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/11-quick-reference.md
This example demonstrates a basic aiogram bot with a two-window dialog. It covers bot initialization, state management, dialog setup, and handling the start command.
```python
import asyncio
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.fsm.state import StatesGroup, State
from aiogram.filters import CommandStart
from aiogram.types import Message
from aiogram_dialog import Dialog, Window, DialogManager, setup_dialogs, StartMode
from aiogram_dialog.widgets.text import Const
from aiogram_dialog.widgets.kbd import Button, Next, Back
TOKEN = "YOUR_TOKEN"
class MainDialog(StatesGroup):
main = State()
next_step = State()
dialog = Dialog(
Window(
Const("Welcome!"),
Next(Const("Next")),
state=MainDialog.main,
),
Window(
Const("Second step"),
Back(Const("Back")),
state=MainDialog.next_step,
),
)
async def main():
bot = Bot(token=TOKEN)
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
dp.include_router(dialog)
bg_factory = setup_dialogs(dp)
@dp.message(CommandStart())
async def on_start(message: Message, manager: DialogManager):
await manager.start(MainDialog.main, mode=StartMode.RESET_STACK)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------
### Complete aiogram-dialog Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
A full example demonstrating the setup of a bot with aiogram-dialog, including defining states, creating a dialog with a window and button, initializing the bot and dispatcher with memory storage, and starting polling.
```python
import asyncio
from aiogram import Bot, Dispatcher, Router
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog import Dialog, Window, setup_dialogs
from aiogram_dialog.widgets.text import Const
from aiogram_dialog.widgets.kbd import Button
TOKEN = "YOUR_TOKEN"
# Define states
class Main(StatesGroup):
menu = State()
# Create dialog
dialog = Dialog(
Window(
Const("Welcome!"),
Button(Const("Click me"), id="btn"),
state=Main.menu,
),
)
async def main():
# Initialize bot and dispatcher
bot = Bot(token=TOKEN)
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
# Register dialog
dp.include_router(dialog)
# Setup dialogs
bg_manager_factory = setup_dialogs(dp)
# Start polling
try:
await dp.start_polling(bot)
finally:
await bot.session.close()
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------
### Basic Button with Start Action
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/keyboard/start/index.md
Demonstrates how to create a generic Button widget and define an `on_click` handler to manually start a dialog state. Use this when you need custom logic before starting the dialog.
```python
from aiogram_dialog.widgets.kbd import Button
async def on_click(
cq: CallbackQuery,
button: Button,
dialog_manager: DialogManager
):
... # your actions
await dialog_manager.start(SOME_STATE, SOME_DATA)
button = Button(..., on_click=on_click)
```
--------------------------------
### Basic Dialog Setup
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Demonstrates the basic setup of dialogs with aiogram and aiogram-dialog. Ensure setup_dialogs is called after registering all dialogs.
```python
from aiogram import Bot, Dispatcher
from aiogram_dialog import Dialog, Window, setup_dialogs
# Create dispatcher
dp = Dispatcher()
# Create and register dialogs
my_dialog = Dialog(
Window(...),
)
dp.include_router(my_dialog)
# Setup dialogs - must be called after registering all dialogs
bg_manager_factory = setup_dialogs(dp)
```
--------------------------------
### Starting and Nesting Dialogs
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/transitions/index.md
Demonstrates how to start a new dialog from within another, using the `Start` widget and a custom button click handler. Shows the structure of main and sub-dialog definitions.
```python
from aiogram.filters.state import StatesGroup, State
from aiogram.types import CallbackQuery
from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.kbd import Button, Start
from aiogram_dialog.widgets.text import Const
class DialogSG(StatesGroup):
first = State()
class SubDialogSG(StatesGroup):
first = State()
second = State()
async def start_subdialog(callback: CallbackQuery, button: Button,
manager: DialogManager):
await manager.start(SubDialogSG.second, data={"key": "value"})
dialog = Dialog(
Window(
Const("Main dialog"),
Start(Const("Start 1"), id="start", state=SubDialogSG.first),
Button(Const("Start 2"), id="sec", on_click=start_subdialog),
state=DialogSG.first,
),
)
subdialog = Dialog(
Window(
Const("Subdialog: first"),
state=SubDialogSG.first,
),
Window(
Const("Subdialog: second"),
state=SubDialogSG.second,
),
)
```
--------------------------------
### Select Widget Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Example demonstrating how to use the Select widget to allow users to choose a product. It includes a getter for products and an on_click handler.
```python
async def get_products(**kwargs):
return {
"products": [
{"id": 1, "name": "Apple"},
{"id": 2, "name": "Banana"},
]
}
async def on_product_select(event: CallbackQuery, widget, manager: DialogManager, item_id: int):
await manager.update(data={"selected_product": item_id})
Window(
Const("Select product:"),
Select(
Format("{item[name]}"),
id="products",
item_id_getter=lambda item: item["id"],
items=lambda data: data["products"],
on_click=on_product_select,
),
state=MyState.shop,
getter=get_products,
)
```
--------------------------------
### Install aiogram-dialog
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/quickstart/index.md
Install the library using pip. Ensure you have Python and pip installed.
```default
pip install aiogram_dialog
```
--------------------------------
### Dialog Setup with Bot Polling Integration
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Illustrates integrating dialog setup with bot polling, including setting up storage and the dispatcher.
```python
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram_dialog import setup_dialogs
TOKEN = "123:ABC"
async def main():
bot = Bot(token=TOKEN)
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
# Include dialogs
dp.include_router(my_dialog)
# Setup dialogs
bg_manager_factory = setup_dialogs(dp)
# Start polling
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------
### Start Dialog Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Initiates a dialog, optionally resetting the stack and passing initial data. This is typically used in response to a message command.
```python
@router.message()
async def start_dialog(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(
MyDialog.first_state,
data={"triggered_by": "command"},
mode=StartMode.RESET_STACK,
)
```
--------------------------------
### Dispatcher and Router Setup
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Demonstrates setting up aiogram-dialog with both a Dispatcher and a Router. The setup process is similar for both, involving including the dialog's router and calling setup_dialogs.
```python
# With Dispatcher
dp = Dispatcher()
dp.include_router(dialog)
setup_dialogs(dp)
# With Router
router = Router()
router.include_router(dialog)
setup_dialogs(router)
```
--------------------------------
### Install aiogram_dialog with tools extras
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/helper_tools/index.md
Install the library with the necessary extras for using the helper tools.
```bash
pip install aiogram_dialog[tools]
```
--------------------------------
### Start
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Initiates a new dialog. It requires a text, ID, and the initial state of the dialog to start, along with optional data and startup mode.
```APIDOC
## Start
### Description
Starts a new dialog.
### Parameters
- **text** (TextWidget) - Required - Button label.
- **id** (str) - Required - Button ID.
- **state** (State) - Required - Initial state of dialog to start.
- **data** (Data) - Optional - Data to pass to started dialog.
- **on_click** (OnClick | None) - Optional - Optional callback before start.
- **show_mode** (ShowMode | None) - Optional - How to show dialog.
- **mode** (StartMode) - Optional - How to handle stack (NORMAL, RESET_STACK, NEW_STACK). Default is NORMAL.
- **when** (WhenCondition) - Optional - Show/hide condition.
- **style** (StyleWidget) - Optional - Button style.
```
--------------------------------
### Integration Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Example demonstrating how to integrate DialogManager into an aiogram application.
```APIDOC
### Integration Example
```python
from aiogram import Router, F
from aiogram.types import Message
from aiogram_dialog import DialogManager, StartMode
router = Router()
@router.message()
async def start_dialog(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(
MyDialog.first_state,
data={"triggered_by": "command"},
mode=StartMode.RESET_STACK,
)
@router.callback_query()
async def handle_button(query: CallbackQuery, dialog_manager: DialogManager):
if dialog_manager.has_context():
ctx = dialog_manager.current_context()
await dialog_manager.switch_to(MyDialog.next_state)
```
```
--------------------------------
### ManagedWidget Interface Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/12-style-and-common-widgets.md
Demonstrates how to find a managed widget using its ID and interact with its state, such as getting or setting a checked status.
```python
# Find widget and get managed wrapper
managed = dialog_manager.find("checkbox_id")
# Get current state
is_checked = await managed.get_checked()
# Set state
await managed.set_checked(manager.dialog_data, True)
```
--------------------------------
### Dialog Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/01-dialog-api.md
Demonstrates the creation of a dialog with multiple windows, custom callbacks, and data getters.
```python
from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog import Dialog, Window
from aiogram_dialog.widgets.text import Const, Format
from aiogram_dialog.widgets.kbd import Button, Next
class UserFlow(StatesGroup):
greeting = State()
confirmation = State()
async def on_dialog_start(data, manager):
print("User started flow")
async def get_user_name(**kwargs):
return {"name": "John"}
dialog = Dialog(
Window(
Format("Hello, {name}!"),
Button(Const("Continue"), id="btn_next"),
state=UserFlow.greeting,
getter=get_user_name,
),
Window(
Const("Are you sure?"),
Next(Const("Yes")),
state=UserFlow.confirmation,
),
on_start=on_dialog_start,
launch_mode=LaunchMode.SINGLE_TOP,
)
```
--------------------------------
### ListGroup with URL Buttons
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/keyboard/list_group/index.md
This example demonstrates how to use ListGroup to display a list of products, where each product is represented by a URL button. It shows how to define the items, get item IDs, and format the button text and URL using item data. The `getter` function provides the `products` data to the window.
```Python
from aiogram import F
from aiogram.filters.state import State, StatesGroup
from aiogram_dialog import (
Window,
Dialog,
)
from aiogram_dialog.widgets.kbd import (
Url,
ListGroup,
SwitchTo,
Back,
)
from aiogram_dialog.widgets.text import Const, Format
class SG(StatesGroup):
main = State()
result = State()
success = F["products"]
fail = ~success
async def actions(**kwargs):
products = [
{"id": 1, "name": "Ferrari", "category": "car",
"url": "https://www.ferrari.com/"},
{"id": 2, "name": "Detroit", "category": "game",
"url": "https://wikipedia.org/wiki/Detroit:_Become_Human"},
]
return {
"products": products,
}
dialog = Dialog(
Window(
Const("Click find products to show a list of available products:"),
SwitchTo(Const("Find products"), id="search", state=SG.result),
state=SG.main,
),
Window(
Const("Searching results:", when=success),
Const("Search did not return any results", when=fail),
ListGroup(
Url(
Format("{item[name]} ({item[category]})"),
Format("{item[url]}"),
id="url",
),
id="select_search",
item_id_getter=lambda item: item["id"],
items="products",
),
Back(Const("Back")),
state=SG.result,
getter=actions,
)
)
```
--------------------------------
### Configuring Dialog Start Mode
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/transitions/index.md
Demonstrates setting the `mode` for starting a dialog using `dialog_manager.start`, with `StartMode.RESET_STACK` to clear the existing stack before launching.
```python
async def start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(..., mode=StartMode.RESET_STACK)
```
--------------------------------
### Get Start Data Property
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Retrieve the data that was passed when the dialog was initially started.
```python
@property
def start_data(self) -> Data
```
--------------------------------
### Custom DialogManagerFactory Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
An example of creating a custom DialogManagerFactory by inheriting from the protocol and implementing the create method.
```python
from aiogram_dialog.api.internal import DialogManagerFactory
class CustomManagerFactory(DialogManagerFactory):
async def create(
self,
router: Router,
middleware_data: dict,
registry: DialogRegistryProtocol,
) -> DialogManager:
# Create custom DialogManager
...
setup_dialogs(
dp,
dialog_manager_factory=CustomManagerFactory(),
)
```
--------------------------------
### Start Button Widget
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/keyboard/start/index.md
Shows the usage of the specialized Start widget, which directly configures the dialog state and data to be started upon click. This is a more concise way to initiate dialogs compared to a generic Button.
```python
from aiogram_dialog.widgets.kbd import Button, Start
async def on_click(
cq: CallbackQuery,
button: Button,
dialog_manager: DialogManager
):
... # your actions
button = Start(..., state=SOME_STATE, data=SOME_DATA, on_click=on_click)
```
--------------------------------
### Complete aiogram-dialog Bot Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/quickstart/index.md
A comprehensive example combining all the previous steps to create a functional Telegram bot with a simple dialog. This includes imports, state definition, window creation, dialog setup, command handling, and bot execution.
```python
from aiogram import Bot, Dispatcher
from aiogram.filters import Command
from aiogram.filters.state import State, StatesGroup
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import Message
from aiogram_dialog import (
Dialog,
DialogManager,
setup_dialogs,
StartMode,
Window,
)
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog.widgets.text import Const
class MySG(StatesGroup):
main = State()
main_window = Window(
Const("Hello, unknown person"),
Button(Const("Useless button"), id="nothing"),
state=MySG.main,
)
dialog = Dialog(main_window)
storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(storage=storage)
dp.include_router(dialog)
setup_dialogs(dp)
@dp.message(Command("start"))
async def start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)
if __name__ == '__main__':
dp.run_polling(bot, skip_updates=True)
```
--------------------------------
### BgManagerFactory Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Demonstrates how to use the BgManagerFactory, returned by setup_dialogs, to create background managers for operations outside the event loop.
```python
# In background task or webhook handler
async def notify_user(user_id: int, bg_manager_factory: BgManagerFactory, bot: Bot):
manager = bg_manager_factory.bg(
bot=bot,
user_id=user_id,
chat_id=user_id, # Same as user_id for private chats
)
await manager.update(data={"notification": "You have new message"})
```
--------------------------------
### Example Usage of Progress Widget
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/04-text-widgets-api.md
Demonstrates how to use the Progress widget within a Window, providing a getter function to supply progress data.
```python
async def get_progress(**kwargs):
return {
"current": 5,
"total": 10,
}
Window(
Progress(
text_getter=lambda data, _: f"Progress: {data['current']}/{data['total']}",
value_getter=lambda data: data["current"],
max_value_getter=lambda data: data["total"],
),
state=MyState.progress,
getter=get_progress,
)
```
--------------------------------
### Custom Dialog Setup Configuration
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Shows how to set up dialogs with custom components like event isolation and a global getter.
```python
from aiogram.fsm.storage.memory import MemoryStorage, SimpleEventIsolation
from aiogram_dialog import setup_dialogs
# Register dialogs...
# Setup with custom components
bg_manager_factory = setup_dialogs(
dp,
events_isolation=SimpleEventIsolation(),
getter=async def global_getter(**kwargs):
return {"app_version": "1.0.0"}
)
```
--------------------------------
### Start New Dialog Button
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Use the Start widget to initiate a new dialog. It requires text, ID, and the initial state of the dialog to start. You can also pass data and specify the start mode.
```python
class Start(EventProcessorButton):
def __init__(
self,
text: TextWidget,
id: str,
state: State,
data: Data = None,
on_click: OnClick | None = None,
show_mode: ShowMode | None = None,
mode: StartMode = StartMode.NORMAL,
when: WhenCondition = None,
style: StyleWidget = EMPTY_STYLE,
)
```
```python
Window(
Const("Open submenu"),
Start(
Const("Settings"),
id="settings",
state=SettingsDialog.main,
mode=StartMode.NORMAL,
),
state=MainDialog.menu,
)
```
--------------------------------
### Start Dialog with Command Handler
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/quickstart/index.md
Create a command handler to initiate the dialog. Use DialogManager to start the dialog and ensure `mode=StartMode.RESET_STACK` is set to prevent dialog stacking.
```python
from aiogram.filters import Command
from aiogram.types import Message
from aiogram_dialog import DialogManager, StartMode
@dp.message(Command("start"))
async def start(message: Message, dialog_manager: DialogManager):
# Important: always set `mode=StartMode.RESET_STACK` you don't want to stack dialogs
await dialog_manager.start(MySG.main, mode=StartMode.RESET_STACK)
```
--------------------------------
### Counter Widget Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/keyboard/counter/index.md
Demonstrates the creation and basic configuration of a Counter widget, including setting a default value, maximum value, and a click handler for the text display.
```python
from aiogram_dialog.widgets.kbd import ManagedCounter, Counter
async def on_text_click(
event: CallbackQuery,
widget: ManagedCounter,
dialog_manager: DialogManager,
) -> None:
await event.answer(f"Value: {widget.get_value()}")
counter = Counter(
id="someid",
default=0,
max_value=1000,
on_text_click=on_text_click,
)
```
--------------------------------
### Keyboard Widgets Examples
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/11-quick-reference.md
Examples of common keyboard widgets for user interaction in aiogram-dialog.
```python
Button(Const("Click"), id="btn")
```
```python
SwitchTo(Const("Next"), id="next", state=...)
```
```python
Next(Const("Next"))
```
```python
Back(Const("Back"))
```
```python
Start(Const("Menu"), id="menu", state=...)
```
```python
Cancel(Const("Cancel"))
```
```python
Select(..., items=...)
```
```python
Multiselect(..., items=...)
```
```python
Group(btn1, btn2, btn3)
```
```python
Column(btn1, btn2)
```
```python
Calendar(id="cal")
```
```python
Counter(id="count")
```
```python
Checkbox(checked_text, unchecked_text, id="check")
```
--------------------------------
### Custom Media Storage Setup
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Configure custom media storage for aiogram dialogs. Pass an instance of your custom storage class to setup_dialogs.
```python
setup_dialogs(
dp,
media_id_storage=CustomMediaStorage(),
)
```
--------------------------------
### StyleWidget Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Shows a basic example of applying a style to a Button widget. The style can be a predefined string, such as 'destructive', to control button appearance.
```python
from aiogram_dialog.widgets.style import StyleWidget
# Style can be a fixed string
button = Button(..., style="destructive")
```
--------------------------------
### Multiselect Widget Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Example demonstrating the Multiselect widget for choosing multiple items. It includes a handler to toggle the checked state of items.
```python
async def on_selection_changed(event, widget, manager: DialogManager, item_id: str):
widget.set_checked(manager.dialog_data, item_id, not widget.is_checked(manager.dialog_data, item_id))
Window(
Const("Select items:"),
Multiselect(
Format("☑ {item}" if checked else "☐ {item}"),
id="items",
item_id_getter=lambda x: x,
items=lambda data: data["available_items"],
on_state_changed=on_selection_changed,
),
state=MyState.select,
)
```
--------------------------------
### When Condition Usage Examples
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/12-style-and-common-widgets.md
Provides examples of different ways to define 'when' conditions: lambda functions, static booleans, and separate functions.
```python
# Lambda condition
when=lambda data, widget, manager: data["count"] > 0
# Static boolean
when=True
# Condition function
def should_show(data: dict, widget, manager: DialogManager) -> bool:
return data.get("show_details", False)
when=should_show
# No condition (always shown)
when=None
```
--------------------------------
### Example of Conditional Rendering in a Window
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/04-text-widgets-api.md
Demonstrates conditional rendering of a 'Balance' field based on its presence in the provided data.
```python
Window(
Const("Welcome!"),
Format(
"Balance: ${balance}",
when=lambda data, *_: data.get("balance") is not None,
),
state=MyState.main,
getter=get_data,
)
```
--------------------------------
### Setup Dialogs Middleware
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/quickstart/index.md
Call `setup_dialogs` to register necessary middlewares and core handlers for aiogram-dialog with your Dispatcher.
```python
from aiogram_dialog import setup_dialogs
setup_dialogs(dp)
```
--------------------------------
### Group Widget Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Example showing how to use the Group widget to display buttons 'Option A', 'Option B', and 'Option C' in a single row.
```python
Window(
Const("Choose:"),
Group(
Button(Const("Option A"), id="a"),
Button(Const("Option B"), id="b"),
Button(Const("Option C"), id="c"),
),
state=MyState.choose,
)
```
--------------------------------
### Starting Background Task with Progress
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/text/progress/index.md
This snippet illustrates how to initiate a background task for progress updates using `manager.bg()`. It specifies user and chat IDs, a stack ID, and loads existing data, then starts a specific background state.
```python
async def start_bg(callback: CallbackQuery, button: Button,
manager: DialogManager):
bg = manager.bg(
user_id=callback.from_user.id,
chat_id=callback.message.chat.id,
stack_id="progress_stack",
load=True,
)
await bg.start(Bg.progress)
asyncio.create_task(background(callback, bg))
```
--------------------------------
### Calendar Widget Usage Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/05-keyboard-widgets-api.md
Example demonstrating the Calendar widget for picking a date. The `on_date_selected` handler updates dialog data with the ISO format of the selected date.
```python
async def on_date_selected(event, widget, manager, date):
await manager.update(data={"selected_date": date.isoformat()})
Window(
Const("Pick a date:"),
Calendar(id="calendar", on_click=on_date_selected),
state=MyState.pick_date,
)
```
--------------------------------
### Start a New Dialog
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Initiates a new dialog and displays its first window. Use RESET_STACK mode to clear the existing dialog stack before starting.
```python
async def handle_start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(
MainMenu.greeting,
data={"user_id": message.from_user.id},
mode=StartMode.RESET_STACK,
)
```
--------------------------------
### TextInput Widget Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/input/text_input/index.md
Demonstrates the usage of the TextInput widget for capturing country and age, including type validation for age. The example sets up multiple windows for different input stages and a final window to display the collected information.
```python
from typing import Any
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import Message
from aiogram_dialog import (
Dialog,
DialogManager,
Window,
)
from aiogram_dialog.widgets.input import TextInput
from aiogram_dialog.widgets.kbd import Next
from aiogram_dialog.widgets.text import Const, Jinja
class SG(StatesGroup):
age = State()
country = State()
result = State()
async def error(
message: Message,
dialog_: Any,
manager: DialogManager,
error_: ValueError
):
await message.answer("Age must be a number!")
async def getter(dialog_manager: DialogManager, **kwargs):
return {
"age": dialog_manager.find("age").get_value(),
"country": dialog_manager.find("country").get_value(),
}
dialog = Dialog(
Window(
Const("Enter your country:"),
TextInput(id="country", on_success=Next()),
state=SG.country,
),
Window(
Const("Enter your age:"),
TextInput(
id="age",
on_error=error,
on_success=Next(),
type_factory=int,
),
state=SG.age,
),
Window(
Jinja(
"You entered:\n\n"
"age: {{age}}\n"
"country: {{country}}\n"
),
state=SG.result,
getter=getter,
parse_mode="html",
),
)
```
--------------------------------
### Dialog Lifecycle Registration and Setup
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/11-quick-reference.md
Register the dialog router with dp.include_router and set up dialogs using setup_dialogs(dp). These are the initial steps for integrating aiogram-dialog into your application.
```python
# 1. Register: dp.include_router(dialog)
# 2. Setup: setup_dialogs(dp)
```
--------------------------------
### DialogManager.start
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Starts a new dialog and displays its initial window. It can optionally accept data, specify how to handle an existing dialog stack, and define how the dialog should be shown.
```APIDOC
## DialogManager.start
### Description
Start a new dialog and show its first window.
### Method
`start`
### Parameters
- **state** (State) - Required - Initial FSM state (usually first window state)
- **data** (dict or None) - Optional - Optional data passed to dialog's on_start callback
- **mode** (StartMode) - Optional - How to handle existing stack - NORMAL, RESET_STACK, or NEW_STACK
- **show_mode** (ShowMode or None) - Optional - How to show the dialog - AUTO, EDIT, SEND, DELETE_AND_SEND, or NO_UPDATE
- **access_settings** (AccessSettings or None) - Optional - Access control settings for stack
### Raises
Exception if state is not registered or dialog not found
### Example
```python
async def handle_start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(
MainMenu.greeting,
data={"user_id": message.from_user.id},
mode=StartMode.RESET_STACK,
)
```
```
--------------------------------
### StartMode Values
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Defines the different modes for starting a dialog.
```APIDOC
### StartMode Values
- **NORMAL**: Continue from current state without resetting stack
- **RESET_STACK**: Clear existing stack and start fresh
- **NEW_STACK**: Create new stack while retaining old one
```
--------------------------------
### Register Dialog with Dispatcher
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/README.md
Include the created dialog router into the Dispatcher and call setup_dialogs to enable dialog functionality. This setup is crucial for the dialogs to operate correctly.
```python
from aiogram import Dispatcher
from aiogram_dialog import setup_dialogs
dp = Dispatcher(storage=storage) # create as usual
dp.include_router(dialog)
setup_dialogs(dp)
```
--------------------------------
### Dialog Lifecycle Start and Handling
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/11-quick-reference.md
Initiate a dialog with manager.start(state) and handle events through callbacks like on_start, on_close, and event handlers for user interactions.
```python
# 3. Start: await manager.start(state)
# 4. On Start: on_start callback (if defined)
# 5. Render: Window renders text, keyboard, media
# 6. Show: Message sent or edited
# 7. Handle Event: User clicks button or sends message
# 8. Process: Window processes event
# 9. Close: await manager.done() or Cancel()
# 10. On Close: on_close callback (if defined)
```
--------------------------------
### Setup Dialogs Function Signature
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
The main function to initialize the dialog system with a dispatcher. It accepts various optional parameters for customization.
```python
def setup_dialogs(
router: Router,
*,
dialog_manager_factory: DialogManagerFactory | None = None,
message_manager: MessageManagerProtocol | None = None,
media_id_storage: MediaIdStorageProtocol | None = None,
stack_access_validator: StackAccessValidator | None = None,
events_isolation: BaseEventIsolation | None = None,
getter: DataGetter | None = None,
) -> BgManagerFactory
```
--------------------------------
### JSON-Serializable Dialog Data Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/13-data-flows-and-context.md
Demonstrates how to structure dialog data to be JSON-serializable by using primitive types.
```python
dialog_data = {
"name": "John",
"age": 25,
"tags": ["admin", "verified"],
"score": 95.5,
}
```
--------------------------------
### Setup Jinja2 Environment
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/04-text-widgets-api.md
Globally configures the Jinja2 environment for use with the Jinja text widget. Allows specifying a custom environment or loader.
```python
def setup_jinja(
env: Environment | None = None,
loader: BaseLoader | None = None,
) -> None
```
```python
from jinja2 import Environment, FileSystemLoader
from aiogram_dialog.widgets.text import setup_jinja
setup_jinja(
loader=FileSystemLoader("templates/"),
)
```
--------------------------------
### Setup aiogram Dispatcher and Dialogs
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/00-core-concepts.md
This snippet shows how to create an asynchronous dispatcher and include dialogs in your aiogram bot. Ensure you import the necessary components.
```python
from aiogram import Dispatcher
from aiogram_dialog import setup_dialogs, Dialog, Window
dp = Dispatcher()
dialog = Dialog(...)
dp.include_router(dialog)
setup_dialogs(dp)
```
--------------------------------
### Show Link Preview Above Text Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Illustrates configuring the LinkPreview widget to display the URL preview above the message text by setting `show_above_text` to True.
```python
Window(
Format("Featured: {url}"),
LinkPreview(show_above_text=True),
state=MyState.featured,
)
```
--------------------------------
### Select Widget Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/keyboard/select/index.md
Demonstrates how to create and configure a Select widget. It uses a Format for button text, specifies an ID, an item ID getter, defines the source of items from window data, and sets an on-click handler.
```python
import operator
from typing import Any
from aiogram.types import CallbackQuery
from aiogram_dialog import DialogManager
from aiogram_dialog.widgets.kbd import Select
from aiogram_dialog.widgets.text import Format
# let's assume this is our window data getter
async def get_data(**kwargs):
fruits = [
("Apple", '1'),
("Pear", '2'),
("Orange", '3'),
("Banana", '4'),
]
return {
"fruits": fruits,
"count": len(fruits),
}
async def on_fruit_selected(callback: CallbackQuery, widget: Any,
manager: DialogManager, item_id: str):
print("Fruit selected: ", item_id)
fruits_kbd = Select(
Format("{item[0]} ({pos}/{data[count]})"), # E.g `✓ Apple (1/4)`
id="s_fruits",
item_id_getter=operator.itemgetter(1),
# each item is a tuple with id on a first position
items="fruits", # we will use items from window data at a key `fruits`
on_click=on_fruit_selected,
)
```
--------------------------------
### Get Current Dialog Context
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Retrieves the current dialog's context, including its state and start data. Raises `NoContextError` if no dialog is active.
```python
ctx = dialog_manager.current_context()
print(ctx.state) # Current FSM state
print(ctx.start_data) # Data passed to start()
```
--------------------------------
### Handle Button Callback Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/03-dialog-manager-api.md
Handles callback queries from buttons within a dialog, allowing for state transitions. It checks for an existing dialog context before switching states.
```python
@router.callback_query()
async def handle_button(query: CallbackQuery, dialog_manager: DialogManager):
if dialog_manager.has_context():
ctx = dialog_manager.current_context()
await dialog_manager.switch_to(MyDialog.next_state)
```
--------------------------------
### Prevent Unregistered Dialog Error
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/09-errors-and-exceptions.md
Ensure dialogs are correctly registered with the Dispatcher and `setup_dialogs` is called to prevent `UnregisteredDialogError`. This example shows the necessary setup steps.
```python
from aiogram import Dispatcher
from aiogram_dialog import setup_dialogs
dp = Dispatcher()
dp.include_router(my_dialog) # Must register
setup_dialogs(dp) # Must call setup
try:
await dialog_manager.start(MyDialog.state)
except UnregisteredDialogError as e:
print(f"Dialog not found: {e}")
```
--------------------------------
### Serve Dialog Previews via Web
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/helper_tools/index.md
Serve dialog previews directly using the command line interface. Run `aiogram-dialog-preview` with the path to your Dispatcher, Router, or Dialog object.
```bash
aiogram-dialog-preview example/subdialog:dialog_router
```
--------------------------------
### Define Product List and Detail Windows
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/02-window-api.md
Example of defining two windows for a product dialog: one for listing products and another for displaying product details. It includes state definitions, data getters, and widget configurations.
```python
from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog import Window
from aiogram_dialog.widgets.text import Format, Const
from aiogram_dialog.widgets.kbd import Button, Select
from aiogram_dialog.widgets.media import StaticMedia
class ProductView(StatesGroup):
list = State()
detail = State()
async def get_products(**kwargs):
return {"products": ["Product A", "Product B"]}
async def get_product_detail(item_id: str, **kwargs):
products = {"1": "Product A", "2": "Product B"}
return {"product_name": products.get(item_id, "Unknown")}
dialog_windows = [
Window(
Const("Available products:"),
Select(
Format("{item}"),
id="products",
item_id_getter=lambda x: str(x),
items=lambda data: enumerate(data["products"]),
),
state=ProductView.list,
getter=get_products,
),
Window(
Format("Product: {product_name}"),
Button(Const("Back"), id="back"),
state=ProductView.detail,
getter=get_product_detail,
parse_mode="HTML",
),
]
```
--------------------------------
### setup_dialogs
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/07-setup-and-configuration.md
Main function to initialize the dialog system with your dispatcher. It registers dialogs and sets up the middleware pipeline.
```APIDOC
## setup_dialogs
### Description
Main setup function to initialize dialog system with dispatcher. Registers dialogs with Dispatcher and sets up middleware pipeline.
### Parameters
- **router** (Router) - Required - Aiogram router or dispatcher to register dialogs with
- **dialog_manager_factory** (DialogManagerFactory | None) - Optional - Custom factory for creating DialogManager instances
- **message_manager** (MessageManagerProtocol | None) - Optional - Custom message manager for sending/editing messages
- **media_id_storage** (MediaIdStorageProtocol | None) - Optional - Custom storage for media IDs to avoid reuploads
- **stack_access_validator** (StackAccessValidator | None) - Optional - Custom validator for access control
- **events_isolation** (BaseEventIsolation | None) - Optional - FSM isolation strategy
- **getter** (DataGetter | None) - Optional - Global getter applied to all dialogs
### Returns
Returns `BgManagerFactory` for creating background managers outside of event handling.
### Basic Setup
```python
from aiogram import Bot, Dispatcher
from aiogram_dialog import Dialog, Window, setup_dialogs
# Create dispatcher
dp = Dispatcher()
# Create and register dialogs
my_dialog = Dialog(
Window(...),
)
dp.include_router(my_dialog)
# Setup dialogs - must be called after registering all dialogs
bg_manager_factory = setup_dialogs(dp)
```
### Custom Configuration
```python
from aiogram.fsm.storage.memory import MemoryStorage, SimpleEventIsolation
from aiogram_dialog import setup_dialogs
# Register dialogs...
# Setup with custom components
bg_manager_factory = setup_dialogs(
dp,
events_isolation=SimpleEventIsolation(),
getter=async def global_getter(**kwargs):
return {"app_version": "1.0.0"}
)
```
### Integration with Bot Polling
```python
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram_dialog import setup_dialogs
TOKEN = "123:ABC"
async def main():
bot = Bot(token=TOKEN)
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
# Include dialogs
dp.include_router(my_dialog)
# Setup dialogs
bg_manager_factory = setup_dialogs(dp)
# Start polling
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
```
```
--------------------------------
### Text Widgets Examples
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/11-quick-reference.md
Examples of common text widgets used in aiogram-dialog for displaying static or dynamic text.
```python
Const("Hello")
```
```python
Format("Name: {name}")
```
```python
Jinja("{% for x in items %}...")
```
```python
Case("status", {"active": ..., "done": ...})
```
```python
List(items=..., item_formatter=...)
```
```python
Multi(Const("A"), Format("{b}"), sep="\n")
```
--------------------------------
### Check Stack Depth Before Starting Submenu
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/09-errors-and-exceptions.md
Prevent exceeding maximum stack depth by checking before starting a new submenu.
```python
MAX_STACK_DEPTH = 5
async def start_submenu(dialog_manager: DialogManager):
stack = dialog_manager.current_stack()
if len(stack.contexts) >= MAX_STACK_DEPTH:
await dialog_manager.show(show_mode=ShowMode.NO_UPDATE)
return
await dialog_manager.start(Submenu.main)
```
--------------------------------
### Basic StaticMedia Widget Usage
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/widgets/media/static_media/index.md
Demonstrates how to use the StaticMedia widget to display a photo from a local file path. Ensure the path is correct and accessible.
```python
from aiogram.types import ContentType
from aiogram_dialog import Window
from aiogram_dialog.widgets.media import StaticMedia
windows = Window(
StaticMedia(
path="/home/tishka17/python_logo.png",
type=ContentType.PHOTO,
),
)
```
--------------------------------
### Window Constructor
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/02-window-api.md
Initializes a new Window instance. It takes various widgets, an FSM state, and optional parameters for data fetching, result processing, markup generation, and message formatting.
```APIDOC
## Window Constructor
### Description
Initializes a new Window instance. It takes various widgets, an FSM state, and optional parameters for data fetching, result processing, markup generation, and message formatting.
### Parameters
- **widgets** (*WidgetSrc): Variable-length argument of UI widgets. Widgets are parsed to identify text, keyboard, message handler, media, and link preview.
- **state** (State): FSM state for this window. Must belong to StatesGroup used by parent dialog.
- **getter** (Awaitable or None): Async function returning dict of data for rendering text and keyboards. Called before each render.
- **on_process_result** (Callable[[Data, Any, DialogManager], Awaitable] or None): Callback when nested dialog returns result.
- **markup_factory** (MarkupFactory): Factory for rendering keyboard markup. Default uses Telegram inline keyboards.
- **parse_mode** (str or None): Text parse mode for message. Values: "HTML", "Markdown", "MarkdownV2", or None.
- **protect_content** (bool or None): Whether to protect message from forwarding/copying.
- **disable_web_page_preview** (bool or None): Deprecated. Use LinkPreview widget instead. Disables preview for URLs in text.
- **preview_add_transitions** (list[Keyboard] or None): Additional keyboard transitions to show in offline preview.
- **preview_data** (Awaitable or None): Getter used only for preview generation, separate from runtime getter.
```
--------------------------------
### StaticMedia Widget - From File
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Use StaticMedia to display a document from a local file path. Specify the correct file path and content type.
```python
Window(
Const("Catalog:"),
StaticMedia(
path="./catalog.pdf",
type=ContentType.DOCUMENT,
),
state=MyState.catalog,
)
```
--------------------------------
### Handle Dialog Start Errors
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/09-errors-and-exceptions.md
Safely start a dialog and handle potential errors like unregistered dialogs or general dialogs errors.
```python
async def start_dialog(message: Message, dialog_manager: DialogManager):
try:
await dialog_manager.start(
MyDialog.greeting,
mode=StartMode.RESET_STACK,
)
except UnregisteredDialogError:
await message.reply("Dialog not configured")
except DialogsError as e:
await message.reply(f"Error: {e}")
```
--------------------------------
### setup_jinja
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/04-text-widgets-api.md
Configures the Jinja2 environment globally for use with Jinja text widgets. Allows specifying a custom environment or loader.
```APIDOC
## Function: setup_jinja
### Description
Configures the global Jinja2 environment. This function allows you to set up a custom Jinja2 Environment or specify a template loader for all Jinja widgets.
### Parameters
- **env** (Environment | None) - Optional - A custom Jinja2 Environment instance.
- **loader** (BaseLoader | None) - Optional - A custom Jinja2 template loader.
```
--------------------------------
### Window Methods
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/02-window-api.md
Includes methods for retrieving the window's state, finding widgets, and rendering text, keyboard, and media.
```APIDOC
## Window Methods
### get_state
```python
def get_state(self) -> State
```
Returns the FSM state for this window.
### find
```python
def find(self, widget_id: str) -> Widget | None
```
Find a widget by ID within this window's widget tree.
**Parameters**:
- `widget_id` (str): The widget ID to search for
**Returns**: Widget instance or None
### render_text
```python
async def render_text(self, data: dict, manager: DialogManager) -> str
```
Render the text for this window.
**Parameters**:
- `data` (dict): Data dict from getter
- `manager` (DialogManager): Dialog manager
**Returns**: Rendered text string
### render_kbd
```python
async def render_kbd(self, data: dict, manager: DialogManager) -> MarkupVariant
```
Render the keyboard for this window.
**Parameters**:
- `data` (dict): Data dict from getter
- `manager` (DialogManager): Dialog manager
**Returns**: InlineKeyboard or other markup
### render_media
```python
async def render_media(self, data: dict, manager: DialogManager) -> MediaAttachment | None
```
Render media attachment if present.
**Parameters**:
- `data` (dict): Data dict from getter
- `manager` (DialogManager): Dialog manager
**Returns**: MediaAttachment or None
```
--------------------------------
### Print Current Dialog and Start Data
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/13-data-flows-and-context.md
A handler function to print the current dialog data and start data managed by the DialogManager for debugging purposes.
```python
async def debug_handler(event, button, manager: DialogManager):
print(f"Dialog data: {manager.dialog_data}")
print(f"Start data: {manager.start_data}")
ctx = manager.current_context()
print(f"Context: state={ctx.state}, id={ctx.id}")
```
--------------------------------
### Initialize Bot and Dispatcher
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/docs/quickstart/index.md
Set up your aiogram Bot and Dispatcher instances. Proper storage is crucial as aiogram-dialog uses FSMContext internally.
```python
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(storage=storage)
```
--------------------------------
### Simple String TextInput Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Demonstrates a basic TextInput widget configured to capture a user's name as a string. The on_success callback updates dialog data with the provided name.
```python
async def on_name_input(message: Message, widget, manager: DialogManager, data: str):
await manager.update(data={"user_name": data})
Window(
Const("Enter your name:"),
TextInput(
id="name_input",
on_success=on_name_input,
),
state=MyState.name,
)
```
--------------------------------
### Window Constructor
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/02-window-api.md
Initializes a new Window instance with various configuration options for widgets, state, rendering, and event handling.
```python
def __init__(
self,
*widgets: WidgetSrc,
state: State,
getter: GetterVariant = None,
on_process_result: OnResultEvent | None = None,
markup_factory: MarkupFactory = _DEFAULT_MARKUP_FACTORY,
parse_mode: str | None = UNSET_PARSE_MODE,
disable_web_page_preview: bool | None = None,
protect_content: bool | None = None,
preview_add_transitions: list[Keyboard] | None = None,
preview_data: GetterVariant = None,
)
```
--------------------------------
### Photo Upload MessageInput Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Example of using MessageInput to capture a photo upload. The on_success callback extracts the file ID of the last photo in the message.
```python
async def on_photo(message: Message, widget, manager: DialogManager):
if message.photo:
photo_id = message.photo[-1].file_id
await manager.update(data={"photo_id": photo_id})
Window(
Const("Send your photo:"),
MessageInput(
id="photo_input",
on_success=on_photo,
),
state=MyState.photo,
)
```
--------------------------------
### TextInput with Filter Example
Source: https://github.com/tishka17/aiogram_dialog/blob/develop/_autodocs/08-media-and-input-widgets.md
Illustrates using a filter with TextInput to validate input before processing. This example ensures the input contains an '@' symbol, suitable for email validation.
```python
async def validate_email(message: Message, **kwargs) -> bool:
return "@" in message.text
async def on_email_input(message: Message, widget, manager: DialogManager, data: str):
await manager.update(data={"email": data})
Window(
Const("Enter email:"),
TextInput(
id="email_input",
filter=validate_email,
on_success=on_email_input,
),
state=MyState.email,
)
```