Skip to content

Commit

Permalink
readme
Browse files Browse the repository at this point in the history
  • Loading branch information
sliemeobn committed Jun 21, 2024
1 parent 5087824 commit be8f309
Showing 1 changed file with 79 additions and 18 deletions.
97 changes: 79 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Elementary
# Elementary: HTML Templating in Pure Swift

**Typesafe HTML templating in pure Swift.**
**A modern and efficient HTML rendering library - inspired by SwiftUI, built for the web.**

_🚧 Work in progress 🚧_
[Examples](#play-with-it) | [Motivation](#motivation-and-other-packages)

```swift
struct MainPage: HtmlDocument {
Expand Down Expand Up @@ -49,7 +49,7 @@ Check out the [Hummingbird example app](https://github.com/sliemeobn/elementary/

## Lightweight and fast

Elementary renders straight to text, ideal for serving generated HTML from a [Hummingbird](https://github.com/hummingbird-project/hummingbird) or [Vapor](https://vapor.codes/) app.
Elementary renders straight to text, ideal for serving generated HTML from a [Hummingbird](https://github.com/hummingbird-project/hummingbird) or [Vapor](https://vapor.codes/) server app.

Any element can be rendered individually, ideal for [htmx](https://htmx.org/).

Expand All @@ -61,7 +61,7 @@ let fragment = FeatureList(features: ["Anything conforming to Html can be render
// <ul><li>Anything conforming to Html can be rendered</li></ul>
```

Optionally you can render formatted output, or stream the rendered Html without collecting it in a string first.
Optionally you can render formatted output, or stream the rendered HTML without collecting it in a string first.

```swift
print(
Expand All @@ -82,6 +82,10 @@ print(
MainPage().render(into: responseStream)
```

Elementary has zero dependencies (not even Foundation) and does not use runtime reflection or existential containers (there is not a single `any` in the code base).

By design, it does not come with a layout engine, reactive state tracking, or built-in CSS styling: it just renders HTML.

## Clean and composable

Structure your HTML with a SwiftUI-inspired composition API.
Expand Down Expand Up @@ -119,21 +123,78 @@ struct ListItem: Html {
}
```

## Framework agnostig and unopinionated
## First class attribute handling

Elementary utilizes Swift's powerful generics to provide an attribute system that knows what goes where. Every element knows which Tag it is for.

As in HTML, attributes go right after the "opening tag".

```swift
// staying close to HTML syntax really helps
div(.data("hello", value: "there")) {
a(.href("/swift"), .target(.blank)) {
img(.src("/swift.png"))
span(.class("fancy")) { "Click Me" }
}
}
```

Attributes can also be altered by using the modifier syntax, this allows for easy handling of conditional attributes.

```swift
div {
p { "Hello" }
.attributes(.id("maybe-fancy"))
.attributes(.class("fancy"), when: isFancy)
}
```

By exposing the tag type of `content`, attributes will fall through and be applied correctly.

```swift
struct Button: Html {
var text: String

// by exposing the HtmlTag type information...
var content: some Html<HtmlTag.input> {
input(.type(.button), .value(text))
}
}

div {
// ... Button will know it really is an <input> element ...
Button(text: "Hello")
.attributes(.autofocus) // ... and pass on any attributes
}
```

As a sensible default, _class_ and _style_ attributes are merged (with a blank space or semicolon respectively). All other attributes are overwritten by default.

### 🚧 Work in progress 🚧

The list of built-in attributes is quite short still, but adding them is quite easy (and can be done in external packages as well).

Feel free to open a PR with additional attributes that are missing from the model.

## Motivation and other packages

[Plot](https://github.com/JohnSundell/Plot), [HTMLKit](https://github.com/vapor-community/HTMLKit), and [Swim](https://github.com/robb/Swim) are all excellent packages for doing a similar thing.

My main motivation for Elementary was to create an experience like these, but

Elementary has zero dependencies (not even Foundation) and does not use runtime reflection or existentials (there is not a single `any` in the code base).
- stay true to HTML tag names and conventions (including the choice of lowercase types)
- avoid allocating an intermedate structure and go straght to text
- using generics to stay away from allocating a ton of lists of existential `any`s
- have a list of attributes go before the content block
- provide _attribute fallthrough_ and merging
- zero dependencies on other packages

It does not come with a layout engine, reactive state tracking, or built-in CSS styling: it just renders HTML.
[Tokamak](https://github.com/TokamakUI/Tokamak) is an awesome project and very inspiring. It can produce HTML, but it's main focus is on a very different beast. Check it out!

## 🚧 Work in progress 🚧
[swift-html](https://github.com/pointfreeco/swift-html) and [swift-dom](https://github.com/tayloraswift/swift-dom) will produce HTML nicely, but they use a different syntax for composing HTML elements.

TODO:
## Future directions

- finish readme (explain attribute mering, add motivation, add links and acknowledgements to other packages)
- push to SPI
- include badges in readme
- add code comments and documentation build (SPI)
- add public API to control attribute merging/overrides
- add more common attributes (definitely the on\* events)
- fix formatted rendering, improve API
- share tailwind intelli sense trick
- Try out a **_hummingbird + elementary + htmx + tailwind_** stack for fully-featured web apps (without too much client javascript or wasm)
- Experiment with an `AsyncHtml` type, that can include `await` in bodies and stream html and an async sequence
- Experiment with embedded swift for wasm and bolt a lean state tracking/reconciler for reactive DOM manipulation on top

0 comments on commit be8f309

Please sign in to comment.