SwifTML allows you to build HTML pages or fragments directly in Swift. Part of the Fly framework.
Download the included playground to see how it works.
// TODO code sample
The built-in Tag definitions are auto-generated, with some pre-defined tag helpers that are customized with special arguments and behavior.
Examples of custom tags are currently Link
, Img
, and Stylesheet
, with more ideas written down.
You are encouraged to define your own tag helpers with an extension:
// TODO code sample
There are some helpers to control the whitespace between elements, you have to define these yourself in your project. See the playground for a usage example.
prefix operator <<
prefix func <<(tag: Tag) -> Tag {
var tag = tag
tag.whitespace.combine(.Pre)
return tag
}
postfix operator >>
postfix func >>(tag: Tag) -> Tag {
var tag = tag
tag.whitespace.combine(.Post)
return tag
}
prefix operator <<>>
prefix func <<>>(tag: Tag) -> Tag {
var tag = tag
tag.whitespace = .All
return tag
}
Writing HTML tags by hand is for suckers.
Using SwifTML embraces and leans on the compiler to make writing HTML a type-safe activity. I have a healthy distrust of String use when not necessary. This approach could also make it easy to enforce semantically valid HTML output.
Other templating solutions require more indirection and give up type-safety/compiler benefits.
Cues have been taken from the tag helpers in Rails and templating languages like Slim.
We'll see if this is a good idea long-term, but I find this preferable to existing Swift templating solutions that I'm aware of.
That's not a question? Just go use Stencil.
There's some weird and non-standard stuff going on here:
- The tag functions start with an uppercase character, unlike most functions
- Each pre-defined tag has two function variants for taking content:
- as the first argument for simple content
- as the last argument for defining a list of sub-tags
- Each tag function pair has both class and instance variants
- Tag functions are auto-generated
These decisions came out of trying to balance aesthetic desires and technical factors and limitations.
I want it as seamless as possible to use SwifTML anywhere without making the functions globally
available. The function definitions for tags look more like a struct, but I don't actually want
them to be individual structs. One benefit here is they each return an instance of the Tag
struct.
- Refactor arguments to take enum cases for attributes instead of each type of argument having its own argument pair. Something like:
Div("content", attributes: .data("name", "value"), .id("page-123"), .class("button"), .classes(["one", "two", "three"]))
-> <div data-name="value", id="page-123", class="button one two three">content</div>
// class and classes would be properly combined, in addition to style classes and other similar things.
- Experiment with short-hand syntax (ZenCoding/Emmet style)? Like
Tag("ul.listClass>li#itemID", "hello")
outputting<ul class="listClass"><li id="itemID">hello</li></ul>
. This gives up too much safety, but something like that might be interesting.