Setup app
These examples expect that the user has setup the initial application like the following code snippet. The examples should be inserted into the home_page function.
It is recommended to use a virtual environment like poetry or pipenv.
Create a main.py file
from uiwiz import ui, UiwizApp
import uvicorn
app = UiwizApp()
@app.page("/")
async def home_page():
ui.label("Hello world")
if __name__ == "__main__":
uvicorn.run("main:app", reload=True)
Run it
python main.py
Text elements
Labels for inputs
ui.label("Create a label")
Link
ui.link("UiWizard", "https://ui-wizard.com")
ui.link("UiWizard", "https://ui-wizard.com").classes("btn btn-ghost drawer-button font-normal")
with ui.element("ul").classes("menu menu-horizontal menu-md"):
with ui.element("li"):
ui.link("UiWizard", "https://ui-wizard.com")
Markdown
ui.markdown("""This is **Markdown**.""")
This is Markdown.
HTML
ui.html("UiWizard <strong>STRONG</strong>")
Control elements
Button
from uiwiz import ui, UiwizApp
app = UiwizApp()
@app.ui("/click/button")
def click_button():
ui.toast("Clicked")
ui.button("Click me").on_click(click_button, swap="none")
Checkbox
box = ui.checkbox(name="checkbox")
ui.label(text="Checkbox", for_=box)
Checkbox
ui.datepicker(name="datepicker", value=datetime.now(timezone.utc))
Toggle
toggle = ui.toggle(name="key_name")
ui.label("Enable feature", toggle)
Dropdown
items = ["UiWizard", "HTMX"]
ui.dropdown(name="selection", items=items, placeholder="Placeholder")
Range
ui.range(name="Range", min=0, max=10, value=0, step=2)
Radio
with ui.col():
with ui.row():
wiz = ui.radio(name="radio", value="UiWizard")
ui.label(text="UiWizard", for_=wiz)
with ui.row():
htmx = ui.radio(name="radio", value="HTMX")
ui.label(text="HTMX", for_=htmx)
Input
from uiwiz import ui, UiwizApp
app = UiwizApp()
class InputModel(BaseModel):
input: str
@app.ui("/change/input")
def change_input(input_model: InputModel):
ui.element(content=input_model.input)
ui.input(name="input", placeholder="Text").on("input", change_input, target=lambda: output.id)
output = ui.element()
Text area
from uiwiz import ui, UiwizApp
app = UiwizApp()
class InputModel(BaseModel):
input: str
@app.ui("/change/input")
def change_input(input_model: InputModel):
ui.element(content=input_model.input)
ui.textarea(name="input", placeholder="Text").on("input", change_input, target=lambda: output.id)
output = ui.element()
Upload
The upload is limited to 2048 bytes as it could be used to abuse server
from uiwiz import ui, UiwizApp
from fastapi import UploadFile
app = UiwizApp()
async def handle_upload(upload: UploadFile):
data = upload.read()
ui.toast(data)
ui.upload(name="upload").on_upload(on_upload=handle_upload, swap="none").attributes["accept"] = ".txt"
Forms
The name of the input element must match the name of the model attribute. Notice that the form will indicate the input, which failed validation. This works by leveraging pydantic and fastapi, which automatically sends a 422 response with the fields that failed validation.
from pydantic import BaseModel, Field
from uiwiz import ui, UiwizApp
app = UiwizApp()
class FormData(BaseModel):
desc: str = Field(min_length=4)
age: int
# ..
# Without the @app.ui a hash of the function is
# used instead for the endpoint instead
@app.ui("/form/inputdata")
async def handle_form_request(input_form: FormData):
ui.toast(str(input_form)).success()
with ui.form().on_submit(handle_form_request, swap="none"):
ui.input("Description", name="desc")
ui.input("Age", name="age")
ui.button("submit")
It is also possible to have UiWiard create the form from a model
class FormData(BaseModel):
desc: str = Field(min_length=4)
age: int
# ..
@app.ui("/form/inputdata")
async def handle_form_request(input_form: FormData):
ui.toast(str(input_form)).success()
ui.modelForm(FormData).on_submit(handle_form_request)
It is also possible to customize the inputs from the model
class Base(BaseModel):
desc: Annotated[str, UiAnno(ui.textarea)] = Field(min_length=4)
age: int
ui.modelForm(
Base,
age={
"ui": ui.dropdown,
"placeholder": "Select",
"items": [1, 2, 3, 4]
}
).on_submit(handle_form_request)
Indicators
ui.spinner()
ui.spinner().ball()
ui.spinner().bars()
ui.spinner().infinity()
ui.spinner().dots()
ui.spinner().infinity().extra_small()
ui.spinner().infinity().small()
ui.spinner().infinity().medium()
ui.spinner().infinity().large()
The indicators can be used on actions performed by any element that requires a web request transaction
with ui.button("Request").on_click(handle_spinner, swap="none") as requester:
ui.spinner(requester).infinity().medium()
Data and layout
Tables
data = [
{"col1": "dat1", "col2": "dat2"},
{"col1": "dat1", "col2": "dat2"}
]
df = pd.DataFrame(data)
ui.table.from_dataframe(df)
col1 | col2 |
---|---|
dat1 | dat2 |
dat1 | dat2 |
data = [
{"col1": "dat1", "col2": "dat2"},
{"col1": "dat1", "col2": "dat2"}
]
df = pd.DataFrame(data)
ui.aggrid(df)
Tabs
with ui.tabs():
with ui.tab("Tab 1"):
ui.element(content="This is tab 1")
with ui.tab("Tab 2"):
ui.element(content="This is tab 2")
Toast
The current version supports 4 different look and feel for toast.
Info, Error, Warning, Success
from uiwiz import ui, UiwizApp
app = UiwizApp()
@app.ui("/click/button")
def click_button():
ui.toast("Clicked")
ui.toast("Clicked").info()
ui.toast("Clicked").success()
ui.toast("Clicked").warning()
ui.toast("Clicked").error()
ui.button("Click me").on_click(click_button, swap="none")
from uiwiz import ui, UiwizApp
app = UiwizApp()
@app.ui("/click/button/rich")
def click_button_rich():
with ui.toast():
ui.html("This is the github logo")
svg = ui.html('''
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
''')
# Style the gh logo to match the current theme
svg.attributes["style"] = "fill: oklch(var(--bc)/1);"
svg.classes("rounded-full")
ui.button("Click me").on_click(click_button_rich, swap="none")
Components
def component(data: dict):
with ui.element():
ui.label("This is a component")
for key, value in data.items():
ui.html(f"Key: {key}, Value: {value}")
component({"key1": "value1", "key2": "value2"})
Show
data = {
"name": "Karl",
"age": 20,
"city": "Random"
}
with row():
ui.show(data)
ui.show([data])
name | age | city |
---|---|---|
Karl | 20 | Random |
Karl | 20 | Random |
Karl | 20 | Random |
Drawer
with ui.drawer(always_open=True, right=False) as drawer:
with drawer.drawer_content():
with ui.nav().classes("w-full navbar"):
with ui.label(for_=drawer.drawer_toggle).classes("btn drawer-button lg:hidden"):
ui.html(get_svg("menu"))
ui.label("test1")
with ui.footer():
ui.label("some footer text")
with drawer.drawer_side():
with ui.element("li"):
ui.link("Github", "https://github.com/Declow/uiwiz")