!DOCTYPE>
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
ui.label("Create a label")
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")
ui.markdown("""This is **Markdown**.""")
This is Markdown.
ui.html("UiWizard <strong>STRONG</strong>")
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")
box = ui.checkbox(name="checkbox")
ui.label(text="Checkbox", for_=box)
ui.datepicker(name="datepicker", value=datetime.now(timezone.utc))
toggle = ui.toggle(name="key_name")
ui.label("Enable feature", toggle)
items = ["UiWizard", "HTMX"]
ui.dropdown(name="selection", items=items, placeholder="Placeholder")
ui.range(name="Range", min=0, max=10, value=0, step=2)
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)
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()
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()
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"
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)
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 = [
{"col1": "dat1", "col2": "dat2"},
{"col1": "dat1", "col2": "dat2"}
]
df = pd.DataFrame(data)
ui.table.from_dataframe(df)
col1 | col2 |
---|---|
dat1 | dat2 |
dat1 | dat2 |
from uiwiz import PageRouter, ui
from uiwiz.models.model_handler import UiAnno
from pydantic import BaseModel
# Define the model
class TableData(BaseModel):
id: Annotated[str, UiAnno(ui.hiddenInput)]
input: str
title: str
des: str
# Create some data
table_data = {
"1": TableData(id="1", input="This is input", title="Some title", des="Description"),
"2": TableData(id="2", input="Second input", title="Second title", des="Description")
}
@router.ui("/table/save/row/")
async def save_row(model: TableData):
ui.table.render_row(model, "id", edit_row, delete_row)
@router.ui("/table/display/row/{id}")
async def display_row(id: str):
if id in table_data:
ui.table.render_row(table_data[id], "id", edit_row, delete_row)
@router.ui("/table/edit/row/{id}")
async def edit_row(id: str):
ui.table.render_edit_row(
table_data[id],
"id",
save_row,
display_row,
)
@router.ui("/table/delete/row/{id}")
async def delete_row(id: str):
# Delete the row
pass
@router.ui("/table/add/row/")
async def add_row():
ui.table.render_edit_row(
TableData(id=str(len(table_data) + 1), input="", title="", des=""),
"id",
save_row,
display_row
)
ui.table(list(table_data.values()), "id").edit_row(edit_row).delete_row(delete_row).create_row(add_row)
id | input | title | des | |
---|---|---|---|---|
1 | This is input | Some title | Description | |
2 | Second input | Second title | Description |
data = [
{"col1": "dat1", "col2": "dat2"},
{"col1": "dat1", "col2": "dat2"}
]
df = pd.DataFrame(data)
ui.aggrid(df)
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")
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")
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"})
data = {
"name": "Karl",
"age": 20,
"city": "Random",
"friends": ["John", "Doe"]
}
ui.dict(data).border_classes("bg-base-200 w-full rounded-lg pl-4")
{
"name":"Karl",
"age":20,
"city":"Random",
"friends": ["John","Doe"
]
}
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 |
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")
ui.echart({
"tooltip": {"trigger": "axis", "axisPointer": {"type": "line"}},
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
"yAxis": {"type": "value"},
"series": [
{
"name": "Sales",
"type": "line",
"data": [150, 230, 224, 218, 135, 147, 260],
}
],
})
from uiwiz import ui, UiwizApp
from random import randint
app = UiwizApp()
@app.post("/update/chart")
async def update_chart():
return ui.echart.response(
{
"tooltip": {"trigger": "axis", "axisPointer": {"type": "line"}},
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
"yAxis": {"type": "value"},
"series": [
{
"name": "Sales",
"type": "line",
"data": [randint(0, 300) for _ in range(7)],
}
],
}
)
@app.post("/")
async def page_with_chart():
ui.element(content="Update chart")
ui.button("Update chart").on_click(update_chart, lambda: chart.id, swap="none")
chart = ui.echart({
"tooltip": {"trigger": "axis", "axisPointer": {"type": "line"}},
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
"yAxis": {"type": "value"},
"series": [
{
"name": "Sales",
"type": "line",
"data": [150, 230, 224, 218, 135, 147, 260],
}
],
})
ui.echart({
"series": {
"type": "sankey",
"layout": "none",
"emphasis": {"focus": "adjacency"},
"data": [
{"name": "a"},
{"name": "b"},
{"name": "a1"},
{"name": "a2"},
{"name": "b1"},
{"name": "c"},
],
"links": [
{"source": "a", "target": "a1", "value": 5},
{"source": "a", "target": "a2", "value": 3},
{"source": "b", "target": "b1", "value": 8},
{"source": "a", "target": "b1", "value": 3},
{"source": "b1", "target": "a1", "value": 1},
{"source": "b1", "target": "c", "value": 2},
],
}
})