<project title="MonsterUI Documentation">> MonsterUI is a python library which brings styling to python for FastHTML apps.<api reference><doc title="API List" desc="Complete API Reference"># monsterui Module Documentation

## monsterui.core

- `class ThemeRadii(Enum)`
    Members: none, sm, md, lg


- `class ThemeShadows`

- `class ThemeFont`

- `class Theme(Enum)`
    Selector to choose theme and get all headers needed for app.  Includes frankenui + tailwind + daisyui + highlight.js options
    Members: slate, stone, gray, neutral, red, rose, orange, green, blue, yellow, violet, zinc

    - `headers(self, mode, daisy, highlightjs, katex, radii, shadows, font)`
        Create frankenui and tailwind cdns

    - `local_headers(self, mode, static_dir, daisy, highlightjs, katex, radii, shadows, font)`
        Create headers using local files downloaded from CDNs


## monsterui.daisy

- `class AlertT(Enum)`
    Alert styles from DaisyUI
    Members: info, success, warning, error


- `def Alert(*c, **kwargs)`
    Alert informs users about important events.

- `class StepsT(Enum)`
    Options for Steps
    Members: vertical, horizonal


- `class StepT(Enum)`
    Step styles for LiStep
    Members: primary, secondary, accent, info, success, warning, error, neutral


- `def Steps(*li, **kwargs)`
    Creates a steps container

- `def LiStep(*c, **kwargs)`
    Creates a step list item

- `class LoadingT(Enum)`
    Members: spinner, dots, ring, ball, bars, infinity, xs, sm, md, lg


- `def Loading(cls, htmx_indicator, **kwargs)`
    Creates a loading animation component

- `class ToastHT(Enum)`
    Horizontal position for Toast
    Members: start, center, end


- `class ToastVT(Enum)`
    Vertical position for Toast
    Members: top, middle, bottom


## monsterui.foundations

> Data Structures and Utilties

- `def stringify(o)`
    Converts input types into strings that can be passed to FT components

- `class VEnum(Enum)`
    Members: 

    - `__str__(self)`
    - `__add__(self, other)`
    - `__radd__(self, other)`

## monsterui.franken

- `class TextT(Enum)`
    Text Styles from https://franken-ui.dev/docs/text
    Members: paragraph, lead, meta, gray, italic, xs, sm, lg, xl, light, normal, medium, bold, extrabold, muted, primary, secondary, success, warning, error, info, left, right, center, justify, start, end, top, middle, bottom, truncate, break_, nowrap, underline, highlight


- `class TextPresets(Enum)`
    Common Typography Presets
    Members: muted_sm, muted_lg, bold_sm, bold_lg, md_weight_sm, md_weight_muted


- `def CodeSpan(*c, **kwargs)`
    A CodeSpan with Styling

- `def CodeBlock(*c, **kwargs)`
    CodeBlock with Styling

- `def H1(*c, **kwargs)`
    H1 with styling and appropriate size

- `def H2(*c, **kwargs)`
    H2 with styling and appropriate size

- `def H3(*c, **kwargs)`
    H3 with styling and appropriate size

- `def H4(*c, **kwargs)`
    H4 with styling and appropriate size

- `def H5(*c, **kwargs)`
    H5 with styling and appropriate size

- `def H6(*c, **kwargs)`
    H6 with styling and appropriate size

- `def Subtitle(*c, **kwargs)`
    Styled muted_sm text designed to go under Headings and Titles

- `def Q(*c, **kwargs)`
    Styled quotation mark

- `def Em(*c, **kwargs)`
    Styled emphasis text

- `def Strong(*c, **kwargs)`
    Styled strong text

- `def I(*c, **kwargs)`
    Styled italic text

- `def Small(*c, **kwargs)`
    Styled small text

- `def Mark(*c, **kwargs)`
    Styled highlighted text

- `def Del(*c, **kwargs)`
    Styled deleted text

- `def Ins(*c, **kwargs)`
    Styled inserted text

- `def Sub(*c, **kwargs)`
    Styled subscript text

- `def Sup(*c, **kwargs)`
    Styled superscript text

- `def Blockquote(*c, **kwargs)`
    Blockquote with Styling

- `def Caption(*c, **kwargs)`
    Styled caption text

- `def Cite(*c, **kwargs)`
    Styled citation text

- `def Time(*c, **kwargs)`
    Styled time element

- `def Address(*c, **kwargs)`
    Styled address element

- `def Abbr(*c, **kwargs)`
    Styled abbreviation with dotted underline

- `def Dfn(*c, **kwargs)`
    Styled definition term with italic and medium weight

- `def Kbd(*c, **kwargs)`
    Styled keyboard input with subtle background

- `def Samp(*c, **kwargs)`
    Styled sample output with subtle background

- `def Var(*c, **kwargs)`
    Styled variable with italic monospace

- `def Figure(*c, **kwargs)`
    Styled figure container with card-like appearance

- `def Details(*c, **kwargs)`
    Styled details element

- `def Summary(*c, **kwargs)`
    Styled summary element

- `def Data(*c, **kwargs)`
    Styled data element

- `def Meter(*c, **kwargs)`
    Styled meter element

- `def S(*c, **kwargs)`
    Styled strikethrough text (different semantic meaning from Del)

- `def U(*c, **kwargs)`
    Styled underline (for proper names in Chinese, proper spelling etc)

- `def Output(*c, **kwargs)`
    Styled output element for form results

- `def PicSumImg(h, w, id, grayscale, blur, **kwargs)`
    Creates a placeholder image using https://picsum.photos/

- `class ButtonT(Enum)`
    Options for styling Buttons
    Members: default, ghost, primary, secondary, destructive, text, link, xs, sm, lg, xl, icon


- `def Button(*c, **kwargs)`
    Button with Styling (defaults to `submit` for form submission)

- `class ContainerT(Enum)`
    Max width container sizes from https://franken-ui.dev/docs/container
    Members: xs, sm, lg, xl, expand


- `class BackgroundT(Enum)`
    Members: muted, primary, secondary, default


- `def Container(*c, **kwargs)`
    Div to be used as a container that often wraps large sections or a page of content

- `def Titled(title, *c, **kwargs)`
    Creates a standard page structure for titled page.  Main(Container(title, content))

- `class DividerT(Enum)`
    Divider Styles from https://franken-ui.dev/docs/divider
    Members: icon, sm, vertical


- `def Divider(*c, **kwargs)`
    Divider with default styling and margin

- `def DividerSplit(*c)`
    Creates a simple horizontal line divider with configurable thickness and vertical spacing

- `def Article(*c, **kwargs)`
    A styled article container for blog posts or similar content

- `def ArticleTitle(*c, **kwargs)`
    A title component for use within an Article

- `def ArticleMeta(*c, **kwargs)`
    A metadata component for use within an Article showing things like date, author etc

- `class SectionT(Enum)`
    Section styles from https://franken-ui.dev/docs/section
    Members: default, muted, primary, secondary, xs, sm, lg, xl, remove_vertical


- `def Section(*c, **kwargs)`
    Section with styling and margins

- `def Form(*c, **kwargs)`
    A Form with default spacing between form elements

- `def Fieldset(*c, **kwargs)`
    A Fieldset with default styling

- `def Legend(*c, **kwargs)`
    A Legend with default styling

- `def Input(*c, **kwargs)`
    An Input with default styling

- `def Radio(*c, **kwargs)`
    A Radio with default styling

- `def CheckboxX(*c, **kwargs)`
    A Checkbox with default styling

- `def Range(*c, **kwargs)`
    A Range with default styling

- `def TextArea(*c, **kwargs)`
    A Textarea with default styling

- `def Switch(*c, **kwargs)`
    A Switch with default styling

- `def Upload(*c, **kwargs)`
    A file upload component with default styling

- `def UploadZone(*c, **kwargs)`
    A file drop zone component with default styling

- `def FormLabel(*c, **kwargs)`
    A Label with default styling

- `class LabelT(Enum)`
    Members: primary, secondary, danger


- `def Label(*c, **kwargs)`
    FrankenUI labels, which look like pills

- `def UkFormSection(title, description, *c)`
    A form section with a title, description and optional button

- `def GenericLabelInput(label, lbl_cls, input_cls, container, cls, id, input_fn, **kwargs)`
    `Div(Label,Input)` component with Uk styling injected appropriately. Generally you should higher level API, such as `LabelInput` which is created for you in this library

- `def LabelInput(label, lbl_cls, input_cls, cls, id, **kwargs)`
    A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id

- `def LabelRadio(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
    A FormLabel and Radio pair that provides default spacing and links/names them based on id

- `def LabelCheckboxX(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
    A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id

- `def LabelSelect(*option, **kwargs)`
    A FormLabel and Select pair that provides default spacing and links/names them based on id (usually UkLabelSelect is a better choice)

- `def Options(*c)`
    Helper function to wrap things into `Option`s for use in `Select`

- `def Select(*option, **kwargs)`
    Creates a select dropdown with uk styling and option for adding a search box

- `@delegates(GenericLabelInput, but=['input_fn', 'cls']) def LabelRange(label, lbl_cls, input_cls, cls, id, value, min, max, step, label_range, **kwargs)`
    A FormLabel and Range pair that provides default spacing and links/names them based on id

- `class AT(Enum)`
    Link styles from https://franken-ui.dev/docs/link
    Members: muted, text, reset, primary, classic


- `class ListT(Enum)`
    List styles using Tailwind CSS
    Members: disc, circle, square, decimal, hyphen, bullet, divider, striped


- `def ModalContainer(*c, **kwargs)`
    Creates a modal container that components go in

- `def ModalDialog(*c, **kwargs)`
    Creates a modal dialog

- `def ModalHeader(*c, **kwargs)`
    Creates a modal header

- `def ModalBody(*c, **kwargs)`
    Creates a modal body

- `def ModalFooter(*c, **kwargs)`
    Creates a modal footer

- `def ModalTitle(*c, **kwargs)`
    Creates a modal title

- `def ModalCloseButton(*c, **kwargs)`
    Creates a button that closes a modal with js

- `def Modal(*c, **kwargs)`
    Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you

- `def Placeholder(*c, **kwargs)`
    Creates a placeholder

- `def Progress(*c, **kwargs)`
    Creates a progress bar

- `def UkIcon(icon, height, width, stroke_width, cls, **kwargs)`
    Creates an icon using lucide icons

- `def UkIconLink(icon, height, width, stroke_width, cls, button, **kwargs)`
    Creates an icon link using lucide icons

- `def DiceBearAvatar(seed_name, h, w)`
    Creates an Avatar using https://dicebear.com/

- `def Center(*c, **kwargs)`
    Centers contents both vertically and horizontally by default

- `class FlexT(Enum)`
    Flexbox modifiers using Tailwind CSS
    Members: block, inline, left, center, right, between, around, stretch, top, middle, bottom, row, row_reverse, column, column_reverse, nowrap, wrap, wrap_reverse


- `def Grid(*div, **kwargs)`
    Creates a responsive grid layout with smart defaults based on content

- `def DivFullySpaced(*c, **kwargs)`
    Creates a flex div with it's components having as much space between them as possible

- `def DivCentered(*c, **kwargs)`
    Creates a flex div with it's components centered in it

- `def DivLAligned(*c, **kwargs)`
    Creates a flex div with it's components aligned to the left

- `def DivRAligned(*c, **kwargs)`
    Creates a flex div with it's components aligned to the right

- `def DivVStacked(*c, **kwargs)`
    Creates a flex div with it's components stacked vertically

- `def DivHStacked(*c, **kwargs)`
    Creates a flex div with it's components stacked horizontally

- `class NavT(Enum)`
    Members: default, primary, secondary


- `def NavContainer(*li, **kwargs)`
    Creates a navigation container (useful for creating a sidebar navigation).  A Nav is a list (NavBar is something different)

- `def NavParentLi(*nav_container, **kwargs)`
    Creates a navigation list item with a parent nav for nesting

- `def NavDividerLi(*c, **kwargs)`
    Creates a navigation list item with a divider

- `def NavHeaderLi(*c, **kwargs)`
    Creates a navigation list item with a header

- `def NavSubtitle(*c, **kwargs)`
    Creates a navigation subtitle

- `def NavCloseLi(*c, **kwargs)`
    Creates a navigation list item with a close button

- `class ScrollspyT(Enum)`
    Members: underline, bold


- `def NavBar(*c)`
    Creates a responsive navigation bar with mobile menu support

- `def SliderContainer(*c, **kwargs)`
    Creates a slider container

- `def SliderItems(*c, **kwargs)`
    Creates a slider items container

- `def SliderNav(cls, prev_cls, next_cls, **kwargs)`
    Navigation arrows for Slider component

- `def Slider(*c, **kwargs)`
    Creates a slider with optional navigation arrows

- `def DropDownNavContainer(*li, **kwargs)`
    A Nav that is part of a DropDown

- `def TabContainer(*li, **kwargs)`
    A TabContainer where children will be different tabs

- `class CardT(Enum)`
    Card styles from UIkit
    Members: default, primary, secondary, destructive, hover


- `def CardTitle(*c, **kwargs)`
    Creates a card title

- `def CardHeader(*c, **kwargs)`
    Creates a card header

- `def CardBody(*c, **kwargs)`
    Creates a card body

- `def CardFooter(*c, **kwargs)`
    Creates a card footer

- `def CardContainer(*c, **kwargs)`
    Creates a card container

- `def Card(*c, **kwargs)`
    Creates a Card with a header, body, and footer

- `class TableT(Enum)`
    Members: divider, striped, hover, sm, lg, justify, middle, responsive


- `def Table(*c, **kwargs)`
    Creates a table

- `def TableFromLists(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
    Creates a Table from a list of header data and a list of lists of body data

- `def TableFromDicts(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
    Creates a Table from a list of header data and a list of dicts of body data

- `def apply_classes(html_str, class_map, class_map_mods)`
    Apply classes to html string

- `def render_md(md_content, class_map, class_map_mods)`
    Renders markdown using mistletoe and lxml

- `def get_franken_renderer(img_dir)`
    Create a renderer class with the specified img_dir

- `def ThemePicker(color, radii, shadows, font, mode, cls, custom_themes)`
    Theme picker component with configurable sections

- `def LightboxContainer(*lightboxitem, **kwargs)`
    Lightbox container that will hold `LightboxItems`

- `def LightboxItem(*c, **kwargs)`
    Anchor tag with appropriate structure to go inside a `LightBoxContainer`
</doc></api reference><examples><doc title="Playground" desc="FrankenUI Playground Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Playground Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import *
from monsterui.all import *
from fasthtml.svg import *

app, rt = fast_app(hdrs=Theme.blue.headers())

preset_options = ["Grammatical Standard English", "Summarize for a 2nd grader",
        "Text to command","Q&A","English to other languages","Parse unstructured data",
        "Classification","Natural language to Python","Explain code","Chat","More examples"]

def playground_navbar():
    save_modal = Modal(
        ModalTitle("Save preset"),
        P("This will save the current playground state as a preset which you can access later or share with others.",cls=("mt-1.5", TextPresets.muted_sm)),
        LabelInput("Name",        id="name"), 
        LabelInput("Description", id="description"),
        ModalCloseButton("Save", cls=ButtonT.primary),
        id="save")
    
    share_dd = Div(cls="space-y-6 p-4")(
        H3("Share preset"),
        P("Anyone who has this link and an OpenAI account will be able to view this.", cls=TextPresets.muted_sm),
        Div(Input(value="https://platform.openai.com/playground/p/7bbKYQvsVkNmVb8NGcdUOLae?model=text-davinci-003", readonly=True),
            Button(UkIcon('copy'), cls=(ButtonT.primary, "uk-drop-close",'mt-4'))))

    rnav = (
        Select(*Options(*preset_options), name='preset', optgroup_label="Examples",
                 placeholder='Load a preset', searchable=True, cls='h-9 w-[200px] lg:w-[300px]'),
        Button("Save",         cls=ButtonT.secondary, data_uk_toggle="#save"),save_modal,
        Button("View Code",    cls=ButtonT.secondary),
        Button("Share",        cls=ButtonT.secondary),DropDownNavContainer(share_dd),
        Button(UkIcon(icon="ellipsis"), cls=ButtonT.secondary),
        DropDownNavContainer(
            Li(A("Content filter preferences")),
            NavDividerLi(),
            Li(A("Delete preset", cls="text-destructive")),
        uk_dropdown="mode: click"))
    
    return NavBar(*rnav, brand=H4('Playground'))

rsidebar = NavContainer(
    Select(
        Optgroup(map(Option,("text-davinci-003", "text-curie-001", "text-babbage-001", "text-ada-001")),label='GPT-3'),
        Optgroup(map(Option,("code-davinci-002", "code-cushman-001")),label='Codex'),
        label="Model",
        searchable=True),
    LabelRange(label='Temperature', value='12'),
    LabelRange(label='Maximum Length', value='80'),
    LabelRange(label='Top P', value='40'),
    cls='space-y-6 mt-8')

@rt
def index(): 
    navbar = playground_navbar()
    main_content = Div(
        Div(cls="flex-1")(
            Textarea(cls="uk-textarea h-full p-4", placeholder="Write a tagline for an ice cream shop")),
            cls="flex h-[700px] p-8 w-4/5")
    
    bottom_buttons = Div(
        Button("Submit", cls=ButtonT.primary),
        Button(UkIcon(icon="history"), cls=ButtonT.secondary),
        cls="flex gap-x-2")
    
    return Title("Playground Example"),Div(navbar, Div(cls="flex w-full")(main_content, rsidebar), bottom_buttons)

serve()</doc><doc title="Scrollspy" desc="MonsterUI Scrollspy Example application">"MonsterUI Scrollspy Example application" 

from fasthtml.common import *
from monsterui.all import *
import random

# Using the "slate" theme with Highlight.js enabled
hdrs = Theme.slate.headers(highlightjs=True)
app, rt = fast_app(hdrs=hdrs)

################################
### Example Data and Content ###
################################
products = [
    {"name": "Laptop", "price": "$999"},
    {"name": "Smartphone", "price": "$599"}
]

code_example = """
# Python Code Example
def greet(name):
    return f"Hello, {name}!"

print(greet("World"))
"""
testimonials = [
    {"name": "Alice", "feedback": "Great products and excellent customer service!"},
    {"name": "Bob", "feedback": "Fast shipping and amazing quality!"},
    {"name": "Charlie", "feedback": "Amazing experience! Will definitely buy again."},
    {"name": "Diana", "feedback": "Affordable prices and great variety!"},
    {"name": "Edward", "feedback": "Customer support was very helpful."},
    {"name": "Fiona", "feedback": "Loved the design and quality!"}
]

# Team members
team = [
    {"name": "Isaac Flath", "role": "CEO"},
    {"name": "Benjamin Clavié", "role": "AI Researcher"},
    {"name": "Alexis Gallagher", "role": "ML Engineer"},
    {"name": "Hamel Husain", "role": "Data Scientist"},
    {"name": "Austin Huang", "role": "Software Engineer"},
    {"name": "Benjamin Warner", "role": "Product Manager"},
    {"name": "Jonathan Whitaker", "role": "UX Designer"},
    {"name": "Kerem Turgutlu", "role": "DevOps Engineer"},
    {"name": "Curtis Allan", "role": "DevOps Engineer"},
    {"name": "Audrey Roy Greenfeld", "role": "Security Analyst"},
    {"name": "Nathan Cooper", "role": "Full Stack Developer"},
    {"name": "Jeremy Howard", "role": "CTO"},
    {"name": "Wayde Gilliam", "role": "Cloud Architect"},
    {"name": "Daniel Roy Greenfeld", "role": "Blockchain Expert"},
    {"name": "Tommy Collins", "role": "AI Ethics Researcher"}
]


def ProductCard(p,img_id=1):
    return Card(
        PicSumImg(w=500, height=100, id=img_id),
        DivFullySpaced(H4(p["name"]), P(Strong(p["price"], cls=TextT.sm))), 
        Button("Details", cls=(ButtonT.primary, "w-full")))

def TestimonialCard(t,img_id=1):
    return Card(
        DivLAligned(PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), H4(t["name"])), 
        P(Q((t["feedback"]))))


def TeamCard(m,img_id=1): 
    return Card(
        DivLAligned(
            PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), 
            Div(H4(m["name"]), P(m["role"]))),
        DivRAligned(
            UkIcon('twitter', cls='w-5 h-5'), 
            UkIcon('linkedin', cls='w-5 h-5'),
            UkIcon('github', cls='w-5 h-5'),
            cls=TextT.gray+'space-x-2'
        ),
        cls='p-3')

################################
### Navigation and Scrollspy ###
################################

scrollspy_links = (
                A("Welcome",      href="#welcome-section"),
                A("Products",     href="#products-section"),
                A("Testimonials", href="#testimonials-section"), 
                A("Team",         href="#team-section"),
                A("Code Example", href="#code-section"))
@rt
def index():
    def _Section(*c, **kwargs): return Section(*c, cls='space-y-3 my-48',**kwargs)
    return Container(
        NavBar(
            *scrollspy_links,
            brand=DivLAligned(H3("Scrollspy Demo!"),UkIcon('rocket',height=30,width=30)),
            sticky=True, uk_scrollspy_nav=True,
            scrollspy_cls=ScrollspyT.bold),
        NavContainer(
            *map(Li, scrollspy_links),
            uk_scrollspy_nav=True,
            sticky=True,
            cls=(NavT.primary,'pt-20 px-5 pr-10')),
        Container(
            # Notice the ID of each section corresponds to the `scrollspy_links` dictionary
            # So in scollspy `NavContainer` the `href` of each `Li` is the ID of the section
            DivCentered(
                H1("Welcome to the Store!"), 
                Subtitle("Explore our products and enjoy dynamic code examples."), 
                id="welcome-section"),
            _Section(H2("Products"),
                     Grid(*[ProductCard(p,img_id=i) for i,p in enumerate(products)], cols_lg=2),                   
                     id="products-section"),
            _Section(H2("Testimonials"), 
                     Slider(*[TestimonialCard(t,img_id=i) for i,t in enumerate(testimonials)]),       
                     id="testimonials-section"),
            _Section(H2("Our Team"), 
                     Grid(*[TeamCard(m,img_id=i) for i,m in enumerate(team)], cols_lg=2, cols_max=3),                          
                     id="team-section"),
            _Section(H2("Code Example"), 
                     CodeBlock(code_example, lang="python"),                             
                     id="code-section")), 
            cls=(ContainerT.xl,'uk-container-expand'))

serve()</doc><doc title="Mail" desc="FrankenUI Mail Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Mail Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import *
from monsterui.all import *
from fasthtml.svg import *
import pathlib, json
from datetime import datetime

app, rt = fast_app(hdrs=Theme.blue.headers())

sidebar_group1 = (('home', 'Inbox', '128'), ('file-text', 'Drafts', '9'), (' arrow-up-right', 'Sent', ''),
    ('ban', 'Junk', '23'), ('trash', 'Trash', ''), ('folder', 'Archive', ''))

sidebar_group2 = (('globe','Social','972'),('info','Updates','342'),('messages-square','Forums','128'),
    ('shopping-cart','Shopping','8'),('shopping-bag','Promotions','21'),)

def MailSbLi(icon, title, cnt): 
    return Li(A(DivLAligned(Span(UkIcon(icon)),Span(title),P(cnt, cls=TextPresets.muted_sm)),href='#',  cls='hover:bg-secondary p-4'))

sidebar = NavContainer(
    NavHeaderLi(H3("Email"), cls='p-3'),
    Li(Select(map(Option, ('alicia@example.com','alicia@gmail.com', 'alicia@yahoo.com')))),
    *[MailSbLi(i, t, c) for i, t, c in sidebar_group1],
    Li(Hr()),
    *[MailSbLi(i, t, c) for i, t, c in sidebar_group2],
    cls='mt-3')

mail_data = json.load(open(pathlib.Path('data/mail.json')))

def format_date(date_str):
    date_obj = datetime.fromisoformat(date_str)
    return date_obj.strftime("%Y-%m-%d %I:%M %p")

def MailItem(mail):
    cls_base = 'relative rounded-lg border border-border p-3 text-sm hover:bg-secondary space-y-2'
    cls = f"{cls_base} {'bg-muted' if mail == mail_data[0] else ''} {'tag-unread' if not mail['read'] else 'tag-mail'}"
    
    return Li(
        DivFullySpaced(
            DivLAligned(
                Strong(mail['name']),
                    Span(cls='flex h-2 w-2 rounded-full bg-blue-600') if not mail['read'] else ''),
                Time(format_date(mail['date']), cls='text-xs')),
            Small(mail['subject'], href=f"#mail-{mail['id']}"),
            Div(mail['text'][:100] + '...', cls=TextPresets.muted_sm),
            DivLAligned(
                *[Label(A(label, href='#'), cls='uk-label-primary' if label == 'work' else '') for label in mail['labels']]),
        cls=cls)

def MailList(mails): return Ul(cls='js-filter space-y-2 p-4 pt-0')(*[MailItem(mail) for mail in mails])

def MailContent():
    return Div(cls='flex flex-col',uk_filter="target: .js-filter")(
        Div(cls='flex px-4 py-2 ')(
            H3('Inbox'),
            TabContainer(Li(A("All Mail",href='#', role='button'),cls='uk-active', uk_filter_control="filter: .tag-mail"), 
                         Li(A("Unread",href='#', role='button'),                   uk_filter_control="filter: .tag-unread"), 
                         alt=True, cls='ml-auto max-w-40', )),
        Div(cls='flex flex-1 flex-col')(
            Div(cls='p-4')(
                Div(cls='uk-inline w-full')(
                    Span(cls='uk-form-icon text-muted-foreground')(UkIcon('search')),
                    Input(placeholder='Search'))),
            Div(cls='flex-1 overflow-y-auto max-h-[600px]')(MailList(mail_data))))

def IconNavItem(*d): return [Li(A(UkIcon(o[0],uk_tooltip=o[1]))) for o in d]  
def IconNav(*c,cls=''): return Ul(cls=f'uk-iconnav {cls}')(*c)

def MailDetailView(mail):
    top_icons = [('folder','Archive'), ('ban','Move to junk'), ('trash','Move to trash')]
    reply_icons = [('reply','Reply'), ('reply','Reply all'), ('forward','Forward')]
    dropdown_items = ['Mark as unread', 'Star read', 'Add Label', 'Mute Thread']
    
    return Container(
            DivFullySpaced(
                DivLAligned(
                    DivLAligned(*[UkIcon(o[0],uk_tooltip=o[1]) for o in top_icons]),  
                    Div(UkIcon('clock', uk_tooltip='Snooze'), cls='pl-2'),
                    cls='space-x-2 divide-x divide-border'),
                DivLAligned(
                    *[UkIcon(o[0],uk_tooltip=o[1]) for o in reply_icons],
                    Div(UkIcon('ellipsis-vertical',button=True)),
                    DropDownNavContainer(*map(lambda x: Li(A(x)), dropdown_items)))),
            DivLAligned(
                Span(mail['name'][:2], cls='flex h-10 w-10 items-center justify-center rounded-full bg-muted'),
                Div(Strong(mail['name']),
                    Div(mail['subject']),
                    DivLAligned(P('Reply-To:'), A(mail['email'], href=f"mailto:{mail['email']}"), cls='space-x-1'),
                    P(Time(format_date(mail['date']))),
                    cls='space-y-1'+TextT.sm),
                    cls='m-4 space-x-4'),
            DividerLine(),
            P(mail['text'], cls=TextT.sm +'p-4'),
            DividerLine(),
        Div(TextArea(id='message', placeholder=f"Reply {mail['name']}"),
            DivFullySpaced(
                LabelSwitch('Mute this thread',id='mute'),
                Button('Send', cls=ButtonT.primary)),
            cls='space-y-4'))

@rt
def index():
    return Title("Mail Example"),Container(
        Grid(Div(sidebar, cls='col-span-1'),
             Div(MailContent(), cls='col-span-2'),
             Div(MailDetailView(mail_data[0]), cls='col-span-2'),
             cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5, 
             gap=0, cls='flex-1'),
        cls=('flex', ContainerT.xl))

serve()</doc><doc title="Forms" desc="FrankenUI Forms Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Forms Example built with MonsterUI (original design by ShadCN)"""


from fasthtml.common import *
from monsterui.all import *
from fasthtml.svg import *

app, rt = fast_app(hdrs=Theme.blue.headers())

def HelpText(c): return P(c,cls=TextPresets.muted_sm)

def heading():
    return Div(cls="space-y-5")(
            H2("Settings"),
            Subtitle("Manage your account settings and set e-mail preferences."),
            DividerSplit())


sidebar = NavContainer(
    *map(lambda x: Li(A(x)), ("Profile", "Account", "Appearance", "Notifications", "Display")),
    uk_switcher="connect: #component-nav; animation: uk-animation-fade",
    cls=(NavT.secondary,"space-y-4 p-4 w-1/5"))


def FormSectionDiv(*c, cls='space-y-2', **kwargs): return Div(*c, cls=cls, **kwargs)

def FormLayout(title, subtitle, *content, cls='space-y-3 mt-4'): return Container(Div(H3(title), Subtitle(subtitle), DividerLine(), Form(*content, cls=cls)))

def profile_form():
    content = (FormSectionDiv(
            LabelInput("Username", placeholder='sveltecult', id='username'),
            HelpText("This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.")),
        FormSectionDiv(
            LabelSelect(
                      Option("Select a verified email to display", value="", selected=True, disabled=True),
                     *[Option(o, value=o) for o in ('m@example.com', 'm@yahoo.com', 'm@cloud.com')],  
                     label="Email", id="email"),
            HelpText("You can manage verified email addresses in your email settings.")),
        FormSectionDiv(
            LabelTextArea("Bio", id="bio", placeholder="Tell us a little bit about yourself"),
            HelpText("You can @mention other users and organizations to link to them."),
            P("String must contain at least 4 character(s)", cls="text-destructive")),
        FormSectionDiv(
            FormLabel("URLs"),
            HelpText("Add links to your website, blog, or social media profiles."),
            Input(value="https://www.franken-ui.dev"),
            Input(value="https://github.com/sveltecult/franken-ui"),
            Button("Add URL")),
            Button('Update profile', cls=ButtonT.primary))
    
    return FormLayout('Profile', 'This is how others will see you on the site.', *content)

def account_form():
    content = (
        FormSectionDiv(
            LabelInput("Name", placeholder="Your name", id="name"),
            HelpText("This is the name that will be displayed on your profile and in emails.")),
        FormSectionDiv(
            LabelInput("Date of Birth", type="date", placeholder="Pick a date", id="date_of_birth"),
            HelpText("Your date of birth is used to calculate your age.")),
        FormSectionDiv(
            LabelSelect(*Options("Select a language", "English", "French", "German", "Spanish", "Portuguese", selected_idx=1, disabled_idxs={0}),
                          label='Language', id="language"),
            HelpText("This is the language that will be used in the dashboard.")),
        Button('Update profile', cls=ButtonT.primary))
    
    return FormLayout('Account', 'Update your account settings. Set your preferred language and timezone.', *content)

def appearance_form():
    def theme_item(bg_color, content_bg, text_bg):
        common_content = f"space-y-2 rounded-md {content_bg} p-2 shadow-sm"
        item_row = lambda: Div(cls=f"flex items-center space-x-2 {common_content}")(
            Div(cls=f"h-4 w-4 rounded-full {text_bg}"),
            Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}"))
        
        return Div(cls=f"space-y-2 rounded-sm {bg_color} p-2")(
            Div(cls=common_content)(
                Div(cls=f"h-2 w-[80px] rounded-lg {text_bg}"),
                Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}")),
            item_row(),
            item_row())
    
    common_toggle_cls = "block cursor-pointer items-center rounded-md border-2 border-muted p-1 ring-ring"

    content = (
        FormSectionDiv(
            LabelSelect(*Options('Select a font family', 'Inter', 'Geist', 'Open Sans', selected_idx=2, disabled_idxs={0}),
            label='Font Family', id='font_family'), 
            HelpText("Set the font you want to use in the dashboard.")),
        FormSectionDiv(
            FormLabel("Theme"),
            HelpText("Select the theme for the dashboard."),
            Grid(
                A(id="theme-toggle-light", cls=common_toggle_cls)(theme_item("bg-[#ecedef]", "bg-white", "bg-[#ecedef]")),
                A(id="theme-toggle-dark", cls=f"{common_toggle_cls} bg-popover")(theme_item("bg-slate-950", "bg-slate-800", "bg-slate-400")),
                cols_max=2,cls=('max-w-md','gap-8'))),
            Button('Update preferences', cls=ButtonT.primary))
    
    return FormLayout('Appearance', 'Customize the appearance of the app. Automatically switch between day and night themes.', *content)


notification_items = [
    {"title": "Communication emails", "description": "Receive emails about your account activity.", "checked": False, "disabled": False},
    {"title": "Marketing emails", "description": "Receive emails about new products, features, and more.", "checked": False, "disabled": False},
    {"title": "Social emails", "description": "Receive emails for friend requests, follows, and more.", "checked": True, "disabled": False},
    {"title": "Security emails", "description": "Receive emails about your account activity and security.", "checked": True, "disabled": True}]

def notifications_form():
    def RadioLabel(label): return DivLAligned(Radio(name="notification", checked=(label=="Nothing")), FormLabel(label))

    def NotificationCard(item):
        return Card(
            Div(cls="space-y-0.5")(
                FormLabel(Strong(item['title'], cls=TextT.sm),
                HelpText(item['description']))))
    content = Div(
        FormSectionDiv(
            FormLabel("Notify me about"),
            *map(RadioLabel, ["All new messages", "Direct messages and mentions", "Nothing"])),
        Div(
            H4("Email Notifications", cls="mb-4"),
            Grid(*map(NotificationCard, notification_items), cols=1)),
            LabelCheckboxX("Use different settings for my mobile devices", id="notification_mobile"),
            HelpText("You can manage your mobile notifications in the mobile settings page."),
            Button('Update notifications', cls=ButtonT.primary))
    
    return FormLayout('Notifications', 'Configure how you receive notifications.', *content)

def display_form():
    content = (
        Div(cls="space-y-2")(
            Div(cls="mb-4")(
                H5("Sidebar"),
                Subtitle("Select the items you want to display in the sidebar.")),
            *[Div(CheckboxX(id=f"display_{i}", checked=i in [0, 1, 2]),FormLabel(label))
              for i, label in enumerate(["Recents", "Home", "Applications", "Desktop", "Downloads", "Documents"])]),
            Button('Update display', cls=ButtonT.primary))
    return FormLayout('Display', 'Turn items on or off to control what\'s displayed in the app.', *content)

@rt
def index():
    return Title("Forms Example"),Container(
        heading(),
        Div(cls="flex gap-x-12")(
            sidebar,
                Ul(id="component-nav", cls="uk-switcher max-w-2xl")(
                    Li(cls="uk-active")(profile_form(),
                    *map(Li, [account_form(), appearance_form(), notifications_form(), display_form()])))))

serve()</doc><doc title="Tasks" desc="FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import *
from monsterui.all import *
from fasthtml.svg import *
import json

app, rt = fast_app(hdrs=Theme.blue.headers())

def LAlignedCheckTxt(txt): return DivLAligned(UkIcon(icon='check'), P(txt, cls=TextPresets.muted_sm))

with open('data/status_list.json', 'r') as f: data     = json.load(f)
with open('data/statuses.json',    'r') as f: statuses = json.load(f)

def _create_tbl_data(d):
    return {'Done': d['selected'], 'Task': d['id'], 'Title': d['title'], 
            'Status'  : d['status'], 'Priority': d['priority'] }
    
data = [_create_tbl_data(d)  for d in data]
page_size = 15
current_page = 0
paginated_data = data[current_page*page_size:(current_page+1)*page_size]

priority_dd = [{'priority': "low", 'count': 36 }, {'priority': "medium", 'count': 33 }, {'priority': "high", 'count': 31 }]

status_dd = [{'status': "backlog", 'count': 21 },{'status': "todo", 'count': 21 },{'status': "progress", 'count': 20 },{'status': "done",'count': 19 },{'status': "cancelled", 'count': 19 }]

def create_hotkey_li(hotkey): return NavCloseLi(A(DivFullySpaced(hotkey[0], Span(hotkey[1], cls=TextPresets.muted_sm))))

hotkeys_a = (('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team',''))
hotkeys_b = (('Logout',''), )

avatar_opts = DropDownNavContainer(
    NavHeaderLi(P('sveltecult'),NavSubtitle('leader@sveltecult.com')),
    NavDividerLi(),
    *map(create_hotkey_li, hotkeys_a),
    NavDividerLi(),
    *map(create_hotkey_li, hotkeys_b),)

def CreateTaskModal():
    return Modal(
        Div(cls='p-6')(
            ModalTitle('Create Task'),
            P('Fill out the information below to create a new task', cls=TextPresets.muted_sm),
            Br(),
            Form(cls='space-y-6')(
                Grid(Div(Select(*map(Option,('Documentation', 'Bug', 'Feature')), label='Task Type', id='task_type')),
                     Div(Select(*map(Option,('In Progress', 'Backlog', 'Todo', 'Cancelled', 'Done')), label='Status', id='task_status')),
                     Div(Select(*map(Option, ('Low', 'Medium', 'High')), label='Priority', id='task_priority'))),
                TextArea(label='Title', placeholder='Please describe the task that needs to be completed'),
                DivRAligned(
                    ModalCloseButton('Cancel', cls=ButtonT.ghost),
                    ModalCloseButton('Submit', cls=ButtonT.primary),
                    cls='space-x-5'))),
        id='TaskForm')

page_heading = DivFullySpaced(cls='space-y-2')(
            Div(cls='space-y-2')(
                H2('Welcome back!'),P("Here's a list of your tasks for this month!", cls=TextPresets.muted_sm)),
            Div(DiceBearAvatar("sveltcult",8,8),avatar_opts))

table_controls =(Input(cls='w-[250px]',placeholder='Filter task'),
     Button("Status"),
     DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(P(a['status']), P(a['count'])),cls='capitalize') for a in status_dd])), 
     Button("Priority"),
     DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(LAlignedCheckTxt(a['priority']), a['count']),cls='capitalize') for a in priority_dd])),
     Button("View"),
     DropDownNavContainer(map(NavCloseLi,[A(LAlignedCheckTxt(o)) for o in ['Title','Status','Priority']])),
     Button('Create Task',cls=(ButtonT.primary, TextPresets.bold_sm), data_uk_toggle="target: #TaskForm"))

def task_dropdown():
    return Div(Button(UkIcon('ellipsis')),
               DropDownNavContainer(
                   map(NavCloseLi,[
                       *map(A,('Edit', 'Make a copy', 'Favorite')),
                        A(DivFullySpaced(*[P(o, cls=TextPresets.muted_sm) for o in ('Delete', '⌘⌫')]))])))
def header_render(col):
    match col:
        case "Done":    return Th(CheckboxX(), shrink=True)
        case 'Actions': return Th("",          shrink=True)
        case _:         return Th(col,         expand=True)

def cell_render(col, val):
    def _Td(*args,cls='', **kwargs): return Td(*args, cls=f'p-2 {cls}',**kwargs)
    match col:
        case "Done": return _Td(shrink=True)(CheckboxX(selected=val))
        case "Task":  return _Td(val, cls='uk-visible@s')  # Hide on small screens
        case "Title": return _Td(val, cls='font-medium', expand=True)
        case "Status" | "Priority": return _Td(cls='uk-visible@m uk-text-nowrap capitalize')(Span(val))
        case "Actions": return _Td(task_dropdown(), shrink=True)
        case _: raise ValueError(f"Unknown column: {col}")

task_columns = ["Done", 'Task', 'Title', 'Status', 'Priority', 'Actions']

tasks_table = Div(cls='mt-4')(
    TableFromDicts(
        header_data=task_columns,
        body_data=paginated_data,
        body_cell_render=cell_render,
        header_cell_render=header_render,
        sortable=True,
        cls=(TableT.responsive, TableT.sm, TableT.divider)))


def footer():
    total_pages = (len(data) + page_size - 1) // page_size
    return DivFullySpaced(
        Div('1 of 100 row(s) selected.', cls=TextPresets.muted_sm),
        DivLAligned(
            DivCentered(f'Page {current_page + 1} of {total_pages}', cls=TextT.sm),
            DivLAligned(*[UkIconLink(icon=i,  button=True) for i in ('chevrons-left', 'chevron-left', 'chevron-right', 'chevrons-right')])))

tasks_ui = Div(DivFullySpaced(DivLAligned(table_controls), cls='mt-8'), tasks_table, footer())

@rt
def index(): return Container(page_heading, tasks_ui, CreateTaskModal())

serve()</doc><doc title="Cards" desc="FrankenUI Cards Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Cards Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import *
from fasthtml.components import Uk_input_tag
from fasthtml.svg import *
from monsterui.all import *
import calendar
from datetime import datetime

app, rt = fast_app(hdrs=Theme.blue.headers())

CreateAccount = Card(
    Grid(Button(DivLAligned(UkIcon('github'),Div('Github'))),Button('Google')),
            DividerSplit("OR CONTINUE WITH", text_cls=TextPresets.muted_sm),
            LabelInput('Email',    id='email',   placeholder='m@example.com'),
            LabelInput('Password', id='password',placeholder='Password', type='Password'),
            header=(H3('Create an Account'),Subtitle('Enter your email below to create your account')),
            footer=Button('Create Account',cls=(ButtonT.primary,'w-full')))

PaypalSVG_data = "M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z"
AppleSVG_data = "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
Card1Svg  = Svg(viewBox="0 0 24 24", fill="none", stroke="currentColor", stroke_linecap="round", stroke_linejoin="round", stroke_width="2", cls="h-6 w-6 mr-1")(Rect(width="20", height="14", x="2", y="5", rx="2"),Path(d="M2 10h20"))
PaypalSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=PaypalSVG_data, fill="currentColor")),
AppleSvg  = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=AppleSVG_data, fill="currentColor"))

PaymentMethod = Card(
    Grid(Button(DivCentered(Card1Svg,  "Card"),   cls='h-20 border-2 border-primary'),
         Button(DivCentered(PaypalSvg, "PayPal"), cls='h-20'),
         Button(DivCentered(AppleSvg,  "Apple"),  cls='h-20')),
    Form(LabelInput('Name',        id='name',        placeholder='John Doe'),
         LabelInput('Card Number', id='card_number', placeholder='m@example.com'),
         Grid(LabelSelect(*Options(*calendar.month_name[1:],selected_idx=0),label='Expires',id='expire_month'),
              LabelSelect(*Options(*range(2024,2030),selected_idx=0),       label='Year',   id='expire_year'),
              LabelInput('CVV', id='cvv',placeholder='CVV', cls='mt-0'))),
        header=(H3('Payment Method'),Subtitle('Add a new payment method to your account.')))

area_opts = ('Team','Billing','Account','Deployment','Support')
severity_opts = ('Severity 1 (Highest)', 'Severity 2', 'Severity 3', 'Severity 4 (Lowest)')
ReportIssue = Card(
    Grid(Div(LabelSelect(*Options(*area_opts),    label='Area',    id='area')),
         Div(LabelSelect(*Options(*severity_opts),label='Severity',id='area'))),
    LabelInput(    label='Subject',     id='subject',    placeholder='I need help with'),
    LabelTextArea( label='Description', id='description',placeholder='Please include all information relevant to your issue'),
    Div(FormLabel('Tags', fr='#tags'),
        Uk_input_tag(name="Tags",state="danger", value="Spam,Invalid", uk_cloak=True, id='tags')),
    header=(H3('Report Issue'),Subtitle('What area are you having problems with?')),
    footer = DivFullySpaced(Button('Cancel'), Button(cls=ButtonT.primary)('Submit')))

monster_desc ="Python-first beautifully designed components because you deserve to focus on features that matter and your app deserves to be beautiful from day one."
MonsterUI = Card(H4("Monster UI"),
              Subtitle(monster_desc),
              DivLAligned(
                    Div("Python"),
                    DivLAligned(UkIcon('star'),Div("20k"), cls='space-x-1'),
                    Div(datetime.now().strftime("%B %d, %Y")),
                    cls=('space-x-4',TextPresets.muted_sm)))

def CookieTableRow(heading, description, active=False):
    return Tr(Td(H5(heading)),
              Td(P(description, cls=TextPresets.muted_sm)),
              Td(Switch(checked=active)))

CookieSettings = Card(
    Table(Tbody(
        CookieTableRow('Strictly Necessary', 'These cookies are essential in order to use the website and use its features.', True),
        CookieTableRow('Functional Cookies', 'These cookies allow the website to provide personalized functionality.'),
        CookieTableRow('Performance Cookies', 'These cookies help to improve the performance of the website.'))),
    header=(H4('Cookie Settings'),Subtitle('Manage your cookie settings here.')),
    footer=Button('Save Preferences', cls=(ButtonT.primary, 'w-full')))

team_members = [("Sofia Davis", "m@example.com", "Owner"),("Jackson Lee", "p@example.com", "Member"),]
def TeamMemberRow(name, email, role):
    return DivFullySpaced(
        DivLAligned(
            DiceBearAvatar(name, 10,10),
            Div(P(name, cls=(TextT.sm, TextT.medium)),
                P(email, cls=TextPresets.muted_sm))),
        Button(role, UkIcon('chevron-down', cls='ml-4')),
        DropDownNavContainer(map(NavCloseLi, [
            A(Div('Viewer',    NavSubtitle('Can view and comment.'))),
            A(Div('Developer', NavSubtitle('Can view, comment and edit.'))),
            A(Div('Billing',   NavSubtitle('Can view, comment and manage billing.'))),
            A(Div('Owner',     NavSubtitle('Admin-level access to all resources.')))])))

TeamMembers = Card(*[TeamMemberRow(*member) for member in team_members],
        header = (H4('Team Members'),Subtitle('Invite your team members to collaborate.')))

access_roles = ("Read and write access", "Read-only access")
team_members = [("Olivia Martin", "m@example.com", "Read and write access"),
                ("Isabella Nguyen", "b@example.com", "Read-only access"),
                ("Sofia Davis", "p@example.com", "Read-only access")]

def TeamMemberRow(name, email, role):
    return DivFullySpaced(
        DivLAligned(DiceBearAvatar(name, 10,10),
                    Div(P(name, cls=(TextT.sm, TextT.medium)),
                        P(email, cls=TextPresets.muted_sm))),
        Select(*Options(*access_roles, selected_idx=access_roles.index(role))))

ShareDocument = Card(
    DivLAligned(Input(value='http://example.com/link/to/document'),Button('Copy link', cls='whitespace-nowrap')),
    Divider(),
    H4('People with access', cls=TextPresets.bold_sm),
    *[TeamMemberRow(*member) for member in team_members],
    header = (H4('Share this document'),Subtitle('Anyone with the link can view this document.')))

DateCard = Card(Button('Jan 20, 2024 - Feb 09, 2024'))

section_content =(('bell','Everything',"Email digest, mentions & all activity."), 
                  ('user',"Available","Only mentions and comments"),
                  ('ban', "Ignoring","Turn of all notifications"))

def NotificationRow(icon, name, desc):
    return Li(cls='-mx-1')(A(DivLAligned(UkIcon(icon),Div(P(name),P(desc, cls=TextPresets.muted_sm)))))

Notifications = Card(
    NavContainer(
        *[NotificationRow(*row) for row in section_content],
        cls=NavT.secondary),
    header = (H4('Notification'),Subtitle('Choose what you want to be notified about.')),
    body_cls='pt-0')

TeamCard = Card(
    DivLAligned(
        DiceBearAvatar("Isaac Flath", h=24, w=24),
        Div(H3("Isaac Flath"), P("Library Creator"))),
    footer=DivFullySpaced(
        DivHStacked(UkIcon("map-pin", height=16), P("Alexandria, VA")),
        DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github")))),
    cls=CardT.hover)

@rt
def index():
    return Title("Cards Example"),Container(Grid(
            *map(Div,(
                      Div(PaymentMethod,CreateAccount, TeamCard, cls='space-y-4'),
                      Div(TeamMembers, ShareDocument,DateCard,Notifications, cls='space-y-4'),
                      Div(ReportIssue,MonsterUI,CookieSettings, cls='space-y-4'))),
         cols_md=1, cols_lg=2, cols_xl=3))

serve()</doc><doc title="Dashboard" desc="FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import * # Bring in all of fasthtml
import fasthtml.common as fh # Used to get unstyled components
from monsterui.all import * # Bring in all of monsterui, including shadowing fasthtml components with styled components
from fasthtml.svg import *
import numpy as np
import plotly.express as px
import pandas as pd
import numpy as np

app, rt = fast_app(hdrs=Theme.blue.headers())

def generate_chart(num_points=30):
    df = pd.DataFrame({
        'Date': pd.date_range('2024-01-01', periods=num_points),
        'Revenue': np.random.normal(100, 10, num_points).cumsum(),
        'Users': np.random.normal(80, 8, num_points).cumsum(), 
        'Growth': np.random.normal(60, 6, num_points).cumsum()})
    
    fig = px.line(df, x='Date', y=['Revenue', 'Users', 'Growth'],  template='plotly_white', line_shape='spline')
    
    fig.update_traces(mode='lines+markers')
    fig.update_layout(
        margin=dict(l=20, r=20, t=20, b=20), hovermode='x unified',
        showlegend=True, legend=dict(orientation='h', yanchor='bottom', y=1.02,  xanchor='right', x=1),
        plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
        xaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'),
        yaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'))
    
    return fig.to_html(include_plotlyjs=True, full_html=False, config={'displayModeBar': False})

def InfoCard(title, value, change): return Card(H3(value),P(change, cls=TextPresets.muted_sm), header = H4(title))

rev = InfoCard("Total Revenue", "$45,231.89", "+20.1% from last month")
sub = InfoCard("Subscriptions", "+2350", "+180.1% from last month")
sal = InfoCard("Sales", "+12,234", "+19% from last month")
act = InfoCard("Active Now", "+573", "+201 since last hour")

info_card_data = [("Total Revenue", "$45,231.89", "+20.1% from last month"),
                   ("Subscriptions", "+2350", "+180.1% from last month"),
                   ("Sales", "+12,234", "+19% from last month"),
                   ("Active Now", "+573", "+201 since last hour")]

top_info_row = Grid(*[InfoCard(*row) for row in info_card_data])

def AvatarItem(name, email, amount):
    return DivFullySpaced(
        DivLAligned(
            DiceBearAvatar(name, 9,9),
            Div(Strong(name, cls=TextT.sm), 
                Address(A(email,href=f'mailto:{email}')))),
        fh.Data(amount, cls="ml-auto font-medium", value=amount[2:]))

recent_sales = Card(
    Div(cls="space-y-8")(
        *[AvatarItem(n,e,d) for (n,e,d) in (
            ("Olivia Martin",   "olivia.martin@email.com",   "+$1,999.00"),
            ("Jackson Lee",     "jackson.lee@email.com",     "+$39.00"),
            ("Isabella Nguyen", "isabella.nguyen@email.com", "+$299.00"),
            ("William Kim",     "will@email.com",            "+$99.00"),
            ("Sofia Davis",     "sofia.davis@email.com",     "+$39.00"))]),
    header=Div(H3("Recent Sales"),Subtitle("You made 265 sales this month.")),
    cls='col-span-3')

teams = [["Alicia Koch"],['Acme Inc', 'Monster Inc.'],['Create a Team']]

opt_hdrs = ["Personal", "Team", ""]

team_dropdown = Select(
    Optgroup(Option(A("Alicia Koch")), label="Personal Account"),
    Optgroup(Option(A("Acme Inc")), Option(A("Monster Inc.")), label="Teams"),
    Option(A("Create a Team")),
    cls='flex items-center')

hotkeys = [('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team', ''), ('Logout', '')]

def NavSpacedLi(t,s): return NavCloseLi(A(DivFullySpaced(P(t),P(s,cls=TextPresets.muted_sm))))

avatar_dropdown = Div(
      DiceBearAvatar('Alicia Koch',8,8),
      DropDownNavContainer(
          NavHeaderLi('sveltecult',NavSubtitle("leader@sveltecult.com")),
          *[NavSpacedLi(*hk) for hk in hotkeys],))

top_nav = NavBar(
    team_dropdown, *map(A, ["Overview", "Customers", "Products", "Settings"]),
    brand=DivLAligned(avatar_dropdown, Input(placeholder='Search')))

@rt
def index():
    return Title("Dashboard Example"), Container(
        top_nav,
        H2('Dashboard'),
        TabContainer(
            Li(A("Overview"),cls='uk-active'),
            *map(lambda x: Li(A(x)), ["Analytics", "Reports", "Notifications"]),
            alt=True),
        top_info_row,
        Grid(
            Card(Safe(generate_chart(100)), cls='col-span-4'),
            recent_sales,
            gap=4,cols_xl=7,cols_lg=7,cols_md=1,cols_sm=1,cols_xs=1),
        cls=('space-y-4', ContainerT.xl))

serve()</doc><doc title="Ticket" desc="MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components">"""MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components"""
from fasthtml.common import *
from monsterui.all import *
from datetime import datetime

app, rt = fast_app(hdrs=Theme.blue.headers(daisy=True))

def TicketSteps(step):
    return Steps(
        LiStep("Submitted", data_content="📝",
               cls=StepT.success if step > 0 else StepT.primary if step == 0 else StepT.neutral),
        LiStep("In Review", data_content="🔎",
               cls=StepT.success if step > 1 else StepT.primary if step == 1 else StepT.neutral),
        LiStep("Processing", data_content="⚙️",
               cls=StepT.success if step > 2 else StepT.primary if step == 2 else StepT.neutral),
        LiStep("Resolved", data_content="✅",
               cls=StepT.success if step > 3 else StepT.primary if step == 3 else StepT.neutral),
        cls="w-full")

def StatusBadge(status):
    styles = {'high': AlertT.error, 'medium': AlertT.warning,'low': AlertT.info}
    alert_type = styles.get(status, AlertT.info)
    return Alert(f"{status.title()} Priority", cls=(alert_type,"w-32 shadow-sm"))

def TicketCard(id, title, description, status, step, department):
    return Card(
        CardHeader(
            DivFullySpaced(
                Div(H3(f"#{id}", cls=TextT.muted), 
                    H4(title), 
                    cls='space-y-2'),
                StatusBadge(status))),
        CardBody(
            P(description, cls=(TextT.muted, "mb-6")),
            DividerSplit(cls="my-6"),
            TicketSteps(step),
            DividerSplit(cls="my-6"), 
            DivFullySpaced(
                Div(Strong("Department"),
                    P(department),
                    cls=('space-y-3', TextPresets.muted_sm)),
                Div(Strong("Last Updated"),
                    P(Time(datetime.now().strftime('%b %d, %H:%M'))),
                    cls=('space-y-3', TextPresets.muted_sm)),
                Button("View Details", cls=ButtonT.primary),
                cls='mt-6')),
        cls=CardT.hover)

def NewTicketModal():
    return Modal(
        ModalHeader(H3("Create New Support Ticket")),
        ModalBody(
            Alert(
                DivLAligned(UkIcon("info"), Span("Please provide as much detail as possible to help us assist you quickly.")),
                cls=(AlertT.info,"mb-4")),
            Form(
                Grid(LabelInput("Title", id="title", placeholder="Brief description of your issue"),
                     LabelSelect(Options("IT Support", "HR", "Facilities", "Finance"), label="Department", id="department")),
                LabelSelect(Options("Low", "Medium", "High"), label="Priority Level",  id="priority"),
                LabelTextArea("Description", id="description", placeholder="Please provide detailed information about your issue"),
                DivRAligned(
                    Button("Cancel", cls=ButtonT.ghost, data_uk_toggle="target: #new-ticket"),
                    Button(Loading(cls=LoadingT.spinner), "Submit Ticket", cls=ButtonT.primary, data_uk_toggle="target: #success-toast; target: #new-ticket")),
                cls='space-y-8')),
            id="new-ticket")

@rt
def index():
    tickets = [
        {'id': "TK-1001", 'title': "Cloud Storage Access Error", 
         'description': "Unable to access cloud storage with persistent authorization errors. Multiple users affected across marketing department.",
         'status': 'high', 'step': 2, 'department': 'IT Support'},
        {'id': "TK-1002", 'title': "Email Integration Issue", 
         'description': "Exchange server not syncing with mobile devices. Affecting external client communications.",
         'status': 'medium', 'step': 1, 'department': 'IT Support'},
        {'id': "TK-1003", 'title': "Office Equipment Setup", 
         'description': "New department printer needs configuration and network integration. Required for upcoming client presentation.",
         'status': 'low', 'step': 0, 'department': 'Facilities'}
    ]

    return Title("Help Desk Dashboard"), Container(
        Section(
            DivFullySpaced(
                H2("Active Tickets"),
                Button(UkIcon("plus-circle", cls="mr-2"), "New Ticket", cls=ButtonT.primary, data_uk_toggle="target: #new-ticket"),
                cls='mb-8'),
            Grid(*[TicketCard(**ticket) for ticket in tickets], cols=1),
            cls="my-6"),
        NewTicketModal(),
        Toast(DivLAligned(UkIcon('check-circle', cls='mr-2'), "Ticket submitted successfully! Our team will review it shortly."), id="success-toast", alert_cls=AlertT.success, cls=(ToastHT.end, ToastVT.bottom)),
        Loading(htmx_indicator=True, type=LoadingT.dots, cls="fixed top-0 right-0 m-4"),
        cls="mx-auto max-w-7xl"
    )   

serve()</doc><doc title="Auth" desc="FrankenUI Auth Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Auth Example built with MonsterUI (original design by ShadCN)"""

from fasthtml.common import *
from monsterui.all import *
from fasthtml.svg import *

app, rt = fast_app(hdrs=Theme.blue.headers())

@rt
def index():    
    left = Div(cls="col-span-1 hidden flex-col justify-between bg-zinc-900 p-8 text-white lg:flex")(
        Div(cls=(TextT.bold))("Acme Inc"),
        Blockquote(cls="space-y-2")(
            P(cls=TextT.lg)('"This library has saved me countless hours of work and helped me deliver stunning designs to my clients faster than ever before."'),
            Footer(cls=TextT.sm)("Sofia Davis")))

    right = Div(cls="col-span-2 flex flex-col p-8 lg:col-span-1")(
        DivRAligned(Button("Login", cls=ButtonT.ghost)),
        DivCentered(cls='flex-1')(
            Container(
                DivVStacked(
                    H3("Create an account"),
                    Small("Enter your email below to create your account", cls=TextT.muted)),
                Form(
                    Input(placeholder="name@example.com"),
                    Button(Span(cls="mr-2", uk_spinner="ratio: 0.54"), "Sign in with Email", cls=(ButtonT.primary, "w-full"), disabled=True),
                    DividerSplit(Small("Or continue with"),cls=TextT.muted),
                    Button(UkIcon('github',cls='mr-2'), "Github", cls=(ButtonT.default, "w-full")),
                    cls='space-y-6'),
                DivVStacked(Small(
                        "By clicking continue, you agree to our ",
                        A(cls=AT.muted, href="#demo")("Terms of Service")," and ",
                        A(cls=AT.muted, href="#demo")("Privacy Policy"),".",
                        cls=(TextT.muted,"text-center"))),
                cls="space-y-6")))
    
    return Title("Auth Example"),Grid(left,right,cols=2, gap=0,cls='h-screen')


serve()</doc><doc title="Music" desc="FrankenUI Music Example build with MonsterUI (Original design by ShadCN)">"""FrankenUI Music Example build with MonsterUI (Original design by ShadCN)"""

from fasthtml.common import *
from monsterui.all import *
 
app, rt = fast_app(hdrs=Theme.blue.headers())

def MusicLi(t,hk=''): return Li(A(DivFullySpaced(t,P(hk,cls=TextPresets.muted_sm))))

music_items = [("About Music", ""   ),
               ("Preferences", "⌘"  ),
               ("Hide Music" , "⌘H" ),
               ("Hide Others", "⇧⌘H"),
               ("Quit Music" , "⌘Q" )]

file_dd_items = [("New",                   ""),
                 ("Open Stream URL",       "⌘U"),
                 ("Close Window",          "⌘W"),
                 ("Library",               ""),
                 ("Import",                "⌘O"),
                 ("Burn Playlist to Disc", ""),
                 ("Show in Finder",        "⇧⌘R"),
                 ("Convert",               ""),
                 ("Page Setup",            "Print")]

edit_actions = [("Undo",         "⌘Z"),
                ("Redo",         "⇧⌘Z"),
                ("Cut",          "⌘X"),
                ("Copy",         "⌘C"),
                ("Paste",        "⌘V"),
                ("Select All",   "⌘A"),
                ("Deselect All", "⇧⌘A")]

view_dd_data = ["Show Playing Next", "Show Lyrics", "Show Status Bar", "Hide Sidebar", "Enter Full Screen"]


music_headers = NavBar(
    Button("Music", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("Music"),NavContainer(map(lambda x: MusicLi(*x), music_items)))),
    Button("File", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("File"), NavContainer(map(lambda x: MusicLi(*x), file_dd_items)))),
    Button("Edit", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("Edit")),NavContainer(
            *map(lambda x: MusicLi(*x), edit_actions),
            Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
            Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe")))))),
    Button("View", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("View"),NavContainer(map(lambda x: MusicLi(x), view_dd_data)))),
    )
    



# music_headers = NavBarContainer(
#             NavBarLSide(
#                 NavBarNav(
#                 Li(A("Music"),NavBarNavContainer(map(lambda x: MusicLi(*x), music_items))),
#                 Li(A("File"), NavBarNavContainer(map(lambda x: MusicLi(*x), file_dd_items))),
#                 Li(A("Edit")),
#                     NavBarNavContainer(
#                         *map(lambda x: MusicLi(*x), edit_actions),
#                         Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
#                         Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe"))))),
#                 Li(A("View"),
#                 NavBarNavContainer(map(lambda x: MusicLi(x), view_dd_data))),
#                 Li(A("Account"),
#                     NavBarNavContainer(
#                         NavHeaderLi("Switch Account"),
#                         *map(MusicLi, ("Andy", "Benoit", "Luis", "Manage Family", "Add Account")))))))


def Album(title,artist):
    img_url = 'https://ucarecdn.com/e5607eaf-2b2a-43b9-ada9-330824b6afd7/music1.webp'
    return Div(
        Div(cls="overflow-hidden rounded-md")(Img(cls="transition-transform duration-200 hover:scale-105", src=img_url)),
        Div(cls='space-y-1')(Strong(title),P(artist,cls=TextT.muted)))
        
listen_now_albums = (("Roar", "Catty Perry"), ("Feline on a Prayer", "Cat Jovi"),("Fur Elise", "Ludwig van Beethovpurr"),("Purrple Rain", "Prince's Cat"))

made_for_you_albums = [("Like a Feline",         "Catdonna"),
                       ("Livin' La Vida Purrda", "Ricky Catin"),
                       ("Meow Meow Rocket",      "Elton Cat"),
                       ("Rolling in the Purr",   "Catdelle"),
                       ("Purrs of Silence",      "Cat Garfunkel"),
                       ("Meow Me Maybe",         "Carly Rae Purrsen"),]

music_content = (Div(H3("Listen Now"), cls="mt-6 space-y-1"),
                    Subtitle("Top picks for you. Updated daily."),
                    DividerLine(),
                    Grid(*[Album(t,a) for t,a in listen_now_albums], cls='gap-8'),
                    Div(H3("Made for You"), cls="mt-6 space-y-1"),
                    Subtitle("Your personal playlists. Updated daily."),
                    DividerLine(),
                    Grid(*[Album(t,a) for t,a in made_for_you_albums], cols_xl=6))

tabs = TabContainer(
    Li(A('Music',    href='#'),    cls='uk-active'),
    Li(A('Podcasts', href='#')),
    Li(A('Live', cls='opacity-50'), cls='uk-disabled'),
    uk_switcher='connect: #component-nav; animation: uk-animation-fade',
    alt=True)

def podcast_tab():
    return Div(
        Div(cls='space-y-3 mt-6')(
            H3("New Episodes"),
            Subtitle("Your favorite podcasts. Updated daily.")),
        Div(cls="uk-placeholder flex h-[450px] items-center justify-center rounded-md mt-4",uk_placeholder=True)(
            DivVStacked(cls="space-y-6")(
                UkIcon("microphone", 3),
                H4("No episodes added"),
                Subtitle("You have not added any podcasts. Add one below."),
                Button("Add Podcast", cls=ButtonT.primary))))

discoved_data =  [("play-circle","Listen Now"), ("binoculars", "Browse"), ("rss","Radio")]
library_data =   [("play-circle", "Playlists"), ("music", "Songs"), ("user", "Made for You"), ("users", "Artists"), ("bookmark", "Albums")]
playlists_data = [("library","Recently Added"), ("library","Recently Played")]

def MusicSidebarLi(icon, text): return Li(A(DivLAligned(UkIcon(icon), P(text))))
sidebar = NavContainer(
    NavHeaderLi(H3("Discover")), *[MusicSidebarLi(*o) for o in discoved_data],
    NavHeaderLi(H3("Library")),  *[MusicSidebarLi(*o) for o in library_data],
    NavHeaderLi(H3("Playlists")),*[MusicSidebarLi(*o) for o in playlists_data],
    cls=(NavT.primary,'space-y-3','pl-8'))

@rt
def index():
    return Title("Music Example"),Container(music_headers, DividerSplit(),
        Grid(sidebar,
            Div(cls="col-span-4 border-l border-border")(
                Div(cls="px-8 py-6")(
                    DivFullySpaced(
                        Div(cls="max-w-80")(tabs),
                        Button(cls=ButtonT.primary)(DivLAligned(UkIcon('circle-plus')),Div("Add music"))),
                    Ul(id="component-nav", cls="uk-switcher")(
                        Li(*music_content),
                        Li(podcast_tab())))),
            cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5))

serve()</doc></examples><optional><doc title="Button | Link" desc="Buttons &amp; Links API Reference"># Buttons & Links API Reference

See Source

See Output

DefaultPrimarySecondaryDangerTextLinkGhost

[code]

    def ex_buttons(): 
        return Grid(
            Button("Default"),
            Button("Primary",   cls=ButtonT.primary),
            Button("Secondary", cls=ButtonT.secondary),
            Button("Danger",    cls=ButtonT.destructive),
            Button("Text",      cls=ButtonT.text),
            Button("Link",      cls=ButtonT.link),
            Button("Ghost",     cls=ButtonT.ghost),
            )
    
[/code]

See Source

See Output

Default LinkMuted LinkText LinkReset LinkPrimary LinkClassic Link

[code]

    def ex_links(): 
        return Div(cls='space-x-4')(
            A('Default Link'),
            A('Muted Link', cls=AT.muted),
            A('Text Link',  cls=AT.text),
            A('Reset Link', cls=AT.reset),
            A('Primary Link', cls=AT.primary),
            A('Classic Link', cls=AT.classic),)
    
[/code]

### Button

Source

[code]

    Button(*c: Union[str, fastcore.xml.FT], cls: Union[str, enum.Enum] = <ButtonT.default: 'uk-btn-default'>, submit=True, **kwargs) -> fastcore.xml.FT
[/code]

> Button with Styling (defaults to `submit` for form submission)

**Params**

  * `c` Contents of `Button` tag (often text)

  * `cls` Classes in addition to `Button` styling (use `ButtonT` for built in styles)

  * `submit` Whether the button should submit a form

  * `kwargs`

**Returns:** Button(..., cls='uk-btn')

* * *

### ButtonT

_Options for styling Buttons_

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
default | uk-btn-default | ghost | uk-btn-ghost | primary | uk-btn-primary  
secondary | uk-btn-secondary | destructive | uk-btn-destructive | text | uk-btn-text  
link | uk-btn-link | xs | uk-btn-xs | sm | uk-btn-sm  
lg | uk-btn-lg | xl | uk-btn-xl | icon | uk-btn-icon  
  
* * *

### AT

_Link styles from https://franken-ui.dev/docs/link_

Option | Value | Option | Value  
---|---|---|---  
muted | uk-link-muted | text | uk-link-text  
reset | uk-link-reset | primary | uk-link text-primary hover:text-primary-focus underline  
classic | text-blue-600 hover:text-blue-800 underline |  | 
</doc><doc title="Cards" desc="Cards API Reference"># Cards API Reference

### Example Usage

See Source

See Output

Header

A card with header and footer

Input

Range

Footer Submit Button

[code]

    def ex_card():
        return Card(
            Form(LabelInput("Input"),
                 LabelRange("Range")),
            header=Div(
                CardTitle("Header"),
                P("A card with header and footer",cls=TextPresets.muted_sm)),
            footer=DivLAligned(Button("Footer Submit Button")))
    
[/code]

See Source

See Output

#### Creating Custom FastHTML Tags for Markdown Rendering

A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles

Isaac Flath20-October-2024

FastHTMLHTMXWeb Apps

Read

[code]

    def ex_card2_wide():
        def Tags(cats): return DivLAligned(map(Label, cats))
    
        return Card(
            DivLAligned(
                A(Img(src="https://picsum.photos/200/200?random=12", style="width:200px"),href="#"),
                Div(cls='space-y-3 uk-width-expand')(
                    H4("Creating Custom FastHTML Tags for Markdown Rendering"),
                    P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"),
                    DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted),
                    DivFullySpaced(
                        Tags(["FastHTML", "HTMX", "Web Apps"]),
                        Button("Read", cls=(ButtonT.primary,'h-6'))))),
            cls=CardT.hover)
    
[/code]

See Source

See Output

#### Creating Custom FastHTML Tags for Markdown Rendering

A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles

Isaac Flath20-October-2024

FastHTMLHTMXWeb Apps

Read

[code]

    def ex_card2_tall():
        def Tags(cats): return DivLAligned(map(Label, cats))
    
        return Card(
            Div(
                A(Img(src="https://picsum.photos/400/200?random=14"), href="#"),
                Div(cls='space-y-3 uk-width-expand')(
                    H4("Creating Custom FastHTML Tags for Markdown Rendering"),
                    P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"),
                    DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted),
                    DivFullySpaced(
                        Tags(["FastHTML", "HTMX", "Web Apps"]),
                        Button("Read", cls=(ButtonT.primary,'h-6'))))),
            cls=CardT.hover)
    
[/code]

See Source

See Output

### Sarah Chen

Engineering Lead

San Francisco

### James Wilson

Senior Developer

New York

### Maria Garcia

UX Designer

London

### Alex Kumar

Product Manager

Singapore

### Emma Brown

DevOps Engineer

Toronto

### Marcus Johnson

Frontend Developer

Berlin

[code]

    def ex_card3():
        def team_member(name, role, location="Remote"):
            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 ("mail", "linkedin", "github")))))
        team = [
            team_member("Sarah Chen", "Engineering Lead", "San Francisco"),
            team_member("James Wilson", "Senior Developer", "New York"),
            team_member("Maria Garcia", "UX Designer", "London"),
            team_member("Alex Kumar", "Product Manager", "Singapore"),
            team_member("Emma Brown", "DevOps Engineer", "Toronto"),
            team_member("Marcus Johnson", "Frontend Developer", "Berlin")
        ]
        return Grid(*team, cols_sm=1, cols_md=1, cols_lg=2, cols_xl=3)
    
[/code]

### API Reference

### Card

Source

[code]

    Card(*c, header: Union[fastcore.xml.FT, Iterable[fastcore.xml.FT]] = None, footer: Union[fastcore.xml.FT, Iterable[fastcore.xml.FT]] = None, body_cls='space-y-6', header_cls=(), footer_cls=(), cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a Card with a header, body, and footer

**Params**

  * `c` Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.)

  * `header` Component(s) that goes in the header (often a `ModalTitle` and a subtitle)

  * `footer` Component(s) that goes in the footer (often a `ModalCloseButton`)

  * `body_cls` classes for the body

  * `header_cls` classes for the header

  * `footer_cls` classes for the footer

  * `cls` class for outermost component

  * `kwargs`

**Returns:** Card component

### CardTitle

Source

[code]

    CardTitle(*c, cls=(), **kwargs)
[/code]

> Creates a card title

**Params**

  * `c` Components (often a string)

  * `cls` Additional classes on the div

  * `kwargs`

* * *

### CardT

_Card styles from UIkit_

Option | Value | Option | Value  
---|---|---|---  
default | uk-card-default | primary | uk-card-primary  
secondary | uk-card-secondary | destructive | uk-card-destructive  
hover | uk-card hover:shadow-lg hover:-translate-y-1 transition-all duration-200 |  |   
  
The remainder of these are only needed if you're doing something really special. They are used in the `Card` function to generate the boilerplate for you.

### CardContainer

Source

[code]

    CardContainer(*c, cls=<CardT.default: 'uk-card-default'>, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a card container

**Params**

  * `c` Components (typically `CardHeader`, `CardBody`, `CardFooter`)

  * `cls` Additional classes on the div

  * `kwargs`

**Returns:** Container for a card

### CardHeader

Source

[code]

    CardHeader(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a card header

**Params**

  * `c` Components that goes in the header (often a `ModalTitle` and description)

  * `cls` Additional classes on the div

  * `kwargs`

**Returns:** Container for the header of a card

### CardBody

Source

[code]

    CardBody(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a card body

**Params**

  * `c` Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.)

  * `cls` Additional classes on the div

  * `kwargs`

**Returns:** Container for the body of a card

### CardFooter

Source

[code]

    CardFooter(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a card footer

**Params**

  * `c` Components that go in the footer (often a `ModalCloseButton`)

  * `cls` Additional classes on the div

  * `kwargs`

**Returns:** Container for the footer of a card
</doc><doc title="Containers" desc="Articles, Containers &amp; Sections API Reference"># Articles, Containers & Sections API Reference

### ArticleMeta

Source

[code]

    ArticleMeta(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A metadata component for use within an Article showing things like date, author etc

**Params**

  * `c` contents of ArticleMeta tag (often other tags)

  * `cls` Classes in addition to ArticleMeta styling

  * `kwargs`

**Returns:** P(..., cls='uk-article-meta')

### ArticleTitle

Source

[code]

    ArticleTitle(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A title component for use within an Article

**Params**

  * `c` contents of ArticleTitle tag (often other tags)

  * `cls` Classes in addition to ArticleTitle styling

  * `kwargs`

**Returns:** H1(..., cls='uk-article-title')

### Article

Source

[code]

    Article(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A styled article container for blog posts or similar content

**Params**

  * `c` contents of Article tag (often other tags)

  * `cls` Classes in addition to Article styling

  * `kwargs`

**Returns:** Article(..., cls='uk-article')

See Source

See Output

# Sample Article Title

By: John Doe

lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

[code]

    def ex_articles():
        return Article(
            ArticleTitle("Sample Article Title"), 
            Subtitle("By: John Doe"),
            P('lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'))
    
[/code]

### Container

Source

[code]

    Container(*c, cls=('mt-5', <ContainerT.xl: 'uk-container-xl'>), **kwargs) -> fastcore.xml.FT
[/code]

> Div to be used as a container that often wraps large sections or a page of content

**Params**

  * `c` Contents of Container tag (often other FT Components)

  * `cls` Classes in addition to Container styling

  * `kwargs`

**Returns:** Container(..., cls='uk-container')

* * *

### ContainerT

_Max width container sizes from https://franken-ui.dev/docs/container_

Option | Value | Option | Value  
---|---|---|---  
xs | uk-container-xs | sm | uk-container-sm  
lg | uk-container-lg | xl | uk-container-xl  
expand | uk-container-expand |  |   
  
See Source

See Output

This is a sample container with custom styling.

[code]

    def ex_containers():
        return Container(
            "This is a sample container with custom styling.",
            cls=ContainerT.xs,
            style="background-color: #FFA500; color: #000000")
    
[/code]

### Section

Source

[code]

    Section(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Section with styling and margins

**Params**

  * `c` contents of Section tag (often other tags)

  * `cls` Classes in addition to Section styling

  * `kwargs`

**Returns:** Div(..., cls='uk-section')

* * *

### SectionT

_Section styles from https://franken-ui.dev/docs/section_

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
default | uk-section-default | muted | uk-section-muted | primary | uk-section-primary  
secondary | uk-section-secondary | xs | uk-section-xsmall | sm | uk-section-small  
lg | uk-section-large | xl | uk-section-xlarge | remove_vertical | uk-section-remove-vertical
</doc><doc title="Dividers" desc="Dividers API Reference"># Dividers API Reference

### Divider

Source

[code]

    Divider(*c, cls=('my-4', <DividerT.icon: 'uk-divider-icon'>), **kwargs) -> fastcore.xml.FT
[/code]

> Divider with default styling and margin

**Params**

  * `c` contents of Divider tag (often nothing)

  * `cls` Classes in addition to Divider styling

  * `kwargs`

**Returns:** Hr(..., cls='uk-divider-icon') or Div(..., cls='uk-divider-vertical')

* * *

### DividerT

_Divider Styles from https://franken-ui.dev/docs/divider_

Option | Value | Option | Value  
---|---|---|---  
icon | uk-divider-icon | sm | uk-divider-sm  
vertical | uk-divider-vertical |  |   
  
See Source

See Output

Small Divider

* * *

Vertical Divider

Icon Divider

* * *
[code]

    def ex_dividers():
        return Div(
            P("Small Divider"),
            Divider(cls=DividerT.sm),
            DivCentered(
                P("Vertical Divider"),
                Divider(cls=DividerT.vertical)),
            DivCentered("Icon Divider"),
            Divider(cls=DividerT.icon))
    
[/code]

### DividerSplit

Source

[code]

    DividerSplit(*c, cls=(), line_cls=(), text_cls=())
[/code]

> Creates a simple horizontal line divider with configurable thickness and vertical spacing

**Params**

  * `c`

  * `cls`

  * `line_cls`

  * `text_cls`

See Source

See Output

Or continue with

[code]

    def ex_dividersplit():
        return DividerSplit(P("Or continue with", cls=TextPresets.muted_sm))
    
[/code]

### DividerLine

Source

[code]

    DividerLine(lwidth=2, y_space=4)
[/code]

> **Params**

  * `lwidth`

  * `y_space`

See Source

See Output

* * *
[code]

    def ex_dividerline(): 
        return DividerLine()
    
[/code]
</doc><doc title="Forms" desc="Forms and User Inputs API Reference"># Forms and User Inputs API Reference

### Example Form

This form was live coded in a 5 minute video here

See Source

See Output

### Emergency Contact Form

Please fill out the form completely

First Name

Last Name

Email

Phone

### Relationship to patient

Parent

Sibling

Friend

Spouse

Significant Other

Relative

Child

Other

Address

Address Line 2

City

State

Zip

Submit Form

[code]

    def ex_form():
        relationship = ["Parent",'Sibling', "Friend", "Spouse", "Significant Other", "Relative", "Child", "Other"]
        return Div(cls='space-y-4')(
            DivCentered(
                H3("Emergency Contact Form"),
                P("Please fill out the form completely", cls=TextPresets.muted_sm)),
            Form(cls='space-y-4')(
                Grid(LabelInput("First Name",id='fn'), LabelInput("Last Name",id='ln')),
                Grid(LabelInput("Email",     id='em'), LabelInput("Phone",    id='ph')),
                H3("Relationship to patient"),
                Grid(*[LabelCheckboxX(o) for o in relationship], cols=4, cls='space-y-3'),
                LabelInput("Address",        id='ad'),
                LabelInput("Address Line 2", id='ad2'),
                Grid(LabelInput("City",      id='ct'), LabelInput("State",    id='st')),
                LabelInput("Zip",            id='zp'),
                DivCentered(Button("Submit Form", cls=ButtonT.primary))))
    
[/code]

See Source

See Output

Upload Button!

Upload Zone

[code]

    def ex_upload():
        return Div(Upload("Upload Button!", id='upload1'),
                   UploadZone(DivCentered(Span("Upload Zone"), UkIcon("upload")), id='upload2'),
                   cls='space-y-4')
    
[/code]

### FormLabel

Source

[code]

    FormLabel(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Label with default styling

**Params**

  * `c` contents of FormLabel tag (often text)

  * `cls` Classes in addition to FormLabel styling

  * `kwargs`

**Returns:** Label(..., cls='uk-form-label')

See Source

See Output

Form Label

[code]

    def ex_formlabel(): 
        return FormLabel("Form Label")
    
[/code]

### Input

Source

[code]

    Input(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> An Input with default styling

**Params**

  * `c` contents of Input tag (often nothing)

  * `cls` Classes in addition to Input styling

  * `kwargs`

**Returns:** Input(..., cls='uk-input')

See Source

See Output

Input

[code]

    def ex_input(): 
        return Div(
            Input(placeholder="Enter text"), 
            LabelInput(label="Input", id='myid'))
    
[/code]

### LabelInput

Source

[code]

    LabelInput(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT
[/code]

> A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id

**Params**

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `Input`

  * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)

  * `id` id for `FormLabel` and `Input` (`id`, `name` and `for` attributes are set to this value)

  * `kwargs`

**Returns:** Div(cls='space-y-2')(`FormLabel`, `Input`)

### LabelCheckboxX

Source

[code]

    LabelCheckboxX(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(<function ft at 0x7f757a5be7a0>, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT
[/code]

> A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id

**Params**

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `CheckboxX`

  * `container` Container to wrap label and input in (default is Div)

  * `cls` Classes on container (default is 'flex items-center space-x-2')

  * `id` id for `FormLabel` and `CheckboxX` (`id`, `name` and `for` attributes are set to this value)

  * `kwargs`

**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `CheckboxX`)

### LabelSwitch

Source

[code]

    LabelSwitch(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-x-2', id='', *, container=functools.partial(<function ft at 0x7f757a5be7a0>, 'div', void_=False)) -> fastcore.xml.FT
[/code]

> **Params**

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `Switch`

  * `container` Container to wrap label and input in (default is Div)

  * `cls` Classes on container (default is `'space-x-2'` to prevent scrunched up form elements)

  * `id` id for `FormLabel` and `Switch` (`id`, `name` and `for` attributes are set to this value)

**Returns:** Div(cls='space-y-2')(`FormLabel`, `Switch`)

### LabelRange

Source

[code]

    LabelRange(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-6', id='', value='', min=None, max=None, step=None, label_range=True, *, container=functools.partial(<function ft at 0x7f757a5be7a0>, 'div', void_=False)) -> fastcore.xml.FT
[/code]

> A FormLabel and Range pair that provides default spacing and links/names them based on id

**Params**

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `Range`

  * `container` Container to wrap label and input in (default is Div)

  * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)

  * `id` id for `FormLabel` and `Range` (`id`, `name` and `for` attributes are set to this value)

  * `value` Value for the range input

  * `min` Minimum value

  * `max` Maximum value

  * `step` Step size

  * `label_range` Whether to show the range value label (label for the `Range` component)

**Returns:** Div(cls='space-y-2')(`FormLabel`, `Range`)

### LabelTextArea

Source

[code]

    LabelTextArea(label: str | fastcore.xml.FT, value='', lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT
[/code]

> **Params**

  * `label` FormLabel content (often text)

  * `value` Value for the textarea

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `TextArea`

  * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)

  * `id` id for `FormLabel` and `TextArea` (`id`, `name` and `for` attributes are set to this value)

  * `kwargs`

**Returns:** Div(cls='space-y-2')(`FormLabel`, `TextArea`)

### LabelRadio

Source

[code]

    LabelRadio(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(<function ft at 0x7f757a5be7a0>, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT
[/code]

> A FormLabel and Radio pair that provides default spacing and links/names them based on id

**Params**

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `Radio`

  * `container` Container to wrap label and input in (default is Div)

  * `cls` Classes on container (default is 'flex items-center space-x-2')

  * `id` id for `FormLabel` and `Radio` (`id`, `name` and `for` attributes are set to this value)

  * `kwargs`

**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `Radio`)

### LabelSelect

Source

[code]

    LabelSelect(*option, label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(<function ft at 0x7f757a5be7a0>, 'div', void_=False), cls='space-y-2', id='', **kwargs)
[/code]

> A FormLabel and Select pair that provides default spacing and links/names them based on id (usually UkLabelSelect is a better choice)

**Params**

  * `option` Options for the select dropdown (can use `Options` helper function to create)

  * `label` FormLabel content (often text)

  * `lbl_cls` Additional classes for `FormLabel`

  * `input_cls` Additional classes for `Select`

  * `container` Container to wrap label and input in (default is Div)

  * `cls` Classes on container (default is 'space-y-2')

  * `id` id for `FormLabel` and `Select` (`id`, `name` and `for` attributes are set to this value)

  * `kwargs`

### Progress

Source

[code]

    Progress(*c, cls=(), value='', max='100', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a progress bar

**Params**

  * `c` Components to put in the progress bar (often nothing)

  * `cls` Additional classes on the progress bar

  * `value` Value of the progress bar

  * `max` Max value of the progress bar (defaults to 100 for percentage)

  * `kwargs`

**Returns:** Progress(..., cls='uk-progress')

See Source

See Output

[code]

    def ex_progress(): 
        return Progress(value=20, max=100)
    
[/code]

### Radio

Source

[code]

    Radio(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Radio with default styling

**Params**

  * `c` contents of Radio tag (often nothing)

  * `cls` Classes in addition to Radio styling

  * `kwargs`

**Returns:** Input(..., cls='uk-radio', type='radio')

See Source

See Output

Radio

[code]

    def ex_radio(): 
        return Div(
            Radio(name="radio-group", id="radio1"), 
            LabelRadio(label="Radio", id='radio1',cls='flex items-center space-x-4'))
    
[/code]

### CheckboxX

Source

[code]

    CheckboxX(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Checkbox with default styling

**Params**

  * `c` contents of CheckboxX tag (often nothing)

  * `cls` Classes in addition to CheckboxX styling

  * `kwargs`

**Returns:** Input(..., cls='uk-checkbox', type='checkbox')

See Source

See Output

Checkbox

[code]

    def ex_checkbox(): 
        return Div(
            CheckboxX(), 
            LabelCheckboxX(label="Checkbox", id='checkbox1'))
    
[/code]

### Range

Source

[code]

    Range(*c, value='', label=True, min=None, max=None, step=None, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Range with default styling

**Params**

  * `c` contents of Range tag (often nothing)

  * `value`

  * `label`

  * `min`

  * `max`

  * `step`

  * `cls` Classes in addition to Range styling

  * `kwargs`

**Returns:** Input(..., cls='uk-range', type='range')

See Source

See Output

Basic Range

Range with Label

Multiple Values

Custom Range

[code]

    def ex_range(): 
        return Div(
            Range(), 
            Range(label='kg', value="25,75", min=20, max=75),
            LabelRange('Basic Range', value='50', min=0, max=100, step=1),
            LabelRange('Range with Label', value='75', min=0, max=100, step=5, label_range=True),
            LabelRange('Multiple Values', value='25,75', min=0, max=100, step=5, label_range=True),
            LabelRange('Custom Range', value='500', min=0, max=1000, step=100, label_range=True)        
            )
    
[/code]

### Switch

Source

[code]

    Switch(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Switch with default styling

**Params**

  * `c` contents of Switch tag (often nothing)

  * `cls` Classes in addition to Switch styling

  * `kwargs`

**Returns:** Input(..., cls='uk-toggle-switch uk-toggle-switch-primary min-w-9', type='checkbox')

See Source

See Output

Switch

[code]

    def ex_switch(): 
        return Div(
            Switch(id="switch"), 
            LabelSwitch(label="Switch", id='switch'))
    
[/code]

### TextArea

Source

[code]

    TextArea(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Textarea with default styling

**Params**

  * `c` contents of TextArea tag (often text)

  * `cls` Classes in addition to TextArea styling

  * `kwargs`

**Returns:** TextArea(..., cls='uk-textarea')

See Source

See Output

TextArea

[code]

    def ex_textarea(): 
        return Div(
            TextArea(placeholder="Enter multiple lines of text"), 
            LabelTextArea(label="TextArea", id='myid'))
    
[/code]

### Select

Source

[code]

    Select(*option, inp_cls=(), cls=('h-10',), cls_custom='button: uk-input-fake dropdown: w-full', id='', name='', placeholder='', searchable=False, insertable=False, select_kwargs=None, **kwargs)
[/code]

> Creates a select dropdown with uk styling and option for adding a search box

**Params**

  * `option` Options for the select dropdown (can use `Options` helper function to create)

  * `inp_cls` Additional classes for the select input

  * `cls` Classes for the outer div (default h-10 for consistent height)

  * `cls_custom` Classes for the Uk_Select web component

  * `id` ID for the select input

  * `name` Name attribute for the select input

  * `placeholder` Placeholder text for the select input

  * `searchable` Whether the select should be searchable

  * `insertable` Whether to allow user-defined options to be added

  * `select_kwargs` Additional Arguments passed to Select

  * `kwargs`

See Source

See Output

Option 1Option 2Option 3

Select

Option 1Option 2Option 3

[code]

    def ex_select(): 
        return Div(
            Select(map(Option, ["Option 1", "Option 2", "Option 3"])),
            LabelSelect(map(Option, ["Option 1", "Option 2", "Option 3"]), label="Select", id='myid'))
    
[/code]

### Example: Insertable Select

In a production app, the user-inserted option would be saved server-side (db, session etc.)

See Source

See Output

AppleOrangeBananaMango

AppleBananaMangoOrange

[code]

    def ex_insertable_select1():
        fruit_opts = ['apple', 'orange', 'banana', 'mango']
    
        return Grid(
            Select(Option('Apple', value='apple'),
                   Option('Orange', value='orange'),
                   Option('Banana', value='banana'),
                   Option('Mango', value='mango'),
                   id="fruit", icon=True, insertable=True, placeholder="Choose a fruit..."),
    
            Select(Optgroup(label="Fruit")(
                        *map(lambda l: Option(l.capitalize(), value=l), sorted(fruit_opts))),
                    id="fruit", icon=True, insertable=True, placeholder="Choose a fruit...",
                    cls_custom="button: uk-input-fake justify-between w-full; dropdown: w-full"))
    
[/code]

### Legend

Source

[code]

    Legend(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Legend with default styling

**Params**

  * `c` contents of Legend tag (often other tags)

  * `cls` Classes in addition to Legend styling

  * `kwargs`

**Returns:** Legend(..., cls='uk-legend')

### Fieldset

Source

[code]

    Fieldset(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A Fieldset with default styling

**Params**

  * `c` contents of Fieldset tag (often other tags)

  * `cls` Classes in addition to Fieldset styling

  * `kwargs`

**Returns:** Fieldset(..., cls='uk-fieldset')
</doc><doc title="Html" desc="HTML Styling API Reference"># HTML Styling API Reference

See Source

See Output

<div><h1 class="uk-h1 text-4xl font-bold mt-12 mb-6">Hello, World!</h1><p class="text-lg leading-relaxed mb-6">This is a paragraph</p></div>

[code]

    def ex_applyclasses():
        return apply_classes('<h1>Hello, World!</h1><p>This is a paragraph</p>')
    
[/code]
</doc><doc title="Icons | Images" desc="Icons &amp; Images API Reference"># Icons & Images API Reference

# Avatars

See Source

See Output

[code]

    def ex_dicebear():
        return DivLAligned(
            DiceBearAvatar('Isaac Flath',10,10),
            DiceBearAvatar('Aaliyah',10,10),
            DiceBearAvatar('Alyssa',10,10))
    
[/code]

### DiceBearAvatar

Source

[code]

    DiceBearAvatar(seed_name: str, h: int = 20, w: int = 20)
[/code]

> Creates an Avatar using https://dicebear.com/

**Params**

  * `seed_name` Seed name (ie 'Isaac Flath')

  * `h` Height

  * `w` Width

# PlaceHolder Images

See Source

See Output

[code]

    def ex_picsum():
        return Grid(PicSumImg(100,100), PicSumImg(100,100, blur=6),PicSumImg(100,100, grayscale=True))
    
[/code]

### PicSumImg

Source

[code]

    PicSumImg(h: int = 200, w: int = 200, id: int = None, grayscale: bool = False, blur: int = None, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a placeholder image using https://picsum.photos/

**Params**

  * `h` Height in pixels

  * `w` Width in pixels

  * `id` Optional specific image ID to use

  * `grayscale` Whether to return grayscale version

  * `blur` Optional blur amount (1-10)

  * `kwargs`

**Returns:** Img tag with picsum image

# Icons

Icons use Lucide icons - you can find a full list of icons in their docs.

See Source

See Output

[code]

    def ex_icon():
        return Grid(
            UkIcon('chevrons-right', height=15, width=15),
            UkIcon('bug',            height=15, width=15),
            UkIcon('phone-call',     height=15, width=15),
            UkIcon('maximize-2',     height=15, width=15),
            UkIcon('thumbs-up',      height=15, width=15),)        
    
[/code]

### UkIcon

Source

[code]

    UkIcon(icon: str, height: int = None, width: int = None, stroke_width: int = None, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates an icon using lucide icons

**Params**

  * `icon` Icon name from lucide icons

  * `height`

  * `width`

  * `stroke_width` Thickness of lines

  * `cls` Additional classes on the `Uk_icon` tag

  * `kwargs`

**Returns:** a lucide icon of the specified size

See Source

See Output

[code]

    def ex_iconlink():
        return DivLAligned(
            UkIconLink('chevrons-right'),
            UkIconLink('chevrons-right', button=True, cls=ButtonT.primary))
    
[/code]

### UkIconLink

Source

[code]

    UkIconLink(icon: str, height: int = None, width: int = None, stroke_width: int = None, cls=(), button: bool = False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates an icon link using lucide icons

**Params**

  * `icon` Icon name from lucide icons

  * `height`

  * `width`

  * `stroke_width` Thickness of lines

  * `cls` Additional classes on the icon

  * `button` Whether to use a button (defaults to a link)

  * `kwargs`

**Returns:** a lucide icon button or link of the specified size
</doc><doc title="Layout" desc="Layout (Flex and Grid) API Reference"># Layout (Flex and Grid) API Reference

This page covers `Grid`s, which are often used for general structure, `Flex` which is often used for layout of components that are not grid based, padding and positioning that can help you make your layout look good, and dividers that can help break up the page

## Grid

See Source

See Output

Column 1 Item 1

Column 1 Item 2

Column 1 Item 3

Column 2 Item 1

Column 2 Item 2

Column 2 Item 3

Column 3 Item 1

Column 3 Item 2

Column 3 Item 3

[code]

    def ex_grid():
        return Grid(
            Div(
                P("Column 1 Item 1"), 
                P("Column 1 Item 2"), 
                P("Column 1 Item 3")),
            Div(
                P("Column 2 Item 1"), 
                P("Column 2 Item 2"), 
                P("Column 2 Item 3")),
            Div(
                P("Column 3 Item 1"), 
                P("Column 3 Item 2"), 
                P("Column 3 Item 3")))
    
[/code]

### Grid

Source

[code]

    Grid(*div, cols_min: int = 1, cols_max: int = 4, cols_sm: int = None, cols_md: int = None, cols_lg: int = None, cols_xl: int = None, cols: int = None, cls='gap-4', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a responsive grid layout with smart defaults based on content

**Params**

  * `div` `Div` components to put in the grid

  * `cols_min` Minimum number of columns at any screen size

  * `cols_max` Maximum number of columns allowed at any screen size

  * `cols_sm` Number of columns on small screens

  * `cols_md` Number of columns on medium screens

  * `cols_lg` Number of columns on large screens

  * `cols_xl` Number of columns on extra large screens

  * `cols` Number of columns on all screens

  * `cls` Additional classes on the grid (tip: `gap` provides spacing for grids)

  * `kwargs`

**Returns:** Responsive grid component

#### Practical Grid Example

See Source

See Output

#### Laptop

$999

Add to Cart

#### Smartphone

$599

Add to Cart

#### Headphones

$199

Add to Cart

#### Smartwatch

$299

Add to Cart

#### Tablet

$449

Add to Cart

#### Camera

$799

Add to Cart

[code]

    def ex_product_grid():
        products = [
            {"name": "Laptop", "price": "$999", "img": "https://picsum.photos/200/100?random=1"},
            {"name": "Smartphone", "price": "$599", "img": "https://picsum.photos/200/100?random=2"},
            {"name": "Headphones", "price": "$199", "img": "https://picsum.photos/200/100?random=3"},
            {"name": "Smartwatch", "price": "$299", "img": "https://picsum.photos/200/100?random=4"},
            {"name": "Tablet", "price": "$449", "img": "https://picsum.photos/200/100?random=5"},
            {"name": "Camera", "price": "$799", "img": "https://picsum.photos/200/100?random=6"},
        ]
        
        product_cards = [
            Card(
                Img(src=p["img"], alt=p["name"], style="width:100%; height:100px; object-fit:cover;"),
                H4(p["name"], cls="mt-2"),
                P(p["price"], cls=TextPresets.bold_sm),
                Button("Add to Cart", cls=(ButtonT.primary, "mt-2"))
            ) for p in products
        ]
        
        return Grid(*product_cards, cols_lg=3)
    
[/code]

## Flex

Play Flex Box Froggy to get an understanding of flex box.

### DivFullySpaced

Source

[code]

    DivFullySpaced(*c, cls='w-full', **kwargs)
[/code]

> Creates a flex div with it's components having as much space between them as possible

**Params**

  * `c` Components

  * `cls` Classes for outer div (`w-full` makes it use all available width)

  * `kwargs`

See Source

See Output

LeftCenterRight

[code]

    def ex_fully_spaced_div():
        return DivFullySpaced(
            Button("Left", cls=ButtonT.primary),
            Button("Center", cls=ButtonT.secondary),
            Button("Right", cls=ButtonT.destructive)
        )
    
[/code]

### DivCentered

Source

[code]

    DivCentered(*c, cls='space-y-4', vstack=True, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a flex div with it's components centered in it

**Params**

  * `c` Components

  * `cls` Classes for outer div (`space-y-4` provides spacing between components)

  * `vstack` Whether to stack the components vertically

  * `kwargs`

**Returns:** Div with components centered in it

See Source

See Output

### Centered Title

This content is centered both horizontally and vertically.

[code]

    def ex_centered_div():
        return DivCentered(
            H3("Centered Title"),
            P("This content is centered both horizontally and vertically.")
        )
    
[/code]

### DivLAligned

Source

[code]

    DivLAligned(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a flex div with it's components aligned to the left

**Params**

  * `c` Components

  * `cls` Classes for outer div

  * `kwargs`

**Returns:** Div with components aligned to the left

See Source

See Output

#### Left Aligned Title

Some text that's left-aligned with the title and image.

[code]

    def ex_l_aligned_div():
        return DivLAligned(
            Img(src="https://picsum.photos/100/100?random=1", style="max-width: 100px;"),
            H4("Left Aligned Title"),
            P("Some text that's left-aligned with the title and image.")
        )
    
[/code]

### DivRAligned

Source

[code]

    DivRAligned(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a flex div with it's components aligned to the right

**Params**

  * `c` Components

  * `cls` Classes for outer div

  * `kwargs`

**Returns:** Div with components aligned to the right

See Source

See Output

Action

Right-aligned text

[code]

    def ex_r_aligned_div():
        return DivRAligned(
            Button("Action", cls=ButtonT.primary),
            P("Right-aligned text"),
            Img(src="https://picsum.photos/100/100?random=3", style="max-width: 100px;")
        )
    
[/code]

### DivVStacked

Source

[code]

    DivVStacked(*c, cls='space-y-4', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a flex div with it's components stacked vertically

**Params**

  * `c` Components

  * `cls` Additional classes on the div (tip: `space-y-4` provides spacing between components)

  * `kwargs`

**Returns:** Div with components stacked vertically

See Source

See Output

## Vertical Stack

First paragraph in the stack

Second paragraph in the stack

Action Button

[code]

    def ex_v_stacked_div():
        return DivVStacked(
            H2("Vertical Stack"),
            P("First paragraph in the stack"),
            P("Second paragraph in the stack"),
            Button("Action Button", cls=ButtonT.secondary)
        )
    
[/code]

### DivHStacked

Source

[code]

    DivHStacked(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a flex div with it's components stacked horizontally

**Params**

  * `c` Components

  * `cls` Additional classes on the div (`space-x-4` provides spacing between components)

  * `kwargs`

**Returns:** Div with components stacked horizontally

See Source

See Output

#### Column 1

Content for column 1

#### Column 2

Content for column 2

#### Column 3

Content for column 3

[code]

    def ex_h_stacked_div():
        return DivHStacked(
            Div(H4("Column 1"), P("Content for column 1")),
            Div(H4("Column 2"), P("Content for column 2")),
            Div(H4("Column 3"), P("Content for column 3"))
        )
    
[/code]

* * *

### FlexT

_Flexbox modifiers using Tailwind CSS_

Option | Value | Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---|---|---  
block | flex | inline | inline-flex | left | justify-start | center | justify-center  
right | justify-end | between | justify-between | around | justify-around | stretch | items-stretch  
top | items-start | middle | items-center | bottom | items-end | row | flex-row  
row_reverse | flex-row-reverse | column | flex-col | column_reverse | flex-col-reverse | nowrap | flex-nowrap  
wrap | flex-wrap | wrap_reverse | flex-wrap-reverse |  |  |  | 
</doc><doc title="Lightbox" desc="Lightbox API Reference"># Lightbox API Reference

See Source

See Output

Open

[code]

    def ex_lightbox1():
        return LightboxContainer(
            LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='This is my super cool caption'),
        )
    
[/code]

See Source

See Output

Open

[code]

    def ex_lightbox2():
        return LightboxContainer(
            LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 1'),
            LightboxItem(href='https://picsum.photos/id/101/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 2'),
            LightboxItem(href='https://picsum.photos/id/102/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 3'),
        )
    
[/code]

See Source

See Output

mp4YoutubeVimeoIframe

[code]

    def ex_lightbox3():
        return LightboxContainer(
            LightboxItem(Button("mp4"), href='https://yootheme.com/site/images/media/yootheme-pro.mp4'),
            LightboxItem(Button("Youtube"), href='https://www.youtube.com/watch?v=c2pz2mlSfXA'),
            LightboxItem(Button("Vimeo"), href='https://vimeo.com/1084537'),
            LightboxItem(Button("Iframe"), data_type='iframe', href='https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d4740.819266853735!2d9.99008871708242!3d53.550454675412404!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x3f9d24afe84a0263!2sRathaus!5e0!3m2!1sde!2sde!4v1499675200938'))
    
[/code]

### LightboxContainer

Source

[code]

    LightboxContainer(*lightboxitem, data_uk_lightbox='counter: true', **kwargs) -> fastcore.xml.FT
[/code]

> Lightbox container that will hold `LightboxItems`

**Params**

  * `lightboxitem` `LightBoxItem`s that will be inside lightbox

  * `data_uk_lightbox` See https://franken-ui.dev/docs/2.0/lightbox for advanced options

  * `kwargs`

**Returns:** Lightbox

### LightboxItem

Source

[code]

    LightboxItem(*c, href, data_alt=None, data_caption=None, cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Anchor tag with appropriate structure to go inside a `LightBoxContainer`

**Params**

  * `c` Component that when clicked will open the lightbox (often a button)

  * `href` Href to image, youtube video, vimeo, google maps, etc.

  * `data_alt` Alt text for the lightbox item/image

  * `data_caption` Caption for the item that shows below it

  * `cls` Class for the A tag (often nothing or `uk-btn`)

  * `kwargs`

**Returns:** A(... href, data_alt, cls., ...)
</doc><doc title="Lists" desc="Lists API Reference"># Lists API Reference

See Source

See Output

#### disc List:

  * Item 1
  * Item 2

#### circle List:

  * Item 1
  * Item 2

#### square List:

  * Item 1
  * Item 2

#### decimal List:

  * Item 1
  * Item 2

#### hyphen List:

  * Item 1
  * Item 2

#### bullet List:

  * Item 1
  * Item 2

#### divider List:

  * Item 1
  * Item 2

#### striped List:

  * Item 1
  * Item 2

[code]

    def ex_lists():
        list_options = [(style,str(cls)) for style,cls in ListT.__members__.items()]
        lists = [Div(H4(f"{style} List:"), Ul(Li("Item 1"), Li("Item 2"), cls=cls)) for style, cls in list_options]
        return Grid(*lists)
    
[/code]

* * *

### ListT

_List styles using Tailwind CSS_

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
disc | list-disc list-inside | circle | list-[circle] list-inside | square | list-[square] list-inside  
decimal | uk-list uk-list-decimal | hyphen | uk-list uk-list-hyphen | bullet | uk-list uk-list-bullet  
divider | uk-list uk-list-divider | striped | uk-list uk-list-striped |  | 
</doc><doc title="Loading" desc="Loading IndicatorsAPI Reference"># Loading IndicatorsAPI Reference

See Source

See Output

[code]

    def ex_loading1():
        return Loading()
    
[/code]

See Source

See Output

[code]

    def ex_loading2():
        types = [LoadingT.spinner, LoadingT.dots, LoadingT.ring, LoadingT.ball, LoadingT.bars, LoadingT.infinity]
        sizes = [LoadingT.xs, LoadingT.sm, LoadingT.md, LoadingT.lg]
        rows = [Div(*[Loading((t,s)) for s in sizes], cls='flex gap-4') for t in types]
        return Div(*rows, cls='flex flex-col gap-4')
    
[/code]

### Loading

Source

[code]

    Loading(cls=(<LoadingT.bars: 'loading-bars'>, <LoadingT.lg: 'loading-large'>), htmx_indicator=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a loading animation component

**Params**

  * `cls` Classes for indicator (generally `LoadingT` options)

  * `htmx_indicator` Add htmx-indicator class

  * `kwargs`

**Returns:** Span(cls=...)

* * *

### LoadingT

__

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
spinner | loading-spinner | dots | loading-dots | ring | loading-ring  
ball | loading-ball | bars | loading-bars | infinity | loading-infinity  
xs | loading-xsmall | sm | loading-small | md | loading-medium  
lg | loading-large |  |  |  | 
</doc><doc title="Markdown" desc="Markdown + automated HTML styling API Reference"># Markdown + automated HTML styling API Reference

See Source

See Output

# Example Markdown

  * With **bold** and _italics_
  * With a link

### And a subheading

> This is a blockquote

This supports inline latex: $e^{\pi i} + 1 = 0$ as well as block latex thanks to Katex.

$$ \frac{1}{2\pi i} \oint_C \frac{f(z)}{z-z_0} dz $$

And even syntax highlighting thanks to Highlight.js! (Just make sure you set `highlightjs=True` in the headers function)

[code]

    def add(a, b):
        return a + b
    
[/code]

[code]

    def ex_markdown():
        md = '''# Example Markdown
    
    + With **bold** and *italics*
    + With a [link](https://github.com)
    
    ### And a subheading
    
    > This is a blockquote
    
    This supports inline latex: $e^{\\pi i} + 1 = 0$ as well as block latex thanks to Katex.
    
    $$
    \\frac{1}{2\\pi i} \\oint_C \\frac{f(z)}{z-z_0} dz
    $$
    
    And even syntax highlighting thanks to Highlight.js! (Just make sure you set `highlightjs=True` in the headers function)
    
    ```python
    def add(a, b):
        return a + b
    ```
    '''
        return render_md(md)
    
[/code]

You can overwrite the default styling for markdown rendering with your own css classes with `class_map

See Source

See Output

With custom **bold** style

> But no extra quote style because class_map overrides all default styled
[code]

    def ex_markdown2():
        md = '''With custom **bold** style\n\n > But no extra quote style because class_map overrides all default styled'''
        return render_md(md, class_map={'b': 'text-red-500'})
    
[/code]

You can modify the default styling for markdown rendering with your own css classes with `class_map_mods

See Source

See Output

With custom **bold** style

> But default quote style because class_map_mods replaces sepecified styles and leaves the rest as default
[code]

    def ex_markdown3():
        md = '''With custom **bold** style\n\n > But default  quote style because class_map_mods replaces sepecified styles and leaves the rest as default'''
        return render_md(md, class_map_mods={'b': 'text-red-500'})
    
[/code]

This uses the `apply_classes` function, which can be used to apply classes to html strings. This is useful for applying styles to any html you get from an external source.

See Source

See Output

<div><h1 class="uk-h1 text-4xl font-bold mt-12 mb-6">Hello, World!</h1><p class="text-lg leading-relaxed mb-6">This is a paragraph</p></div>

[code]

    def ex_applyclasses():
        return apply_classes('<h1>Hello, World!</h1><p>This is a paragraph</p>')
    
[/code]

One common external source is a markdown renderer. MonsterUI uses tailwind css for styling so you don't get any styling without specifying classes, `apply_classes` can do that for you.

See Source

See Output

# Hi

a link

[code]

    def ex_applyclasses2():
        from mistletoe import markdown, HTMLRenderer
        md = markdown('# Hi\n[a link](www.google.com)', renderer=HTMLRenderer)
        return Safe(apply_classes(md))
    
[/code]

### apply_classes

Source

[code]

    apply_classes(html_str: str, class_map=None, class_map_mods=None) -> str
[/code]

> Apply classes to html string

**Params**

  * `html_str` Html string

  * `class_map` Class map

  * `class_map_mods` Class map that will modify the class map map (useful for small changes to a base class map)

**Returns:** Html string with classes applied
</doc><doc title="Modals" desc="Modals API Reference"># Modals API Reference

### Example Modal

This is a subtitle

See Source

See Output

Open Modal

## Simple Test Modal

With some somewhat brief content to show that it works!

Close

[code]

    def ex_modal():
        return Div(
            Button("Open Modal",data_uk_toggle="target: #my-modal" ),
            Modal(ModalTitle("Simple Test Modal"), 
                  P("With some somewhat brief content to show that it works!", cls=TextPresets.muted_sm),
                  footer=ModalCloseButton("Close", cls=ButtonT.primary),id='my-modal'))
    
[/code]

### Modal

Source

[code]

    Modal(*c, header=None, footer=None, cls=(), dialog_cls=(), header_cls='p-6', body_cls='space-y-6', footer_cls=(), id='', open=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you

**Params**

  * `c` Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.)

  * `header` Components that go in the `ModalHeader` (often a `ModalTitle`)

  * `footer` Components that go in the `ModalFooter` (often a `ModalCloseButton`)

  * `cls` Additional classes on the outermost `ModalContainer`

  * `dialog_cls` Additional classes on the `ModalDialog`

  * `header_cls` Additional classes on the `ModalHeader`

  * `body_cls` Additional classes on the `ModalBody`

  * `footer_cls` Additional classes on the `ModalFooter`

  * `id` id for the outermost container

  * `open` Whether the modal is open (typically used for HTMX controlled modals)

  * `kwargs`

**Returns:** Fully styled modal FT Component

### ModalCloseButton

Source

[code]

    ModalCloseButton(*c, cls=(), htmx=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a button that closes a modal with js

**Params**

  * `c` Components to put in the button (often text and/or an icon)

  * `cls` Additional classes on the button

  * `htmx` Whether to use HTMX to close the modal (must add hx_get to a route that closes the modal)

  * `kwargs`

**Returns:** Button(..., cls='uk-modal-close') + `hx_target` and `hx_swap` if htmx is True

The remainder of the Modal functions below are used internally by the `Modal` function for you. You shouldn't need to use them unless you're doing something really special.

### ModalTitle

Source

[code]

    ModalTitle(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal title

**Params**

  * `c` Components to put in the `ModalTitle` (often text)

  * `cls` Additional classes on the `ModalTitle`

  * `kwargs`

**Returns:** H2(..., cls='uk-modal-title')

### ModalFooter

Source

[code]

    ModalFooter(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal footer

**Params**

  * `c` Components to put in the `ModalFooter` (often buttons)

  * `cls` Additional classes on the `ModalFooter`

  * `kwargs`

**Returns:** Div(..., cls='uk-modal-footer')

### ModalBody

Source

[code]

    ModalBody(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal body

**Params**

  * `c` Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.)

  * `cls` Additional classes on the `ModalBody`

  * `kwargs`

**Returns:** Div(..., cls='uk-modal-body')

### ModalHeader

Source

[code]

    ModalHeader(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal header

**Params**

  * `c` Components to put in the `ModalHeader`

  * `cls` Additional classes on the `ModalHeader`

  * `kwargs`

**Returns:** Div(..., cls='uk-modal-header')

### ModalDialog

Source

[code]

    ModalDialog(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal dialog

**Params**

  * `c` Components to put in the `ModalDialog` (often `ModalBody`, `ModalHeader`, etc)

  * `cls` Additional classes on the `ModalDialog`

  * `kwargs`

**Returns:** Div(..., cls='uk-modal-dialog')

### ModalContainer

Source

[code]

    ModalContainer(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a modal container that components go in

**Params**

  * `c` Components to put in the modal (often `ModalDialog`)

  * `cls` Additional classes on the `ModalContainer`

  * `kwargs`

**Returns:** Div(..., cls='uk-modal uk-modal-container')
</doc><doc title="Navigation" desc="Navigation (Nav, NavBar, Tabs, etc.) API Reference"># Navigation (Nav, NavBar, Tabs, etc.) API Reference

# Nav, NavBar, DowDownNav, and Tab examples

* * *

## Nav

See Source

See Output

  * Option 1
  * Option 2
  * Option 3

[code]

    def ex_nav1():
        mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))]
        return NavContainer(*mbrs1)
    
[/code]

See Source

See Output

  * NavHeaderLi
  * Option 1
  * Option 2
  * Option 3
  * Subtitle Ex 

NavSubtitle text to be shown

  *   * Parent Name
    * Child 1
    * Child 2
    * Child 3

[code]

    def ex_nav2():
        mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))]
        mbrs2 = [Li(A('Child 1')), Li(A('Child 2')),Li(A('Child 3'))]
    
        return NavContainer(
            NavHeaderLi("NavHeaderLi"),
            *mbrs1,
            Li(A(href='')(Div("Subtitle Ex",NavSubtitle("NavSubtitle text to be shown")))),
            NavDividerLi(),
            NavParentLi(
                A('Parent Name'),
                NavContainer(*mbrs2,parent=False),
                 ),
        )
    
[/code]

## Navbars

Fully responsive simple navbar using the high level API. This will collapse to a hamburger menu on mobile devices. See the Scrollspy example for a more complex navbar example.

See Source

See Output

### My Blog

Page1Page2Page3

Page1Page2Page3

[code]

    def ex_navbar1():
        return NavBar(A("Page1",href='/rt1'),
                      A("Page2",href='/rt2'),
                      A("Page3",href='/rt3'),
                      brand=H3('My Blog'))
    
[/code]

See Source

See Output

Page1Page2

Page1Page2

[code]

    def ex_navbar2():    
        return NavBar(
            A(Input(placeholder='search')), 
            A(UkIcon("rocket")), 
            A('Page1',href='/rt1'), 
            A("Page2", href='/rt3'),
            brand=DivLAligned(Img(src='/api_reference/logo.svg'),UkIcon('rocket',height=30,width=30)))
    
[/code]

## Drop Down Navs

See Source

See Output

Open DropDown

  * Item 1
  * Item 2

[code]

    def ex_navdrop():
        return Div(
            Button("Open DropDown"),
            DropDownNavContainer(Li(A("Item 1",href=''),Li(A("Item 2",href='')))))
    
[/code]

## Tabs

See Source

See Output

  * Active
  * Item
  * Item
  * Disabled

[code]

    def ex_tabs2():
        return Container(
            TabContainer(
                Li(A("Active",href='javascript:void(0);', cls='uk-active')),
                Li(A("Item",href='javascript:void(0);')),
                Li(A("Item",href='javascript:void(0);')),
                Li(A("Disabled", cls='uk-disabled'))))
    
[/code]

A tabs can use any method of navigation (htmx, or href). However, often these are use in conjunction with switchers do to this client side

See Source

See Output

  * Active
  * Item
  * Item
  * Disabled

  * # Tab 1

  * # Tab 2

  * # Tab 3

[code]

    def ex_tabs1():
        return Container(
            TabContainer(
                Li(A("Active",href='#', cls='uk-active')),
                Li(A("Item",href='#')),
                Li(A("Item",href='#')),
                Li(A("Disabled",href='#', cls='uk-disabled')),
                uk_switcher='connect: #component-nav; animation: uk-animation-fade',
                alt=True),
             Ul(id="component-nav", cls="uk-switcher")(
                Li(H1("Tab 1")),
                Li(H1("Tab 2")),
                Li(H1("Tab 3"))))
    
[/code]

# API Docs

### NavBar

Source

[code]

    NavBar(*c, brand=h3(('Title',),{'class': 'uk-h3 '}), right_cls='items-center space-x-4', mobile_cls='space-y-4', sticky: bool = False, uk_scrollspy_nav: bool | str = False, cls='p-4', scrollspy_cls=<ScrollspyT.underline: 'navbar-underline'>, menu_id=None) -> fastcore.xml.FT
[/code]

> Creates a responsive navigation bar with mobile menu support

**Params**

  * `c` Component for right side of navbar (Often A tag links)

  * `brand` Brand/logo component for left side

  * `right_cls` Spacing for desktop links

  * `mobile_cls` Spacing for mobile links

  * `sticky` Whether to stick to the top of the page while scrolling

  * `uk_scrollspy_nav` Whether to use scrollspy for navigation

  * `cls` Classes for navbar

  * `scrollspy_cls` Scrollspy class (usually ScrollspyT.*)

  * `menu_id` ID for menu container (used for mobile toggle)

**Returns:** Responsive NavBar

### TabContainer

Source

[code]

    TabContainer(*li, cls='', alt=False, **kwargs) -> fastcore.xml.FT
[/code]

> A TabContainer where children will be different tabs

**Params**

  * `li` Components

  * `cls` Additional classes on the `Ul`

  * `alt` Whether to use an alternative tab style

  * `kwargs`

**Returns:** Tab container

### NavContainer

Source

[code]

    NavContainer(*li, cls=<NavT.primary: 'uk-nav-primary'>, parent=True, uk_nav=False, uk_scrollspy_nav=False, sticky=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation container (useful for creating a sidebar navigation). A Nav is a list (NavBar is something different)

**Params**

  * `li` List items are navigation elements (Special `Li` such as `NavParentLi`, `NavDividerLi`, `NavHeaderLi`, `NavSubtitle`, `NavCloseLi` can also be used)

  * `cls` Additional classes on the nav

  * `parent` Whether this nav is a _parent_ or _sub_ nav

  * `uk_nav` True for default collapsible behavior, see frankenui docs for more advanced options

  * `uk_scrollspy_nav` Activates scrollspy linking each item `A` tags `href` to content's `id` attribute

  * `sticky` Whether to stick to the top of the page while scrolling

  * `kwargs`

**Returns:** FT Component that is a list of `Li` styled for a sidebar navigation menu

* * *

### NavT

__

Option | Value | Option | Value  
---|---|---|---  
default | uk-nav-default | primary | uk-nav-primary  
secondary | uk-nav-secondary |  |   
  
### NavCloseLi

Source

[code]

    NavCloseLi(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation list item with a close button

**Params**

  * `c` Components

  * `cls` Additional classes on the li

  * `kwargs`

**Returns:** Navigation list item with a close button

### NavSubtitle

Source

[code]

    NavSubtitle(*c, cls=<TextPresets.muted_sm: 'text-gray-500 dark:text-gray-200 text-sm'>, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation subtitle

**Params**

  * `c` Components

  * `cls` Additional classes on the div

  * `kwargs`

**Returns:** Navigation subtitle

### NavHeaderLi

Source

[code]

    NavHeaderLi(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation list item with a header

**Params**

  * `c` Components

  * `cls` Additional classes on the li

  * `kwargs`

**Returns:** Navigation list item with a header

### NavDividerLi

Source

[code]

    NavDividerLi(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation list item with a divider

**Params**

  * `c` Components

  * `cls` Additional classes on the li

  * `kwargs`

**Returns:** Navigation list item with a divider

### NavParentLi

Source

[code]

    NavParentLi(*nav_container, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a navigation list item with a parent nav for nesting

**Params**

  * `nav_container` `NavContainer` container for a nested nav with `parent=False`)

  * `cls` Additional classes on the li

  * `kwargs`

**Returns:** Navigation list item

### DropDownNavContainer

Source

[code]

    DropDownNavContainer(*li, cls=<NavT.primary: 'uk-nav-primary'>, parent=True, uk_nav=False, uk_dropdown=True, **kwargs) -> fastcore.xml.FT
[/code]

> A Nav that is part of a DropDown

**Params**

  * `li` Components

  * `cls` Additional classes on the nav

  * `parent` Whether to use a parent nav

  * `uk_nav` True for default collapsible behavior, see https://franken-ui.dev/docs/nav#component-options for more advanced options

  * `uk_dropdown` Whether to use a dropdown

  * `kwargs`

**Returns:** DropDown nav container
</doc><doc title="Notifications" desc="Alerts &amp; Toasts API Reference"># Alerts & Toasts API Reference

### Alerts

The simplest alert is a div wrapped with a span:

See Source

See Output

This is a plain alert

[code]

    def ex_alerts1(): return Alert("This is a plain alert")
    
[/code]

Alert colors are defined by the alert styles:

See Source

See Output

Your purchase has been confirmed!

[code]

    def ex_alerts2(): return Alert("Your purchase has been confirmed!", cls=AlertT.success)
    
[/code]

It often looks nice to use icons in alerts:

See Source

See Output

Please enter a valid email.

[code]

    def ex_alerts3():
        return Alert(
            DivLAligned(UkIcon('triangle-alert'), 
                        P("Please enter a valid email.")),
            cls=AlertT.error)
    
[/code]

### Alert

Source

[code]

    Alert(*c, cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Alert informs users about important events.

**Params**

  * `c` Content for Alert (often text and/or icon)

  * `cls` Class for the alert (often an `AlertT` option)

  * `kwargs`

**Returns:** Div(Span(...), cls='alert', role='alert')

* * *

### AlertT

_Alert styles from DaisyUI_

Option | Value | Option | Value  
---|---|---|---  
info | alert-info | success | alert-success  
warning | alert-warning | error | alert-error  
  
* * *

### Toasts

To define a toast with a particular location, add horizontal or vertical toast type classes:

See Source

See Output

First Example Toast

[code]

    def ex_toasts1():
        return Toast("First Example Toast", cls=(ToastHT.start, ToastVT.bottom))
    
[/code]

To define toast colors, set the class of the alert wrapped by the toast:

See Source

See Output

Second Example Toast

[code]

    def ex_toasts2():
        return Toast("Second Example Toast", alert_cls=AlertT.info)
    
[/code]

### Toast

Source

[code]

    Toast(*c, cls='', alert_cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Toasts are stacked announcements, positioned on the corner of page.

**Params**

  * `c` Content for toast (often test)

  * `cls` Classes for toast (often `ToastHT` and `ToastVT` options)

  * `alert_cls` classes for altert (often `AlertT` options)

  * `kwargs`

**Returns:** Div(Alert(...), cls='toast')

* * *

### ToastHT

_Horizontal position for Toast_

Option | Value | Option | Value  
---|---|---|---  
start | toast-start | center | toast-center  
end | toast-end |  |   
  
* * *

### ToastVT

_Vertical position for Toast_

Option | Value | Option | Value  
---|---|---|---  
top | toast-top | middle | toast-middle  
bottom | toast-bottom |  | 
</doc><doc title="Sliders" desc="Carousel Sliders API Reference"># Carousel Sliders API Reference

Here is a simple example of a slider:

See Source

See Output

[code]

    def ex_sliders_1():
        return Slider(*[Img(src=f'https://picsum.photos/200/200?random={i}') for i in range(10)])
    
[/code]

Here is a slider with cards:

See Source

See Output

### Card 0

Card 0 content

### Card 1

Card 1 content

### Card 2

Card 2 content

### Card 3

Card 3 content

### Card 4

Card 4 content

### Card 5

Card 5 content

### Card 6

Card 6 content

### Card 7

Card 7 content

### Card 8

Card 8 content

### Card 9

Card 9 content

[code]

    def ex_sliders_2():
        def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content'))
        return Slider(*[_card(i) for i in range(10)])
    
[/code]

Here is a slider with cards and autoplay:

See Source

See Output

### Card 0

Card 0 content

### Card 1

Card 1 content

### Card 2

Card 2 content

### Card 3

Card 3 content

### Card 4

Card 4 content

### Card 5

Card 5 content

### Card 6

Card 6 content

### Card 7

Card 7 content

### Card 8

Card 8 content

### Card 9

Card 9 content

[code]

    def ex_sliders_3():
        def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content'))
        return Slider(*[_card(i) for i in range(10)], items_cls='gap-10', uk_slider='autoplay: true; autoplay-interval: 1000')
    
[/code]

Typically you want to use the `Slider` component, but if you need more control you can use the `SliderContainer`, `SliderItems`, and `SliderNav` components.

### Slider

Source

[code]

    Slider(*c, cls='', items_cls='gap-4', nav=True, nav_cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a slider with optional navigation arrows

**Params**

  * `c` Items to show in slider

  * `cls` Classes for slider container

  * `items_cls` Classes for items container

  * `nav` Whether to show navigation arrows

  * `nav_cls` Classes for navigation arrows

  * `kwargs`

**Returns:** SliderContainer(SliderItems(..., cls='gap-4'), SliderNav?)

### SliderContainer

Source

[code]

    SliderContainer(*c, cls='', uk_slider=True, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a slider container

**Params**

  * `c` Components

  * `cls` Additional classes on the container

  * `uk_slider` See FrankenUI Slider docs for more options

  * `kwargs`

**Returns:** Div(..., cls='relative', uk_slider=True, ...)

### SliderItems

Source

[code]

    SliderItems(*c, cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a slider items container

**Params**

  * `c` Components

  * `cls` Additional classes for the items

  * `kwargs`

**Returns:** Div(..., cls='uk-slider-items uk-grid', ...)

### SliderNav

Source

[code]

    SliderNav(cls='uk-position-small uk-hidden-hover', prev_cls='absolute left-0 top-1/2 -translate-y-1/2', next_cls='absolute right-0 top-1/2 -translate-y-1/2', **kwargs) -> fastcore.xml.FT
[/code]

> Navigation arrows for Slider component

**Params**

  * `cls` Additional classes for the navigation

  * `prev_cls` Additional classes for the previous navigation

  * `next_cls` Additional classes for the next navigation

  * `kwargs`

**Returns:** Left and right navigation arrows for Slider component
</doc><doc title="Steps" desc="Steps API Reference"># Steps API Reference

See Source

See Output

  * Account Created
  * Profile Setup
  * Verification

[code]

    def ex_steps2():
        return Steps(
            LiStep("Account Created", cls=StepT.primary),
            LiStep("Profile Setup", cls=StepT.neutral),
            LiStep("Verification", cls=StepT.neutral),
            cls="w-full")
    
[/code]

See Source

See Output

  * Project Planning
  * Design Phase
  * Development
  * Testing
  * Deployment

[code]

    def ex_steps3():
        return Steps(
        LiStep("Project Planning", cls=StepT.success, data_content="📝"),
        LiStep("Design Phase", cls=StepT.success, data_content="💡"),
        LiStep("Development", cls=StepT.primary, data_content="🛠️"),
        LiStep("Testing", cls=StepT.neutral, data_content="🔎"),
        LiStep("Deployment", cls=StepT.neutral, data_content="🚀"),
        cls=(StepsT.vertical, "min-h-[400px]"))
    
[/code]

# API Docs

### Steps

Source

[code]

    Steps(*li, cls='', **kwargs) -> fastcore.xml.FT
[/code]

> Creates a steps container

**Params**

  * `li` Each `Li` represent a step (generally use `LiStep`)

  * `cls` class for Steps (generally a `StepsT` option)

  * `kwargs`

**Returns:** Ul(..., cls='steps')

* * *

### StepsT

_Options for Steps_

Option | Value | Option | Value  
---|---|---|---  
vertical | steps-vertical | horizonal | steps-horizonal  
  
### LiStep

Source

[code]

    LiStep(*c, cls='', data_content=None, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a step list item

**Params**

  * `c` Description for Step that goes next to bubble (often text)

  * `cls` Additional step classes (generally a `StepT` component)

  * `data_content` Content for inside bubble (defaults to number, often an emoji)

  * `kwargs`

**Returns:** Li(..., cls='step')

* * *

### StepT

_Step styles for LiStep_

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
primary | step-primary | secondary | step-secondary | accent | step-accent  
info | step-info | success | step-success | warning | step-warning  
error | step-error | neutral | step-neutral |  | 
</doc><doc title="Tables" desc="Tables API Reference"># Tables API Reference

See Source

See Output

Name | Age | City  
---|---|---  
Alice | 25 | New York  
Bob | 30 | San Francisco  
Charlie | 35 | London  
Total | 90
[code]

    def ex_tables0():
        return Table(
            Thead(Tr(Th('Name'),    Th('Age'), Th('City'))),
            Tbody(Tr(Td('Alice'),   Td('25'),  Td('New York')),
                  Tr(Td('Bob'),     Td('30'),  Td('San Francisco')),
                  Tr(Td('Charlie'), Td('35'),  Td('London'))),
            Tfoot(Tr(Td('Total'),   Td('90'))))
    
[/code]  
  
See Source

See Output

Name | Age | City  
---|---|---  
Alice | 25 | New York  
Bob | 30 | San Francisco  
Charlie | 35 | London  
Total | 90
[code]

    def ex_tables1():
        header =  ['Name',    'Age', 'City']
        body   = [['Alice',   '25',  'New York'],
                  ['Bob',     '30',  'San Francisco'],
                  ['Charlie', '35',  'London']]
        footer =  ['Total',   '90']
        return TableFromLists(header, body, footer)
    
[/code]  
  
See Source

See Output

NAME | AGE | CITY  
---|---|---  
Alice | 30 years | New York  
Bob | 25 years | London
[code]

    def ex_tables2():
        def body_render(k, v):
            match k.lower():
                case 'name': return Td(v, cls='font-bold')
                case 'age':  return Td(f"{v} years")
                case _:      return Td(v)
    
        header_data = ['Name',          'Age',     'City']
        body_data   =[{'Name': 'Alice', 'Age': 30, 'City': 'New York'},
                      {'Name': 'Bob',   'Age': 25, 'City': 'London'}]
    
        return TableFromDicts(header_data, body_data, 
            header_cell_render=lambda v: Th(v.upper()), 
            body_cell_render=body_render)
    
[/code]  
  
### Table

Source

[code]

    Table(*c, cls=(<TableT.middle: 'uk-table-middle'>, <TableT.divider: 'uk-table-divider'>, <TableT.hover: 'uk-table-hover'>, <TableT.sm: 'uk-table-sm'>), **kwargs) -> fastcore.xml.FT
[/code]

> Creates a table

**Params**

  * `c` Components (typically `Thead`, `Tbody`, `Tfoot`)

  * `cls` Additional classes on the table

  * `kwargs`

**Returns:** Table component

### TableFromLists

Source

[code]

    TableFromLists(header_data: Sequence, body_data: Sequence[Sequence], footer_data=None, header_cell_render=<function Th at 0x7f7524465d00>, body_cell_render=<function Td at 0x7f7524465c60>, footer_cell_render=<function Td at 0x7f7524465c60>, cls=(<TableT.middle: 'uk-table-middle'>, <TableT.divider: 'uk-table-divider'>, <TableT.hover: 'uk-table-hover'>, <TableT.sm: 'uk-table-sm'>), sortable=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a Table from a list of header data and a list of lists of body data

**Params**

  * `header_data` List of header data

  * `body_data` List of lists of body data

  * `footer_data` List of footer data

  * `header_cell_render` Function(content) -> FT that renders header cells

  * `body_cell_render` Function(key, content) -> FT that renders body cells

  * `footer_cell_render` Function(key, content) -> FT that renders footer cells

  * `cls` Additional classes on the table

  * `sortable` Whether to use sortable table

  * `kwargs`

**Returns:** Table from lists

### TableFromDicts

Source

[code]

    TableFromDicts(header_data: Sequence, body_data: Sequence[dict], footer_data=None, header_cell_render=<function Th at 0x7f7524465d00>, body_cell_render=<function <lambda> at 0x7f7524465e40>, footer_cell_render=<function <lambda> at 0x7f7524465ee0>, cls=(<TableT.middle: 'uk-table-middle'>, <TableT.divider: 'uk-table-divider'>, <TableT.hover: 'uk-table-hover'>, <TableT.sm: 'uk-table-sm'>), sortable=False, **kwargs) -> fastcore.xml.FT
[/code]

> Creates a Table from a list of header data and a list of dicts of body data

**Params**

  * `header_data` List of header data

  * `body_data` List of dicts of body data

  * `footer_data` List of footer data

  * `header_cell_render` Function(content) -> FT that renders header cells

  * `body_cell_render` Function(key, content) -> FT that renders body cells

  * `footer_cell_render` Function(key, content) -> FT that renders footer cells

  * `cls` Additional classes on the table

  * `sortable` Whether to use sortable table

  * `kwargs`

**Returns:** Styled Table

* * *

### TableT

__

Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---  
divider | uk-table-divider | striped | uk-table-striped | hover | uk-table-hover  
sm | uk-table-sm | lg | uk-table-lg | justify | uk-table-justify  
middle | uk-table-middle | responsive | uk-table-responsive |  |   
  
### Tbody

Source

[code]

    Tbody(*rows, cls=(), sortable=False, **kwargs)
[/code]

> **Params**

  * `rows`

  * `cls`

  * `sortable`

  * `kwargs`

### Th

Source

[code]

    Th(*c, cls=(), shrink=False, expand=False, small=False)
[/code]

> **Params**

  * `c` Components that go in the cell

  * `cls` Additional classes on the cell container

  * `shrink` Whether to shrink the cell

  * `expand` Whether to expand the cell

  * `small` Whether to use a small table

**Returns:** Table cell

### Td

Source

[code]

    Td(*c, cls=(), shrink=False, expand=False, small=False)
[/code]

> **Params**

  * `c` Components that go in the cell

  * `cls` Additional classes on the cell container

  * `shrink` Whether to shrink the cell

  * `expand` Whether to expand the cell

  * `small` Whether to use a small table

**Returns:** Table cell
</doc><doc title="Theme | Headers" desc="Theme and Headers API Reference"># Theme and Headers API Reference

To get headers with a default theme use `hdrs=Theme.<color>.headers()`. For example for the blue theme you would use `hdrs=Theme.blue.headers()`. The theme integrated together different frameworks and allows tailwind, FrankenUI, HighlighJS, and DaisyUI components to work well together.

Tailwind, FrankenUI and DaisyUI are imported by default. You must use DaisyUI headers to use anything in the `daisy` module, and FrankenUI headers to use anything in the `franken` module.

HighlightJS is not added by default, but you can add it by setting `highlightjs=True` in the headers function. The `render_md` function will use HighlightJS for code blocks.

Theme options are:

Theme.slate

Theme.stone

Theme.gray

Theme.neutral

Theme.red

Theme.rose

Theme.orange

Theme.green

Theme.blue

Theme.yellow

Theme.violet

Theme.zinc

### Theme Picker

See Source

See Output

ZincSlateStoneGrayNeutralRedRoseOrangeGreenBlueYellowVioletNoneSmallMediumLargeNoneSmallMediumLargeSmallDefaultLightDark

[code]

    def ex_theme_switcher():
        return ThemePicker()
    
[/code]

### ThemePicker

Source

[code]

    ThemePicker(color=True, radii=True, shadows=True, font=True, mode=True, cls='p-4', custom_themes=[])
[/code]

> Theme picker component with configurable sections

**Params**

  * `color`

  * `radii`

  * `shadows`

  * `font`

  * `mode`

  * `cls`

  * `custom_themes`

Themes are controlled with `bg-background text-foreground` classes on the `Body` tag. `fast_app` and `FastHTML` will do this for you automatically so you typically do not have to do anything

### fast_app

Source

[code]

    fast_app(*args, pico=False, db_file: Optional[str] = None, render: Optional[<built-in function callable>] = None, hdrs: Optional[tuple] = None, ftrs: Optional[tuple] = None, tbls: Optional[dict] = None, before: Union[tuple, NoneType, fasthtml.core.Beforeware] = None, middleware: Optional[tuple] = None, live: bool = False, debug: bool = False, routes: Optional[tuple] = None, exception_handlers: Optional[dict] = None, on_startup: Optional[<built-in function callable>] = None, on_shutdown: Optional[<built-in function callable>] = None, lifespan: Optional[<built-in function callable>] = None, default_hdrs=True, surreal: Optional[bool] = True, htmx: Optional[bool] = True, exts: Union[list, str, NoneType] = None, secret_key: Optional[str] = None, key_fname: str = '.sesskey', session_cookie: str = 'session_', max_age: int = 31536000, sess_path: str = '/', same_site: str = 'lax', sess_https_only: bool = False, sess_domain: Optional[str] = None, htmlkw: Optional[dict] = None, bodykw: Optional[dict] = None, reload_attempts: Optional[int] = 1, reload_interval: Optional[int] = 1000, static_path: str = '.', body_wrap: <built-in function callable> = <function noop_body at 0x7f7579c5dc60>, nb_hdrs: bool = False)
[/code]

> Create a FastHTML or FastHTMLWithLiveReload app with `bg-background text-foreground` to bodykw for frankenui themes

**Params**

  * `db_file` Database file name, if needed

  * `render` Function used to render default database class

  * `hdrs` Additional FT elements to add to 

  * `ftrs` Additional FT elements to add to end of 

  * `tbls` Experimental mapping from DB table names to dict table definitions

  * `before` Functions to call prior to calling handler

  * `middleware` Standard Starlette middleware

  * `live` Enable live reloading

  * `debug` Passed to Starlette, indicating if debug tracebacks should be returned on errors

  * `routes` Passed to Starlette

  * `exception_handlers` Passed to Starlette

  * `on_startup` Passed to Starlette

  * `on_shutdown` Passed to Starlette

  * `lifespan` Passed to Starlette

  * `default_hdrs` Include default FastHTML headers such as HTMX script?

  * `pico` Include PicoCSS header?

  * `surreal` Include surreal.js/scope headers?

  * `htmx` Include HTMX header?

  * `exts` HTMX extension names to include

  * `secret_key` Signing key for sessions

  * `key_fname` Session cookie signing key file name

  * `session_cookie` Session cookie name

  * `max_age` Session cookie expiry time

  * `sess_path` Session cookie path

  * `same_site` Session cookie same site policy

  * `sess_https_only` Session cookie HTTPS only?

  * `sess_domain` Session cookie domain

  * `htmlkw` Attrs to add to the HTML tag

  * `bodykw` Attrs to add to the Body tag

  * `reload_attempts` Number of reload attempts when live reloading

  * `reload_interval` Time between reload attempts in ms

  * `static_path` Where the static file route points to, defaults to root dir

  * `body_wrap` FT wrapper for body contents

  * `nb_hdrs` If in notebook include headers inject headers in notebook DOM?

  * `args`

### FastHTML

Source

[code]

    FastHTML(*args, pico=False, debug=False, routes=None, middleware=None, title: str = 'FastHTML page', exception_handlers=None, on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, ftrs=None, exts=None, before=None, after=None, surreal=True, htmx=True, default_hdrs=True, sess_cls=<class 'starlette.middleware.sessions.SessionMiddleware'>, secret_key=None, session_cookie='session_', max_age=31536000, sess_path='/', same_site='lax', sess_https_only=False, sess_domain=None, key_fname='.sesskey', body_wrap=<function noop_body at 0x7f7579c5dc60>, htmlkw=None, nb_hdrs=False)
[/code]

> Create a FastHTML app and adds `bg-background text-foreground` to bodykw for frankenui themes

**Params**

  * `debug`

  * `routes`

  * `middleware`

  * `title`

  * `exception_handlers`

  * `on_startup`

  * `on_shutdown`

  * `lifespan`

  * `hdrs`

  * `ftrs`

  * `exts`

  * `before`

  * `after`

  * `surreal`

  * `htmx`

  * `default_hdrs`

  * `sess_cls`

  * `secret_key`

  * `session_cookie`

  * `max_age`

  * `sess_path`

  * `same_site`

  * `sess_https_only`

  * `sess_domain`

  * `key_fname`

  * `body_wrap`

  * `htmlkw`

  * `nb_hdrs`

  * `args`

  * `pico`
</doc><doc title="Typography" desc="Typography API Reference"># Typography API Reference

Ready to go semantic options that cover most of what you need based on the HTML spec

See Source

See Output

Titled

# Titled

# Level 1 Heading (H1)

## Level 2 Heading (H2)

### Level 3 Heading (H3)

#### Level 4 Heading (H4)

##### Level 5 Heading (H5)

###### Level 6 Heading (H6)

[code]

    def ex_headings():
        return Div(
            Titled("Titled"),
            H1("Level 1 Heading (H1)"), 
            H2("Level 2 Heading (H2)"), 
            H3("Level 3 Heading (H3)"), 
            H4("Level 4 Heading (H4)"),
            H5("Level 5 Heading (H5)"),
            H6("Level 6 Heading (H6)"),
            )
    
[/code]

See Source

See Output

## Semantic HTML Elements Demo

Here's an example of _emphasized (Em)_ and **strong (Strong)** text.

Some _italic text (I)_ and smaller text (Small) in a paragraph.

You can highlight (Mark) text, show ~~deleted (Del)~~ and inserted (Ins) content.

Chemical formulas use subscripts (Sub) and superscripts (Sup) like H2O.

> The only way to do great work is to love what you do.
>
> Steve Jobs (Cite)

As Shakespeare wrote, "All the world's a stage (Q)".

Posted on 2024-01-29

Mozilla Foundation (Address)  
331 E Evelyn Ave (Address)  
Mountain View, CA 94041 (Address)  
USA (Address)

HTML (Dfn) (HyperText Markup Language (Abbr)) is the standard markup language for documents designed to be displayed in a web browser.

Press `Ctrl (Kbd)` \+ `C (Kbd)` to copy.

The command returned: Hello, World! (Samp)

Let x (Var) be the variable in the equation.

Figure 1: An example image with caption (Caption)Click to show more information (Summary)

This is the detailed content that is initially hidden (P)

123 (Data) is a number, and here's a Meter showing progress:

Temperature:  (with low/high/optimum values)

€42.00 \- price example with semantic value

Form calculation result: The sum is 42 (Output)

### Blog Post Title (H3)

By John Doe • 5 min read (Small)

Article content here...

This text has _proper name annotation (U)_ and this is ~~outdated information (S)~~ that's been superseded.

[code]

    def ex_semantic_elements():
        return Div(
            H2("Semantic HTML Elements Demo"),
            # Text formatting examples
            P("Here's an example of ", Em("emphasized (Em)"), " and ", Strong("strong (Strong)"), " text."),
            P("Some ", I("italic text (I)"), " and ", Small("smaller text (Small)"), " in a paragraph."),
            P("You can ", Mark("highlight (Mark)"), " text, show ", Del("deleted (Del)"), " and ", 
              Ins("inserted (Ins)"), " content."),
            P("Chemical formulas use ", Sub("subscripts (Sub)"), " and ", Sup("superscripts (Sup)"), 
              " like H", Sub("2"), "O."),
            # Quote examples
            Blockquote(
                P("The only way to do great work is to love what you do."),
                Cite("Steve Jobs (Cite)")),
            P("As Shakespeare wrote, ", Q("All the world's a stage (Q)"), "."),
            # Time and Address
            P("Posted on ", Time("2024-01-29", datetime="2024-01-29")),
            Address(
                "Mozilla Foundation (Address)",
                Br(),
                "331 E Evelyn Ave (Address)",
                Br(),
                "Mountain View, CA 94041 (Address)",
                Br(),
                "USA (Address)"),
            # Technical and definition examples
            P(
                Dfn("HTML (Dfn)"), " (", 
                Abbr("HyperText Markup Language (Abbr)", title="HyperText Markup Language"), 
                ") is the standard markup language for documents designed to be displayed in a web browser."),
            P("Press ", Kbd("Ctrl (Kbd)"), " + ", Kbd("C (Kbd)"), " to copy."),
            P("The command returned: ", Samp("Hello, World! (Samp)")),
            P("Let ", Var("x (Var)"), " be the variable in the equation."),
            # Figure with caption
            Figure(
                PicSumImg(),
                Caption("Figure 1: An example image with caption (Caption)")),
            # Interactive elements
            Details(
                Summary("Click to show more information (Summary)"),
                P("This is the detailed content that is initially hidden (P)")),
            # Data representation
            P(
                Data("123 (Data)", value="123"), " is a number, and here's a Meter showing progress: ",
                Meter(value=0.6, min=0, max=1)),
            P(
                "Temperature: ",
                Meter(value=-1, min=-10, max=40, low=0, high=30, optimum=21),
                " (with low/high/optimum values)"),
            P(
                Data("€42.00", value="42"), 
                " - price example with semantic value"),
            # Output example
            P("Form calculation result: ", Output("The sum is 42 (Output)", form="calc-form", for_="num1 num2")),
            # Meta information example
            Section(
                H3("Blog Post Title (H3)"),
                Small("By John Doe • 5 min read (Small)"),
                P("Article content here...")),
            # Text decoration examples
            P("This text has ",U("proper name annotation (U)"), " and this is ",S("outdated information (S)"), " that's been superseded."),
            cls='space-y-4'
        )
    
[/code]

See Source

See Output

`This is a CodeSpan element`

> This is a blockquote element
[code]

    #This is a CodeBlock element
    
    def add(a,b): return a+b
[/code]

[code]

    def ex_other():
        return Div(
            CodeSpan("This is a CodeSpan element"),
            Blockquote("This is a blockquote element"),
            CodeBlock("#This is a CodeBlock element\n\ndef add(a,b): return a+b"))
    
[/code]

Styling text is possibly the most common style thing to do, so we have a couple of helpers for discoverability inside python. `TextPresets` is intended to be combinations are are widely applicable and used often, where `TextT` is intended to be more flexible options for you to combine together yourself.

##### TextPresets.*

See Source

See Output

This is muted_sm text

This is muted_lg text

This is bold_sm text

This is bold_lg text

This is md_weight_sm text

This is md_weight_muted text

[code]

    def ex_textpresets():
        return Grid(*[Div(P(f"This is {preset.name} text", cls=preset.value)) for preset in TextPresets])
    
[/code]

##### TextT.*

See Source

See Output

This is paragraph text

This is lead text

This is meta text

This is gray text

This is italic text

This is xs text

This is sm text

This is lg text

This is xl text

This is light text

This is normal text

This is medium text

This is bold text

This is extrabold text

This is primary text

This is secondary text

This is success text

This is warning text

This is error text

This is info text

This is left text

This is right text

This is center text

This is justify text

This is start text

This is end text

This is top text

This is middle text

This is bottom text

This is truncate text

This is break_ text

This is nowrap text

This is underline text

This is highlight text

[code]

    def ex_textt():
        return Grid(*[Div(P(f"This is {s.name} text", cls=s.value)) for s in TextT])
    
[/code]

### API Reference

* * *

### TextPresets

_Common Typography Presets_

Option | Value | Option | Value  
---|---|---|---  
muted_sm | text-gray-500 dark:text-gray-200 text-sm | muted_lg | text-gray-500 dark:text-gray-200 text-lg  
bold_sm | font-bold text-sm | bold_lg | font-bold text-lg  
md_weight_sm | text-sm font-medium | md_weight_muted | font-medium text-gray-500 dark:text-gray-200  
  
* * *

### TextT

_Text Styles from https://franken-ui.dev/docs/text_

Option | Value | Option | Value | Option | Value | Option | Value  
---|---|---|---|---|---|---|---  
paragraph | uk-paragraph | lead | uk-text-lead | meta | uk-text-meta | gray | text-gray-500 dark:text-gray-200  
italic | italic | xs | text-xs | sm | text-sm | lg | text-lg  
xl | text-xl | light | font-normal | normal | font-light | medium | font-medium  
bold | font-bold | extrabold | font-extrabold | muted | text-gray-500 dark:text-gray-200 | primary | text-primary  
secondary | text-secondary | success | text-success | warning | text-warning | error | text-error  
info | text-info | left | text-left | right | text-right | center | text-center  
justify | text-justify | start | text-start | end | text-end | top | align-top  
middle | align-middle | bottom | align-bottom | truncate | uk-text-truncate | break_ | uk-text-break  
nowrap | uk-text-nowrap | underline | underline | highlight | bg-yellow-200 dark:bg-yellow-800 text-black |  |   
  
### H1

Source

[code]

    H1(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H1 with styling and appropriate size

**Params**

  * `c` Contents of H1 tag (often text)

  * `cls` Classes in addition to H1 styling

  * `kwargs`

**Returns:** H1(..., cls='uk-h1')

### H2

Source

[code]

    H2(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H2 with styling and appropriate size

**Params**

  * `c` Contents of H2 tag (often text)

  * `cls` Classes in addition to H2 styling

  * `kwargs`

**Returns:** H2(..., cls='uk-h2')

### H3

Source

[code]

    H3(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H3 with styling and appropriate size

**Params**

  * `c` Contents of H3 tag (often text)

  * `cls` Classes in addition to H3 styling

  * `kwargs`

**Returns:** H3(..., cls='uk-h3')

### H4

Source

[code]

    H4(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H4 with styling and appropriate size

**Params**

  * `c` Contents of H4 tag (often text)

  * `cls` Classes in addition to H4 styling

  * `kwargs`

**Returns:** H4(..., cls='uk-h4')

### H5

Source

[code]

    H5(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H5 with styling and appropriate size

**Params**

  * `c` Contents of H5 tag (often text)

  * `cls` Classes in addition to H5 styling

  * `kwargs`

**Returns:** H5(..., cls='text-lg font-semibold')

### H6

Source

[code]

    H6(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> H6 with styling and appropriate size

**Params**

  * `c` Contents of H6 tag (often text)

  * `cls` Classes in addition to H6 styling

  * `kwargs`

**Returns:** H6(..., cls='text-base font-semibold')

### CodeSpan

Source

[code]

    CodeSpan(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]

> A CodeSpan with Styling

**Params**

  * `c` Contents of CodeSpan tag (inline text code snippets)

  * `cls` Classes in addition to CodeSpan styling

  * `kwargs`

**Returns:** Code(..., cls='uk-codespan')

### Blockquote

Source

[code]

    Blockquote(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Blockquote with Styling

**Params**

  * `c` Contents of Blockquote tag (often text)

  * `cls` Classes in addition to Blockquote styling

  * `kwargs`

**Returns:** Blockquote(..., cls='uk-blockquote')

### CodeBlock

Source

[code]

    CodeBlock(*c: str, cls: enum.Enum | str | tuple = (), code_cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> CodeBlock with Styling

**Params**

  * `c` Contents of Code tag (often text)

  * `cls` Classes for the outer container

  * `code_cls` Classes for the code tag

  * `kwargs`

**Returns:** Div(Pre(Code(..., cls='uk-codeblock), cls='multiple tailwind styles'), cls='uk-block')

### Em

Source

[code]

    Em(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled emphasis text

**Params**

  * `c` Contents of Em tag (emphasis)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Em tag

### Strong

Source

[code]

    Strong(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled strong text

**Params**

  * `c` Contents of Strong tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Strong tag

### I

Source

[code]

    I(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled italic text

**Params**

  * `c` Contents of I tag (italics)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for I tag

### Small

Source

[code]

    Small(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled small text

**Params**

  * `c` Contents of Small tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Small tag

### Mark

Source

[code]

    Mark(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled highlighted text

**Params**

  * `c` Contents of Mark tag (highlighted text)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Mark tag

### Sub

Source

[code]

    Sub(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled subscript text

**Params**

  * `c` Contents of Sub tag (subscript)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Sub tag

### Sup

Source

[code]

    Sup(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled superscript text

**Params**

  * `c` Contents of Sup tag (superscript)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Sup tag

### Del

Source

[code]

    Del(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled deleted text

**Params**

  * `c` Contents of Del tag (deleted text)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Del tag

### Ins

Source

[code]

    Ins(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled inserted text

**Params**

  * `c` Contents of Ins tag (inserted text)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Ins tag

### Dfn

Source

[code]

    Dfn(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled definition term with italic and medium weight

**Params**

  * `c` Contents of Dfn tag (definition)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Dfn tag

### Abbr

Source

[code]

    Abbr(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), title: str = None, **kwargs) -> fastcore.xml.FT
[/code]

> Styled abbreviation with dotted underline

**Params**

  * `c` Contents of Abbr tag

  * `cls` Additional classes

  * `title` Title attribute for abbreviation

  * `kwargs`

**Returns:** Additional args for Abbr tag

### Q

Source

[code]

    Q(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled quotation mark

**Params**

  * `c` Contents of Q tag (quote)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Q tag

### Kbd

Source

[code]

    Kbd(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled keyboard input with subtle background

**Params**

  * `c` Contents of Kbd tag (keyboard input)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Kbd tag

### Samp

Source

[code]

    Samp(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled sample output with subtle background

**Params**

  * `c` Contents of Samp tag (sample output)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Samp tag

### Var

Source

[code]

    Var(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled variable with italic monospace

**Params**

  * `c` Contents of Var tag (variable)

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Var tag

### Figure

Source

[code]

    Figure(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled figure container with card-like appearance

**Params**

  * `c` Contents of Figure tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Figure tag

### Caption

Source

[code]

    Caption(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled caption text

**Params**

  * `c`

  * `cls`

  * `kwargs`

### Details

Source

[code]

    Details(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled details element

**Params**

  * `c` Contents of Details tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Details tag

### Summary

Source

[code]

    Summary(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled summary element

**Params**

  * `c` Contents of Summary tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Summary tag

### Meter

Source

[code]

    Meter(*c: fastcore.xml.FT | str, value: float = None, min: float = None, max: float = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled meter element

**Params**

  * `c` Contents of Meter tag

  * `value` Current value

  * `min` Minimum value

  * `max` Maximum value

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Meter tag

### Data

Source

[code]

    Data(*c: fastcore.xml.FT | str, value: str = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled data element

**Params**

  * `c` Contents of Data tag

  * `value` Value attribute

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Data tag

### Output

Source

[code]

    Output(*c: fastcore.xml.FT | str, form: str = None, for_: str = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled output element for form results

**Params**

  * `c` Contents of Output tag

  * `form` ID of form this output belongs to

  * `for_` IDs of elements this output is for

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Output tag

### Address

Source

[code]

    Address(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT
[/code]

> Styled address element

**Params**

  * `c` Contents of Address tag

  * `cls` Additional classes

  * `kwargs`

**Returns:** Additional args for Address tag

### Time

Source

[code]

    Time(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), datetime: str = None, **kwargs) -> fastcore.xml.FT
[/code]

> Styled time element

**Params**

  * `c` Contents of Time tag

  * `cls` Additional classes

  * `datetime` datetime attribute

  * `kwargs`

**Returns:** Additional args for Time tag

  *[HyperText Markup Language (Abbr)]: HyperText Markup Language
</doc><doc title="Layout" desc="MonsterUI Page Layout Guide"># MonterUI Page Layout Guide

This guide will discuss 3 tools for laying out your app pages, Grid, Flexbox, and Columns. This page will discuss the strengths and when to use each individually, and then a section for how to combine them for more complex layouts at the end.

> Note: This guide is designed to get you started building layouts quickly, not to teach you all the details needed to build every possible custom layout with pixel-perfect control. To get more detailed and lower-level control, explore the tailwind docs.

This guide is for creating flexible layouts you envision, but does not discuss responsiveness to make different layouts that are both mobile and desktop friendly. Stay tunes for a responsiveness guide that will help with that!

# Grid

Grids are best for regular predictable layouts with lots of the same shape of things that may need to change a lot for different screen sizes. I think the best way to see what it can do is to see a bunch of examples, so here they are!

## Minimal Image Cards

This is a minimal example of a grid that just shows image and text. This is the foundation for many more complex layouts so make sure to understand what's going on here first before moving on!

A grid lays things out in a...grid. As you can see, we have evenly sized cards by default.

See Source

See Output

Image 0

Image 1

Image 2

Image 3

Image 4

Image 5

[code]

    def picsum_img(seed): return Img(src=f'https://picsum.photos/300/200?random={seed}')
       
    Grid(*[Card(picsum_img(i),P(f"Image {i}")) for i in range(6)])
[/code]

## Dashboard Example

However, they don't have to be evenly sized! By providing `row-span-{int}` and `col-span-{int}` we can control how many rows or columns specific grid elements take up. By doing this, we can create a grid that has lots of different shapes and types of elements.

Let's look at a dashboard layout at an examples of this.

See Source

See Output

### SideBar

Range For Filters

A search Bar

Choose Product Line

Product Line AProduct Line BProduct Line CProduct Line D

Include Inactive Users

Include Users without order

Include Users without email

Total Users

### 1,234

Active Now

### 342

Revenue

### $45,678

Conversion

### 2.4%

### Monthly Revenue

Chart Goes Here

### User Growth

Chart Goes Here

[code]

    def StatCard(title, value, color='primary'):
        "A card with a statistics.  Since there is no row/col span class it will take up 1 slot"
        return Card(P(title, cls=TextPresets.muted_sm), H3(value, cls=f'text-{color}'),)
    
    stats = [StatCard(*data) for data in [
                    ("Total Users", "1,234",   "blue-600"),
                    ("Active Now",  "342",     "green-600"),
                    ("Revenue",     "$45,678", "purple-600"),
                    ("Conversion",  "2.4%",    "amber-600")]]
    
    def ChartCard(title): 
        "A card for a chart.  col-span-2 means it will take up 2 columns"
        return Div(cls="col-span-2")( 
            Card(H3(title),Div("Chart Goes Here", cls="h-64 uk-background-muted")))
    chart_cards = [ChartCard(title) for title in ("Monthly Revenue", "User Growth")]
    
    
    sidebar = Form(
        H3("SideBar"),
        LabelRange("Range For Filters", min=0, max=100),
        LabelInput("A search Bar"),
        LabelSelect(map(Option, ["Product Line A", "Product Line B", "Product Line C", "Product Line D"]),
                         label="Choose Product Line"),
        LabelCheckboxX("Include Inactive Users"),
        LabelCheckboxX("Include Users without order"),
        LabelCheckboxX("Include Users without email"),
        # This sidebar will take up 2 rows b/c of row-span-2
        cls='row-span-2 space-y-5'
    )
    
    Container(Grid(sidebar, *stats, *chart_cards, cols=5))
[/code]

# Flexbox

Using Grid for the overall layout, and flex for the individual elements is a powerful pattern. With `MonsterUI` you can do quite a bit without knowing anything about flexbox, which is what will be taught here.

However, flexbox is well worth learning about it in more detail. You will run into situations where you need more flexbox knowledge than is covered here to build your vision. Thankfully you can get that knowledge by playing a fantastic tutorial game called FlexBox Froggy!

## Forms

Often you want to stack things horizontally. You can use the `DivHStacked` component to do this.

`DivHStacked` is a helper function for flexbox and creates a div with these classes by default `cls=(FlexT.block, FlexT.row, FlexT.middle, 'space-x-4')`.

See Source

See Output

### Form with Input Groups

Search Users

Filter Tags

Email List

SubmitCancel

[code]

    def InputGroup(label, placeholder='', button_text='Submit', cls=''):
        # Div H Stacked makes the label and input show up on the same row instead of putting the input on a newline
        return DivHStacked(
            FormLabel(label, cls='whitespace-nowrap'),
            Input(placeholder=placeholder))
    
    Container(
        H3("Form with Input Groups"),
        Form(cls='space-y-4')(
            InputGroup("Search Users", "Enter username..."),
            InputGroup("Filter Tags", "Add tags...", "Add"),
            InputGroup("Email List", "Enter email...", "Subscribe"),
            Div(*(  Button(UkIcon(icon, cls='mr-2'), text) for icon, text in [("rocket", "Submit"), ("circle-x", "Cancel")]), cls='space-x-4')))
[/code]

## Avatar

You can use this same `DivHStacked` to align things like text next to images. And you can use `DivVStacked` to stack things vertically to create design structures you like. `DivVStacked` works by using `cls=(FlexT.block,FlexT.column,FlexT.middle)`

See Source

See Output

John Doe

[email protected]

+1-123-456-7890

[code]

    # DivHStacked makes the a single row so text is to on same line as avatar
    DivHStacked(
        DiceBearAvatar("user"), 
        # DivVStacked stacks things vertically together and centers it with flex
        DivVStacked(
            P("John Doe", cls=TextT.lg),
            P("[email protected]", cls=TextT.muted), 
            P("+1-123-456-7890"), cls=TextT.muted))
[/code]

## Pricing Card

These can be combined with icons and other styling to create larger components like a pricing card.

See Source

See Output

## Pro Plan

### $99

per month

  * Unlimited users

  * 24/7 priority support

  * Custom branding options

  * Advanced analytics dashboard

  * Full API access

  * Priority request queue

Subscribe Now

[code]

    features = [
        "Unlimited users",
        "24/7 priority support",
        "Custom branding options", 
        "Advanced analytics dashboard",
        "Full API access",
        "Priority request queue"
    ]
    
    
    def PricingCard(plan, price, features):
        "Create a polished pricing card with consistent styling"
        return Card(
            DivVStacked( # Center and veritcally stack the plan name and price
                H2(plan),
                H3(price, cls='text-primary'),
                P('per month',cls=TextT.muted),
                cls='space-y-1'),
            # DivHStacked makes green check and feature Li show up on same row instead of newline
            Ul(*[DivHStacked(UkIcon('check', cls='text-green-500 mr-2'), Li(feature)) for feature in features], 
               cls='space-y-4'),
            Button("Subscribe Now", cls=(ButtonT.primary, 'w-full')))
    
    DivVStacked(PricingCard("Pro Plan", "$99", features))
[/code]

## Footer

Or you can combine things to make advanced footers that have titles, organized links, and icons!

In this example we add another flex helper function, `DivFullySpaced`. `DivFullySpaced` is a flex class that puts as much space between items as possible

See Source

See Output

### Company Name

* * *

#### Company

AboutBlogCareersPress Kit

#### Resources

DocumentationHelp CenterStatusContact Sales

#### Legal

Terms of ServicePrivacy PolicyCookie SettingsAccessibility

* * *

© 2024 Company Name. All rights reserved.

[code]

    def FooterLinkGroup(title, links):
        # DivVStacked centers and makes title and each link stack vertically
        return DivVStacked(
            H4(title),
            *[A(text, href=f"#{text.lower().replace(' ', '-')}", cls=TextT.muted)  for text in links])
    
    company = ["About", "Blog", "Careers", "Press Kit"]
    resource = ["Documentation", "Help Center", "Status", "Contact Sales"]
    legal = ["Terms of Service", "Privacy Policy", "Cookie Settings", "Accessibility"]
    
    Container(cls='uk-background-muted py-12')(Div(
        # Company Name and social icons will be on the same row with as much sapce between as possible
        DivFullySpaced( 
            H3("Company Name"),
            # DivHStacked makes the icons be on the same row in a group
            DivHStacked(*[UkIcon(icon, cls=TextT.lead) for icon in 
                          ['twitter', 'facebook', 'github', 'linkedin']])),
        DividerLine(),
        DivFullySpaced( # Each child will be spread out as much as possible based on number of children
            FooterLinkGroup("Company",   company),
            FooterLinkGroup("Resources", resource),
            FooterLinkGroup("Legal",     legal)), 
        DividerLine(),
        P("© 2024 Company Name. All rights reserved.", cls=TextT.lead+TextT.sm),
        cls='space-y-8 p-8'))
[/code]

## Dashboard

See Source

See Output

## Welcome back, Isaac!

Here's what's happening with your projects today.

Total Projects

### 12

+2.5% from last month

Hours Logged

### 164

+12.3% from last month

Tasks Complete

### 64%

-4.1% from last month

Team Velocity

### 23

+8.4% from last month

### Recent Activity

Sarah Chen completed Project Alpha deployment

2h ago

James Wilson commented on Project Beta

4h ago

Maria Garcia uploaded new design files

6h ago

Alex Kumar started Sprint Planning

8h ago

[code]

    def StatsCard(label, value, change):
        color = 'green' if change[0] == '+' else 'red'
        return Card(DivVStacked( # Stacks vertically and centers all elements
            P(label, cls=TextPresets.muted_sm),
            H3(value),
            P(f"{change}% from last month", cls=f"text-{color}-600 text-sm")))
        
    def RecentActivity(user, action, time):
        return DivHStacked( # Makes Avatar and text be on same row
            DiceBearAvatar(user, h=8, w=8),
            P(f"{user} {action}", cls="flex-1"),
            P(time, cls=TextPresets.muted_sm))
        
    DivVStacked( # Centers the entire dashboard layout
        # Page header
        DivVStacked( # Stacks vertically and centers the title/subtitle
            H2("Welcome back, Isaac!"),
            P("Here's what's happening with your projects today.",cls=TextT.muted)),
    
        # DivHStacked puts all the stats cards on the same row
        DivHStacked(*(StatsCard(label, value, change)
            for label, value, change in [
                ("Total Projects", "12", "+2.5"),
                ("Hours Logged", "164", "+12.3"),
                ("Tasks Complete", "64%", "-4.1"),
                ("Team Velocity", "23", "+8.4")]
        )),
    
        # Recent activity
        Card(*(RecentActivity(user, action, time) 
            for user, action, time in [
                ("Sarah Chen", "completed Project Alpha deployment", "2h ago"),
                ("James Wilson", "commented on Project Beta", "4h ago"),
                ("Maria Garcia", "uploaded new design files", "6h ago"),
                ("Alex Kumar", "started Sprint Planning", "8h ago")]),
            header=H3("Recent Activity"),
        ),
        cls="space-y-6"
    )
[/code]

## Columns

Columns are a great for sections that have a lot of text.

See Source

See Output

# Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.

Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor.

[code]

    Container(
        H1("Lorem Ipsum", cls="text-center mb-8"),
    
        # Use 2 columns for the main content
        Div(cls="columns-2 gap-12")(
            P("""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do 
            eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad 
            minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 
            ex ea commodo consequat."""),
    
            DivCentered(cls='mt-8')(
                P("""Duis aute irure dolor in reprehenderit in voluptate velit esse 
                cillum dolore eu fugiat nulla pariatur.""", 
                       cls=(TextT.lg, TextT.bold, TextT.center, TextT.italic, "text-primary"))),
    
            P("""Excepteur sint occaecat cupidatat non proident, sunt in culpa qui 
            officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde 
            omnis iste natus error sit voluptatem accusantium doloremque laudantium."""),
    
            P("""Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit 
            aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem 
            sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor.""")))
[/code]
</doc><doc title="Spacing" desc="Padding &amp; Margin &amp; Spacing, Oh my! (MonsterUI Spacing Guide)"># Padding & Margin & Spacing, Oh my! (MonsterUI Spacing Guide)

This guide will cover some essentials about how to properly space apps and what the differences are between:

  * Padding
  * Margin
  * Spacing
  * Gap

Manipulating the space between components can make a huge difference to the percieved quality of the page. Being able to tweak the spacing can have a big impact!

> Tip: I find it works best to get everything on the page without adjusting spacing much, and adjusting spacing at the end.

## Abreviations:

First a few abbreviations that are helpful to know with tailwind (and a convention we follow in `MonsterUI`).

  * `t`, `b`, `l`, `r` = top, bottom, left, right
  * `p`, `m` = padding, margin
  * `x`, `y` = horizontal, vertical

That means:

  * `mt` means margin on top of the element
  * `px` means padding on the x axis (both left and right)
  * `space-y` means apply spacing on the y axis (both top and bottom)

## Padding vs Margin

Margin applies space to the left of the component, and padding applies space on the left inside of the component.

Please reference the example with cards below:

  * `ml-20` applies space to the left of the card (outside the card)
  * `pl-20` applies space on the left inside of the card (inside the card)

This means that if you want to move the whole thing but keep the actual container unchanged, use margin. If you want to change the container by adding space inside of it, use padding.

See Source

See Output

#### A Simple Card with ml-20

#### A Simple Card with pl-20

[code]

    Grid(
        Card(H4("A Simple Card with ml-20",style='background-color: red'), 
            cls='ml-20'),
        Card(H4("A Simple Card with pl-20", style='background-color: red'),
            cls='pl-20'))
[/code]

## Space vs gap

Spacing and gap are both about setting the space between components.

  * Spacing applies margin to every element except for the first element in a group.
  * Gap creates a gap between every element in flexbox elements and grids.

> Rule of thumb: Use Gap when using grids.

Let's take a look at some grid examples.

#### Grid

See Source

See Output

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

[code]

    Grid(
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        cls='')
[/code]

#### Grid with gap

See Source

See Output

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

[code]

    Grid(
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        cls='gap-4')
[/code]

#### Grid with space

See Source

See Output

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

#### A Simple Card

[code]

    Grid(
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        Card(H4("A Simple Card")),
        cls='space-x-4 space-y-4')
[/code]

### Grid with no gap or space

The first example has no gap or not space applied. As expected this means the cards are flush with each other. Often this is not what you want, because a little space between cards looks much nicer.

### Grid with gap

The second example has the same grid but with gap applied. As youc an see, this gives constent space between all elements of the grid looks great!

### Grid with space

The third example has the same grid but with space applied. As you can see, it's not really what we want. However it's a really good illustration of how space works so let's notice a few things about it:

**X Axis**

  * The first card is flush with the left side of the page (no margin)
  * The card below it isn't flush with the left side of the page (has margin)

**Y Axis**

  * The first card is flush with the heading immediately above it (no margin)
  * The card top it's right isn't flush with the heading above it (has margin)

So `space` applies margin to every element except for the first element in a group!

> Tip: Use your browser developer tools to inspect the examples

Next, let's look at a form example where `gap` isn't a good choice but `space` works beautifully!

See Source

See Output

### My Form

Name

Phone

Email

[code]

    Form(DivCentered(H3("My Form")),
         LabelInput("Name"),
         Grid(LabelInput("Phone"), LabelInput("Email"), cols=2),
         cls='')
[/code]

See Source

See Output

### My Form with gap

Name

Phone

Email

[code]

    Form(DivCentered(H3("My Form with gap")),
         LabelInput("Name"),
         Grid(LabelInput("Phone"), LabelInput("Email"), cols=2),
         cls='gap-y-5')
[/code]

See Source

See Output

### My Form with Spacing

Name

Phone

Email

[code]

    Form(DivCentered(H3("My Form with Spacing")),
         LabelInput("Name"),
         Grid(LabelInput("Phone"), LabelInput("Email"), cols=2),
         cls='space-y-5')
[/code]

### Form with no gap or space

The top form looks a bit scrunched with defaults, but it's certainly passable. There is a bit of a space between the label and it's associated input because of the defaults in MonsterUI.

### Form with gap

The second form with gap is identical to the first. Because we're not in a flex element or a grid, it doesn't do anything at all!

### Form with space

`Space-y-5` adds vertical space between each child which really spreads out the form for a nice aesthetic. If you recall from the grid example, it does not apply this margin to the first element - but in this situation (and many others) we do not want the spacing above the top element (heading) to be the same as the spacing between the form elements.

> Tip: Use your browser developer tools to inspect the examples

# Further reading

For further reading, check out the Tailwind CSS guide, which other users have found to be a useful as an additional guide.
</doc></optional></project>
