https://github.com/swlkr/shtml
Yet another ssr only jsx implementation in rust
https://github.com/swlkr/shtml
Last synced: 9 months ago
JSON representation
Yet another ssr only jsx implementation in rust
- Host: GitHub
- URL: https://github.com/swlkr/shtml
- Owner: swlkr
- Created: 2024-05-01T00:22:56.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-26T00:09:02.000Z (11 months ago)
- Last Synced: 2025-03-26T06:11:16.501Z (10 months ago)
- Language: Rust
- Size: 44.9 KB
- Stars: 45
- Watchers: 2
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# shtml
shtml is a rust library for rendering html.
## Installation
```
cargo add --git https://github.com/swlkr/shtml shtml
```
## Examples
Just write or copy/paste plain old html
```rust
use shtml::{html, Elements, Component, Render};
let result = html! {
shtml the s is silent
}
.to_string();
```
Get this back in the result var
```html
shtml the s is silent
```
Attrs work like you would expect
```rust
let class = "flex items-center h-full";
let result = html! {
}.to_string();
//
```
Pass in rust exprs in curlies just make sure they impl `Render`
```rust
let x = 1;
let result = html! {
{x} }.to_string();
//
1
```
Strings get escaped
```rust
let x = "alert(\"pwned\")";
let result = html! {
{x} }.to_string();
//
<script>alert("pwned")</script>
```
Components work like jsx
```rust
#![allow(non_snake_case)]
fn HStack(elements: Elements) -> Component {
html! {
{elements} }
}
let component = html! {
1
2
3
}.to_string();
//
1
2
3
```
Attrs with components work as well
```rust
#![allow(non_snake_case)]
fn Hypermedia(target: &str) -> Component {
html! {
}
}
let x = "body";
let result = html! { }.to_string();
//
```
Nested components
```rust
#![allow(non_snake_case)]
fn HStack(elements: Elements) -> Component {
html! {
{elements} }
}
fn VStack(elements: Elements) -> Component {
html! {
{elements} }
}
let component = html! {
1
2
}.to_string();
//
1
2
```
Attrs + nested components
```rust
fn Heading(class: &str, els: Elements) -> Component {
html! {
{els}
}
}
let result = html! {
How now brown cow
}.to_string();
//
How now brown cow
```
Fragments just pass through their children
```rust
#![allow(non_snake_case)]
fn HStack(elements: Elements) -> Component {
html! {
{elements} }
}
fn VStack(elements: Elements) -> Component {
html! {
{elements} }
}
let component = html! {
<>
1
2
>
}.to_string();
//
1
2
```
The `Render` trait is only implemented for `Vec`
```rust
#![allow(non_snake_case)]
fn List(elements: Elements) -> Component {
html! {
- {elements}
}
fn Item(elements: Elements) -> Component {
html! {
}
let items = vec![1, 2, 3];
let result = html! {
{
items
.iter()
.map(|i| html! {
{i}
})
.collect::>()
}
}.to_string();
//
- 1
- 2
- 3
```
# Feature flags
- chaos
The `chaos` feature flag requires that you annotate all component functions with a `#[component]` macro attribute and allows you to specify any attr order:
```rust
#[component]
fn Chaos(a: &str, b: u8, c: String) -> Component {
html! {
}
let result = html! { }.to_string();
//
// without the chaos feature flag you need to specify the attrs
// in the same order as the fn args
html! {
}
```
# Tips and tricks
- [leptosfmt](https://github.com/bram209/leptosfmt) with this override `rustfmt = { overrideCommand = ["leptosfmt", "--stdin", "--rustfmt", "--override-macro-names", "html"] }`
- [tree-sitter-rstml](https://github.com/rayliwell/tree-sitter-rstml) for html autocomplete inside of html! macros
For helix users: the html! macro should just work and have correct syntax highlighting and autocomplete with the default html lsp + tailwind if that's your jam
```toml
[language-server.tailwind-ls]
command = "tailwindcss-language-server"
args = ["--stdio"]
[language-server.tailwind-ls.config]
tailwindCSS = { experimental = { classRegex = ["class=\"(.*)\""] } }
[[language]]
name = "rust"
language-servers = ["rust-analyzer", "vscode-html-language-server", "tailwind-ls"]
```