Skip to main content

SwiftUI inspired wrapper for FastHTML

Project description

fhswiftui

fhswiftui is a SwiftUI inspired wrapper for FastHTML and tailwind. fhswiftui is built on top of FastHTML and tailwind and will work with all FT components. Tailwind classes and FastHTML features work seamlessly.

FastHTML enables composing HTML apps by nested Python objects and tailwind is a CSS framework that provides standard CSS components. Since tailwind relies heavily on CSS classes to define components as well as include style information, this can quickly become complex and difficult to read.

For example, let’s consider a simple example of a turn in a chat which displays a user’s message with a timestamp. In FastHTML + tailwind, this would look like something:

Section(
    Div(
        Span('04:30:56', cls='text-xs text-muted-foreground'),
        Div('What is the meaning of life?', cls='flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm border-l-4 border-primary italic'),
        cls='flex gap-2 items-center'
    ),
    cls='space-y-6'
)

fhswiftui provides layout and UI components. It also provides property setters that enable specific styling. The same example above using fhswiftui:

HStack(alignment="center")(
    Text('04:30:56').fg("muted-foreground").font(size="xs"),
    VDivider(border_color),
    Div(t.m).padding(left=3, right=3, top=2, bottom=2).font(size="sm")
)

fhswiftui is built on top of FastHTML and tailwind and will work with all FT components. Tailwind classes and FastHTML features work seamlessly.

Installation

Install latest from pypi

$ pip install fhswiftui

Why build yet another toolkit

Tailwind CSS gets complicated quickly

This slightly more comprhensive demo illustrates how per element classes can explode quickly and become difficult to read.

<div class="flex flex-col items-start gap-6 p-6">
  <div class="flex flex-row items-start gap-4 p-4 bg-gray-50 rounded shadow">
    <div class="flex flex-col items-start gap-1">
<span class="text-2xl font-bold">fhswiftui Demo</span><span class="text-sm font-normal text-gray-500">SwiftUI-inspired layouts with Basecoat styling</span>    </div>
    <div class="flex-grow"></div>
<button class="btn btn-outline btn-sm">Settings</button>  </div>
  <div class="flex flex-row items-start gap-4">
    <article class="card">
      <header>
        <h3 class="font-semibold">Typography</h3>
      </header>
      <section>
        <div class="flex flex-col items-start gap-2">
          <span class="text-2xl font-bold">Title</span>
          <span class="text-xl font-semibold">Headline</span>
          <span class="text-base font-normal">Body text goes here</span>
          <span class="text-sm font-normal text-gray-300">Caption for details</span>
          <span class="text-xs font-normal text-gray-500">Footnote</span>        
        </div>
      </section>
    </article>
    <article class="card">
      <header>
        <h3 class="font-semibold">Form Controls</h3>
      </header>
      <section>
        <div class="flex flex-col items-start gap-3">
          <div class="field">
            <label class="label">Email</label>            
            <input name="email" placeholder="you@example.com" class="input">
          </div>
          <div class="field">
            <label class="label">Password</label>            
            <input name="password" placeholder="••••••••" type="password" class="input">
          </div>
          <div class="flex flex-row items-start gap-2">
            <button class="btn btn-outline">Cancel</button><button class="btn btn-primary">Submit</button>          
          </div>
        </div>
      </section>
    </article>
  </div>
  <div class="flex flex-row items-start gap-3">
    <span class="badge">Active</span><span class="badge badge-destructive">Error</span>  
  </div>
  <div class="border-t w-full my-2"></div>
  <span class="text-xl font-semibold">Semantic Colors</span>  
  <div class="flex flex-row items-start gap-2">
    <span class="text-gray-900">Primary</span>
    <span class="text-gray-500">Secondary</span>
    <span class="text-blue-600">Accent</span>
    <span class="text-green-600">Success</span>
    <span class="text-amber-500">Warning</span>
    <span class="text-red-600">Danger</span>  
  </div>
</div>

Using semantic expressions preserves readablity

By using semantic expressions, this preserves the intent of the designer. Changes become safer.

Notice, that we coexist with FastHTML so it is always possible to dive into raw Tailwind CSS if needed.

We believe, this encourages composiblity. Real world applications would define components that could be composed together in a light scaffolding.

from fasthtml.components import *
from fhswiftui import *


p = mk_previewer()

html = VStack(spacing=6)(
    
    HStack(spacing=4)(
        VStack(spacing=1)(
            Text("fhswiftui Demo").font(Font.Title),
            Text("SwiftUI-inspired layouts with Basecoat styling").font(Font.Caption).fg(Color.Secondary),
        ),
        Spacer(),
        Button("Settings", cls="btn btn-outline btn-sm"),
    ).padding().bg(Color.Surface).corner_radius().shadow(),
    
    # Feature showcase in cards
    HStack(spacing=4)(        
        Article(cls="card")(
            Header(H3("Typography", cls="font-semibold")),
            Section(
                VStack(spacing=2)(
                    Text("Title").font(Font.Title),
                    Text("Headline").font(Font.Headline),
                    Text("Body text goes here").font(Font.Body),
                    Text("Caption for details").font(Font.Caption).fg(Color.Muted),
                    Text("Footnote").font(Font.Footnote).fg(Color.Secondary),
                )
            )
        ),
        
        # Card 2: Form elements
        Article(cls="card")(
            Header(H3("Form Controls", cls="font-semibold")),
            Section(
                VStack(spacing=3)(
                    Div(cls="field")(
                        Label("Email", cls="label"),
                        TextField("email", placeholder="you@example.com", cls="input"),
                    ),
                    Div(cls="field")(
                        Label("Password", cls="label"),
                        TextField("password", placeholder="••••••••", type="password", cls="input"),
                    ),
                    HStack(spacing=2)(
                        Button("Cancel", cls="btn btn-outline"),
                        Button("Submit", cls="btn btn-primary"),
                    ),
                )
            )
        ),
    ),
    
    # Status row
    HStack(spacing=3)(
        Span("Active", cls="badge"),
        Span("Error", cls="badge badge-destructive"),
    ),
    
    # Divider
    HDivider(),
    
    # Color palette showcase
    Text("Semantic Colors").font(Font.Headline),
    HStack(spacing=2)(
        Text("Primary").fg(Color.Primary),
        Text("Secondary").fg(Color.Secondary),
        Text("Accent").fg(Color.Accent),
        Text("Success").fg(Color.Success),
        Text("Warning").fg(Color.Warning),
        Text("Danger").fg(Color.Danger),
    ),
).padding(6)

p(html)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fhswiftui-0.0.5.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fhswiftui-0.0.5-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file fhswiftui-0.0.5.tar.gz.

File metadata

  • Download URL: fhswiftui-0.0.5.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for fhswiftui-0.0.5.tar.gz
Algorithm Hash digest
SHA256 707ce02606f430bb3a847e622840454f738dfd7003db25d53ff4088831aca5b1
MD5 590b526508571cf2967701bbab6c24dd
BLAKE2b-256 97a989b734148a5aad8c55178ab7033c1d699a52a4fea6f26bcefc8bde0f8ec2

See more details on using hashes here.

File details

Details for the file fhswiftui-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: fhswiftui-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for fhswiftui-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 210b3c861aaa0ac2f328d42a862404a6118f6252a57cb75e8348d6eda3ac87a7
MD5 1314539e8d064d606a9f24ef1ad793ef
BLAKE2b-256 8be0217abbc7cd1e25022f70aed8cf9453ab18d615904b928e7cf75ec6c6ba7c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page