Spaces:
Sleeping
Sleeping
| # Concise reference | |
| <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> | |
| ## About FastHTML | |
| ``` python | |
| from fasthtml.common import * | |
| ``` | |
| FastHTML is a python library which brings together Starlette, Uvicorn, | |
| HTMX, and fastcore’s `FT` “FastTags” into a library for creating | |
| server-rendered hypermedia applications. The | |
| [`FastHTML`](https://www.fastht.ml/docs/api/core.html#fasthtml) class | |
| itself inherits from `Starlette`, and adds decorator-based routing with | |
| many additions, Beforeware, automatic `FT` to HTML rendering, and much | |
| more. | |
| Things to remember when writing FastHTML apps: | |
| - *Not* compatible with FastAPI syntax; FastHTML is for HTML-first apps, | |
| not API services (although it can implement APIs too) | |
| - FastHTML includes support for Pico CSS and the fastlite sqlite | |
| library, although using both are optional; sqlalchemy can be used | |
| directly or via the fastsql library, and any CSS framework can be | |
| used. MonsterUI is a richer FastHTML-first component framework with | |
| similar capabilities to shadcn | |
| - FastHTML is compatible with JS-native web components and any vanilla | |
| JS library, but not with React, Vue, or Svelte | |
| - Use [`serve()`](https://www.fastht.ml/docs/api/core.html#serve) for | |
| running uvicorn (`if __name__ == "__main__"` is not needed since it’s | |
| automatic) | |
| - When a title is needed with a response, use | |
| [`Titled`](https://www.fastht.ml/docs/api/xtend.html#titled); note | |
| that that already wraps children in | |
| [`Container`](https://www.fastht.ml/docs/api/pico.html#container), and | |
| already includes both the meta title as well as the H1 element. | |
| ## Minimal App | |
| The code examples here use fast.ai style: prefer ternary op, 1-line | |
| docstring, minimize vertical space, etc. (Normally fast.ai style uses | |
| few if any comments, but they’re added here as documentation.) | |
| A minimal FastHTML app looks something like this: | |
| ``` python | |
| # Meta-package with all key symbols from FastHTML and Starlette. Import it like this at the start of every FastHTML app. | |
| from fasthtml.common import * | |
| # The FastHTML app object and shortcut to `app.route` | |
| app,rt = fast_app() | |
| # Enums constrain the values accepted for a route parameter | |
| name = str_enum('names', 'Alice', 'Bev', 'Charlie') | |
| # Passing a path to `rt` is optional. If not passed (recommended), the function name is the route ('/foo') | |
| # Both GET and POST HTTP methods are handled by default | |
| # Type-annotated params are passed as query params (recommended) unless a path param is defined (which it isn't here) | |
| @rt | |
| def foo(nm: name): | |
| # `Title` and `P` here are FastTags: direct m-expression mappings of HTML tags to Python functions with positional and named parameters. All standard HTML tags are included in the common wildcard import. | |
| # When a tuple is returned, this returns concatenated HTML partials. HTMX by default will use a title HTML partial to set the current page name. HEAD tags (e.g. Meta, Link, etc) in the returned tuple are automatically placed in HEAD; everything else is placed in BODY. | |
| # FastHTML will automatically return a complete HTML document with appropriate headers if a normal HTTP request is received. For an HTMX request, however, just the partials are returned. | |
| return Title("FastHTML"), H1("My web app"), P(f"Hello, {name}!") | |
| # By default `serve` runs uvicorn on port 5001. Never write `if __name__ == "__main__"` since `serve` checks it internally. | |
| serve() | |
| ``` | |
| To run this web app: | |
| ``` bash | |
| python main.py # access via localhost:5001 | |
| ``` | |
| ## FastTags (aka FT Components or FTs) | |
| FTs are m-expressions plus simple sugar. Positional params map to | |
| children. Named parameters map to attributes. Aliases must be used for | |
| Python reserved words. | |
| ``` python | |
| tags = Title("FastHTML"), H1("My web app"), P(f"Let's do this!", cls="myclass") | |
| tags | |
| ``` | |
| (title(('FastHTML',),{}), | |
| h1(('My web app',),{}), | |
| p(("Let's do this!",),{'class': 'myclass'})) | |
| This example shows key aspects of how FTs handle attributes: | |
| ``` python | |
| Label( | |
| "Choose an option", | |
| Select( | |
| Option("one", value="1", selected=True), # True renders just the attribute name | |
| Option("two", value=2, selected=False), # Non-string values are converted to strings. False omits the attribute entirely | |
| cls="selector", id="counter", # 'cls' becomes 'class' | |
| **{'@click':"alert('Clicked');"}, # Dict unpacking for attributes with special chars | |
| ), | |
| _for="counter", # '_for' becomes 'for' (can also use 'fr') | |
| ) | |
| ``` | |
| Classes with `__ft__` defined are rendered using that method. | |
| ``` python | |
| class FtTest: | |
| def __ft__(self): return P('test') | |
| to_xml(FtTest()) | |
| ``` | |
| '<p>test</p>\n' | |
| You can create new FTs by importing the new component from | |
| `fasthtml.components`. If the FT doesn’t exist within that module, | |
| FastHTML will create it. | |
| ``` python | |
| from fasthtml.components import Some_never_before_used_tag | |
| Some_never_before_used_tag() | |
| ``` | |
| ``` html | |
| <some-never-before-used-tag></some-never-before-used-tag> | |
| ``` | |
| FTs can be combined by defining them as a function. | |
| ``` python | |
| def Hero(title, statement): return Div(H1(title),P(statement), cls="hero") | |
| to_xml(Hero("Hello World", "This is a hero statement")) | |
| ``` | |
| '<div class="hero">\n <h1>Hello World</h1>\n <p>This is a hero statement</p>\n</div>\n' | |
| When handling a response, FastHTML will automatically render FTs using | |
| the `to_xml` function. | |
| ``` python | |
| to_xml(tags) | |
| ``` | |
| '<title>FastHTML</title>\n<h1>My web app</h1>\n<p class="myclass">Let's do this!</p>\n' | |
| ## JS | |
| The [`Script`](https://www.fastht.ml/docs/api/xtend.html#script) | |
| function allows you to include JavaScript. You can use Python to | |
| generate parts of your JS or JSON like this: | |
| ``` python | |
| # In future snippets this import will not be shown, but is required | |
| from fasthtml.common import * | |
| app,rt = fast_app(hdrs=[Script(src="https://cdn.plot.ly/plotly-2.32.0.min.js")]) | |
| # `index` is a special function name which maps to the `/` route. | |
| @rt | |
| def index(): | |
| data = {'somedata':'fill me in…'} | |
| # `Titled` returns a title tag and an h1 tag with the 1st param, with remaining params as children in a `Main` parent. | |
| return Titled("Chart Demo", Div(id="myDiv"), Script(f"var data = {data}; Plotly.newPlot('myDiv', data);")) | |
| # In future snippets `serve() will not be shown, but is required | |
| serve() | |
| ``` | |
| Prefer Python whenever possible over JS. Never use React or shadcn. | |
| ## fast_app hdrs | |
| ``` python | |
| # In future snippets we'll skip showing the `fast_app` call if it has no params | |
| app, rt = fast_app( | |
| pico=False, # The Pico CSS framework is included by default, so pass `False` to disable it if needed. No other CSS frameworks are included. | |
| # These are added to the `head` part of the page for non-HTMX requests. | |
| hdrs=( | |
| Link(rel='stylesheet', href='assets/normalize.min.css', type='text/css'), | |
| Link(rel='stylesheet', href='assets/sakura.css', type='text/css'), | |
| Style("p {color: red;}"), | |
| # `MarkdownJS` and `HighlightJS` are available via concise functions | |
| MarkdownJS(), HighlightJS(langs=['python', 'javascript', 'html', 'css']), | |
| # by default, all standard static extensions are served statically from the web app dir, | |
| # which can be modified using e.g `static_path='public'` | |
| ) | |
| ) | |
| @rt | |
| def index(req): return Titled("Markdown rendering example", | |
| # This will be client-side rendered to HTML with highlight-js | |
| Div("*hi* there",cls="marked"), | |
| # This will be syntax highlighted | |
| Pre(Code("def foo(): pass"))) | |
| ``` | |
| ## Responses | |
| Routes can return various types: | |
| 1. FastTags or tuples of FastTags (automatically rendered to HTML) | |
| 2. Standard Starlette responses (used directly) | |
| 3. JSON-serializable types (returned as JSON in a plain text response) | |
| ``` python | |
| @rt("/{fname:path}.{ext:static}") | |
| async def serve_static_file(fname:str, ext:str): return FileResponse(f'public/{fname}.{ext}') | |
| app, rt = fast_app(hdrs=(MarkdownJS(), HighlightJS(langs=['python', 'javascript']))) | |
| @rt | |
| def index(): | |
| return Titled("Example", | |
| Div("*markdown* here", cls="marked"), | |
| Pre(Code("def foo(): pass"))) | |
| ``` | |
| Route functions can be used in attributes like `href` or `action` and | |
| will be converted to paths. Use `.to()` to generate paths with query | |
| parameters. | |
| ``` python | |
| @rt | |
| def profile(email:str): return fill_form(profile_form, profiles[email]) | |
| profile_form = Form(action=profile)( | |
| Label("Email", Input(name="email")), | |
| Button("Save", type="submit") | |
| ) | |
| user_profile_path = profile.to(email="user@example.com") # '/profile?email=user%40example.com' | |
| ``` | |
| ``` python | |
| from dataclasses import dataclass | |
| app,rt = fast_app() | |
| ``` | |
| When a route handler function is used as a fasttag attribute (such as | |
| `href`, `hx_get`, or `action`) it is converted to that route’s path. | |
| [`fill_form`](https://www.fastht.ml/docs/api/components.html#fill_form) | |
| is used to copy an object’s matching attrs into matching-name form | |
| fields. | |
| ``` python | |
| @dataclass | |
| class Profile: email:str; phone:str; age:int | |
| email = 'john@example.com' | |
| profiles = {email: Profile(email=email, phone='123456789', age=5)} | |
| @rt | |
| def profile(email:str): return fill_form(profile_form, profiles[email]) | |
| profile_form = Form(method="post", action=profile)( | |
| Fieldset( | |
| Label('Email', Input(name="email")), | |
| Label("Phone", Input(name="phone")), | |
| Label("Age", Input(name="age"))), | |
| Button("Save", type="submit")) | |
| ``` | |
| ## Testing | |
| We can use `TestClient` for testing. | |
| ``` python | |
| from starlette.testclient import TestClient | |
| ``` | |
| ``` python | |
| path = "/profile?email=john@example.com" | |
| client = TestClient(app) | |
| htmx_req = {'HX-Request':'1'} | |
| print(client.get(path, headers=htmx_req).text) | |
| ``` | |
| <form enctype="multipart/form-data" method="post" action="/profile"><fieldset><label>Email <input name="email" value="john@example.com"> | |
| </label><label>Phone <input name="phone" value="123456789"> | |
| </label><label>Age <input name="age" value="5"> | |
| </label></fieldset><button type="submit">Save</button></form> | |
| ## Form Handling and Data Binding | |
| When a dataclass, namedtuple, etc. is used as a type annotation, the | |
| form body will be unpacked into matching attribute names automatically. | |
| ``` python | |
| @rt | |
| def edit_profile(profile: Profile): | |
| profiles[email]=profile | |
| return RedirectResponse(url=path) | |
| new_data = dict(email='john@example.com', phone='7654321', age=25) | |
| print(client.post("/edit_profile", data=new_data, headers=htmx_req).text) | |
| ``` | |
| <form enctype="multipart/form-data" method="post" action="/profile"><fieldset><label>Email <input name="email" value="john@example.com"> | |
| </label><label>Phone <input name="phone" value="7654321"> | |
| </label><label>Age <input name="age" value="25"> | |
| </label></fieldset><button type="submit">Save</button></form> | |
| ## fasttag Rendering Rules | |
| The general rules for rendering children inside tuples or fasttag | |
| children are: - `__ft__` method will be called (for default components | |
| like `P`, `H2`, etc. or if you define your own components) - If you pass | |
| a string, it will be escaped - On other python objects, `str()` will be | |
| called | |
| If you want to include plain HTML tags directly into e.g. a `Div()` they | |
| will get escaped by default (as a security measure to avoid code | |
| injections). This can be avoided by using `Safe(...)`, e.g to show a | |
| data frame use `Div(NotStr(df.to_html()))`. | |
| ## Exceptions | |
| FastHTML allows customization of exception handlers. | |
| ``` python | |
| def not_found(req, exc): return Titled("404: I don't exist!") | |
| exception_handlers = {404: not_found} | |
| app, rt = fast_app(exception_handlers=exception_handlers) | |
| ``` | |
| ## Cookies | |
| We can set cookies using the | |
| [`cookie()`](https://www.fastht.ml/docs/api/core.html#cookie) function. | |
| ``` python | |
| @rt | |
| def setcook(): return P(f'Set'), cookie('mycookie', 'foobar') | |
| print(client.get('/setcook', headers=htmx_req).text) | |
| ``` | |
| <p>Set</p> | |
| ``` python | |
| @rt | |
| def getcook(mycookie:str): return f'Got {mycookie}' | |
| # If handlers return text instead of FTs, then a plaintext response is automatically created | |
| print(client.get('/getcook').text) | |
| ``` | |
| Got foobar | |
| FastHTML provide access to Starlette’s request object automatically | |
| using special `request` parameter name (or any prefix of that name). | |
| ``` python | |
| @rt | |
| def headers(req): return req.headers['host'] | |
| ``` | |
| ## Request and Session Objects | |
| FastHTML provides access to Starlette’s session middleware automatically | |
| using the special `session` parameter name (or any prefix of that name). | |
| ``` python | |
| @rt | |
| def profile(req, sess, user_id: int=None): | |
| ip = req.client.host | |
| sess['last_visit'] = datetime.now().isoformat() | |
| visits = sess.setdefault('visit_count', 0) + 1 | |
| sess['visit_count'] = visits | |
| user = get_user(user_id or sess.get('user_id')) | |
| return Titled(f"Profile: {user.name}", | |
| P(f"Visits: {visits}"), | |
| P(f"IP: {ip}"), | |
| Button("Logout", hx_post=logout)) | |
| ``` | |
| Handler functions can return the | |
| [`HtmxResponseHeaders`](https://www.fastht.ml/docs/api/core.html#htmxresponseheaders) | |
| object to set HTMX-specific response headers. | |
| ``` python | |
| @rt | |
| def htmlredirect(app): return HtmxResponseHeaders(location="http://example.org") | |
| ``` | |
| ## APIRouter | |
| [`APIRouter`](https://www.fastht.ml/docs/api/core.html#apirouter) lets | |
| you organize routes across multiple files in a FastHTML app. | |
| ``` python | |
| # products.py | |
| ar = APIRouter() | |
| @ar | |
| def details(pid: int): return f"Here are the product details for ID: {pid}" | |
| @ar | |
| def all_products(req): | |
| return Div( | |
| Div( | |
| Button("Details",hx_get=details.to(pid=42),hx_target="#products_list",hx_swap="outerHTML",), | |
| ), id="products_list") | |
| ``` | |
| ``` python | |
| # main.py | |
| from products import ar,all_products | |
| app, rt = fast_app() | |
| ar.to_app(app) | |
| @rt | |
| def index(): | |
| return Div( | |
| "Products", | |
| hx_get=all_products, hx_swap="outerHTML") | |
| ``` | |
| ## Toasts | |
| Toasts can be of four types: | |
| - info | |
| - success | |
| - warning | |
| - error | |
| Toasts require the use of the `setup_toasts()` function, plus every | |
| handler needs: | |
| - The session argument | |
| - Must return FT components | |
| ``` python | |
| setup_toasts(app) | |
| @rt | |
| def toasting(session): | |
| add_toast(session, f"cooked", "info") | |
| add_toast(session, f"ready", "success") | |
| return Titled("toaster") | |
| ``` | |
| `setup_toasts(duration)` allows you to specify how long a toast will be | |
| visible before disappearing.10 seconds. | |
| Authentication and authorization are handled with Beforeware, which | |
| functions that run before the route handler is called. | |
| ## Auth | |
| ``` python | |
| def user_auth_before(req, sess): | |
| # `auth` key in the request scope is automatically provided to any handler which requests it and can not be injected | |
| auth = req.scope['auth'] = sess.get('auth', None) | |
| if not auth: return RedirectResponse('/login', status_code=303) | |
| beforeware = Beforeware( | |
| user_auth_before, | |
| skip=[r'/favicon\.ico', r'/static/.*', r'.*\.css', r'.*\.js', '/login', '/'] | |
| ) | |
| app, rt = fast_app(before=beforeware) | |
| ``` | |
| ## Server-Side Events (SSE) | |
| FastHTML supports the HTMX SSE extension. | |
| ``` python | |
| import random | |
| hdrs=(Script(src="https://unpkg.com/htmx-ext-sse@2.2.3/sse.js"),) | |
| app,rt = fast_app(hdrs=hdrs) | |
| @rt | |
| def index(): return Div(hx_ext="sse", sse_connect="/numstream", hx_swap="beforeend show:bottom", sse_swap="message") | |
| # `signal_shutdown()` gets an event that is set on shutdown | |
| shutdown_event = signal_shutdown() | |
| async def number_generator(): | |
| while not shutdown_event.is_set(): | |
| data = Article(random.randint(1, 100)) | |
| yield sse_message(data) | |
| @rt | |
| async def numstream(): return EventStream(number_generator()) | |
| ``` | |
| ## Websockets | |
| FastHTML provides useful tools for HTMX’s websockets extension. | |
| ``` python | |
| # These HTMX extensions are available through `exts`: | |
| # head-support preload class-tools loading-states multi-swap path-deps remove-me ws chunked-transfer | |
| app, rt = fast_app(exts='ws') | |
| def mk_inp(): return Input(id='msg', autofocus=True) | |
| @rt | |
| async def index(request): | |
| # `ws_send` tells HTMX to send a message to the nearest websocket based on the trigger for the form element | |
| cts = Div( | |
| Div(id='notifications'), | |
| Form(mk_inp(), id='form', ws_send=True), | |
| hx_ext='ws', ws_connect='/ws') | |
| return Titled('Websocket Test', cts) | |
| async def on_connect(send): await send(Div('Hello, you have connected', id="notifications")) | |
| async def on_disconnect(ws): print('Disconnected!') | |
| @app.ws('/ws', conn=on_connect, disconn=on_disconnect) | |
| async def ws(msg:str, send): | |
| # websocket hander returns/sends are treated as OOB swaps | |
| await send(Div('Hello ' + msg, id="notifications")) | |
| return Div('Goodbye ' + msg, id="notifications"), mk_inp() | |
| ``` | |
| Sample chatbot that uses FastHTML’s | |
| [`setup_ws`](https://www.fastht.ml/docs/api/core.html#setup_ws) | |
| function: | |
| ``` py | |
| app = FastHTML(exts='ws') | |
| rt = app.route | |
| msgs = [] | |
| @rt('/') | |
| def home(): | |
| return Div(hx_ext='ws', ws_connect='/ws')( | |
| Div(Ul(*[Li(m) for m in msgs], id='msg-list')), | |
| Form(Input(id='msg'), id='form', ws_send=True) | |
| ) | |
| async def ws(msg:str): | |
| msgs.append(msg) | |
| await send(Ul(*[Li(m) for m in msgs], id='msg-list')) | |
| send = setup_ws(app, ws) | |
| ``` | |
| ### Single File Uploads | |
| [`Form`](https://www.fastht.ml/docs/api/xtend.html#form) defaults to | |
| “multipart/form-data”. A Starlette UploadFile is passed to the handler. | |
| ``` python | |
| upload_dir = Path("filez") | |
| @rt | |
| def index(): | |
| return ( | |
| Form(hx_post=upload, hx_target="#result")( | |
| Input(type="file", name="file"), | |
| Button("Upload", type="submit")), | |
| Div(id="result") | |
| ) | |
| # Use `async` handlers where IO is used to avoid blocking other clients | |
| @rt | |
| async def upload(file: UploadFile): | |
| filebuffer = await file.read() | |
| (upload_dir / file.filename).write_bytes(filebuffer) | |
| return P('Size: ', file.size) | |
| ``` | |
| For multi-file, use `Input(..., multiple=True)`, and a type annotation | |
| of `list[UploadFile]` in the handler. | |
| ## Fastlite | |
| Fastlite and the MiniDataAPI specification it’s built on are a | |
| CRUD-oriented API for working with SQLite. APSW and apswutils is used to | |
| connect to SQLite, optimized for speed and clean error handling. | |
| ``` python | |
| from fastlite import * | |
| ``` | |
| ``` python | |
| db = database(':memory:') # or database('data/app.db') | |
| ``` | |
| Tables are normally constructed with classes, field types are specified | |
| as type hints. | |
| ``` python | |
| class Book: isbn: str; title: str; pages: int; userid: int | |
| # The transform arg instructs fastlite to change the db schema when fields change. | |
| # Create only creates a table if the table doesn't exist. | |
| books = db.create(Book, pk='isbn', transform=True) | |
| class User: id: int; name: str; active: bool = True | |
| # If no pk is provided, id is used as the primary key. | |
| users = db.create(User, transform=True) | |
| users | |
| ``` | |
| <Table user (id, name, active)> | |
| ### Fastlite CRUD operations | |
| Every operation in fastlite returns a full superset of dataclass | |
| functionality. | |
| ``` python | |
| user = users.insert(name='Alex',active=False) | |
| user | |
| ``` | |
| User(id=1, name='Alex', active=0) | |
| ``` python | |
| # List all records | |
| users() | |
| ``` | |
| [User(id=1, name='Alex', active=0)] | |
| ``` python | |
| # Limit, offset, and order results: | |
| users(order_by='name', limit=2, offset=1) | |
| # Filter on the results | |
| users(where="name='Alex'") | |
| # Placeholder for avoiding injection attacks | |
| users("name=?", ('Alex',)) | |
| # A single record by pk | |
| users[user.id] | |
| ``` | |
| User(id=1, name='Alex', active=0) | |
| Test if a record exists by using `in` keyword on primary key: | |
| ``` python | |
| 1 in users | |
| ``` | |
| True | |
| Updates (which take a dict or a typed object) return the updated record. | |
| ``` python | |
| user.name='Lauren' | |
| user.active=True | |
| users.update(user) | |
| ``` | |
| User(id=1, name='Lauren', active=1) | |
| `.xtra()` to automatically constrain queries, updates, and inserts from | |
| there on: | |
| ``` python | |
| users.xtra(active=True) | |
| users() | |
| ``` | |
| [User(id=1, name='Lauren', active=1)] | |
| Deleting by pk: | |
| ``` python | |
| users.delete(user.id) | |
| ``` | |
| <Table user (id, name, active)> | |
| NotFoundError is raised by pk `[]`, updates, and deletes. | |
| ``` python | |
| try: users['Amy'] | |
| except NotFoundError: print('User not found') | |
| ``` | |
| User not found | |
| ## MonsterUI | |
| MonsterUI is a shadcn-like component library for FastHTML. It adds the | |
| Tailwind-based libraries FrankenUI and DaisyUI to FastHTML, as well as | |
| Python’s mistletoe for Markdown, HighlightJS for code highlighting, and | |
| Katex for latex support, following semantic HTML patterns when possible. | |
| It is recommended for when you wish to go beyond the basics provided by | |
| FastHTML’s built-in pico support. | |
| A minimal app: | |
| ``` python | |
| from fasthtml.common import * | |
| from monsterui.all import * | |
| app, rt = fast_app(hdrs=Theme.blue.headers(highlightjs=True)) # Use MonsterUI blue theme and highlight code in markdown | |
| @rt | |
| def index(): | |
| socials = (('github','https://github.com/AnswerDotAI/MonsterUI'),) | |
| return Titled("App", | |
| Card( | |
| P("App", cls=TextPresets.muted_sm), | |
| # LabelInput, DivLAigned, and UkIconLink are non-semantic MonsterUI FT Components, | |
| LabelInput('Email', type='email', required=True), | |
| footer=DivLAligned(*[UkIconLink(icon,href=url) for icon,url in socials]))) | |
| ``` | |
| MonsterUI recommendations: | |
| - Use defaults as much as possible, for example | |
| [`Container`](https://www.fastht.ml/docs/api/pico.html#container) in | |
| monsterui already has defaults for margins | |
| - Use `*T` for button styling consistency, for example | |
| `cls=ButtonT.destructive` for a red delete button or | |
| `cls=ButtonT.primary` for a CTA button | |
| - Use `Label*` functions for forms as much as possible | |
| (e.g. `LabelInput`, `LabelRange`) which creates and links both the | |
| `FormLabel` and user input appropriately to avoid boiler plate. | |
| Flex Layout Elements (such as `DivLAligned` and `DivFullySpaced`) can be | |
| used to create layouts concisely | |
| ``` python | |
| def TeamCard(name, role, location="Remote"): | |
| icons = ("mail", "linkedin", "github") | |
| return Card( | |
| DivLAligned( | |
| DiceBearAvatar(name, h=24, w=24), | |
| Div(H3(name), P(role))), | |
| footer=DivFullySpaced( | |
| DivHStacked(UkIcon("map-pin", height=16), P(location)), | |
| DivHStacked(*(UkIconLink(icon, height=16) for icon in icons)))) | |
| ``` | |
| Forms are styled and spaced for you without significant additional | |
| classes. | |
| ``` python | |
| def MonsterForm(): | |
| relationship = ["Parent",'Sibling', "Friend", "Spouse", "Significant Other", "Relative", "Child", "Other"] | |
| return Div( | |
| DivCentered( | |
| H3("Emergency Contact Form"), | |
| P("Please fill out the form completely", cls=TextPresets.muted_sm)), | |
| Form( | |
| Grid(LabelInput("Name",id='name'),LabelInput("Email", id='email')), | |
| H3("Relationship to patient"), | |
| Grid(*[LabelCheckboxX(o) for o in relationship], cols=4, cls='space-y-3'), | |
| DivCentered(Button("Submit Form", cls=ButtonT.primary))), | |
| cls='space-y-4') | |
| ``` | |
| Text can be styled with markdown automatically with MonsterUI | |
| ```` python | |
| render_md(""" | |
| # My Document | |
| > Important note here | |
| + List item with **bold** | |
| + Another with `code` | |
| ```python | |
| def hello(): | |
| print("world") | |
| ``` | |
| """) | |
| ```` | |
| '<div><h1 class="uk-h1 text-4xl font-bold mt-12 mb-6">My Document</h1>\n<blockquote class="uk-blockquote pl-4 border-l-4 border-primary italic mb-6">\n<p class="text-lg leading-relaxed mb-6">Important note here</p>\n</blockquote>\n<ul class="uk-list uk-list-bullet space-y-2 mb-6 ml-6 text-lg">\n<li class="leading-relaxed">List item with <strong>bold</strong></li>\n<li class="leading-relaxed">Another with <code class="uk-codespan px-1">code</code></li>\n</ul>\n<pre class="bg-base-200 rounded-lg p-4 mb-6"><code class="language-python uk-codespan px-1 uk-codespan px-1 block overflow-x-auto">def hello():\n print("world")\n</code></pre>\n</div>' | |
| Or using semantic HTML: | |
| ``` python | |
| def SemanticText(): | |
| return Card( | |
| H1("MonsterUI's Semantic Text"), | |
| P( | |
| Strong("MonsterUI"), " brings the power of semantic HTML to life with ", | |
| Em("beautiful styling"), " and ", Mark("zero configuration"), "."), | |
| Blockquote( | |
| P("Write semantic HTML in pure Python, get modern styling for free."), | |
| Cite("MonsterUI Team")), | |
| footer=Small("Released February 2025"),) | |
| ``` | |