van-jsx
A small 1kb JSX libs for building SSR/UI with vanilla and hooks.
- Control JSX with vanilla-js and hooks.
- Fast SSR without rehydration or re-render.
- TypeScript support out of the box.
- No virtual-dom.
- Router with SSR support.
Install
Npm
npm i van-jsx
Deno
import {...} from "https://deno.land/x/van_jsx/mod.ts";
Usage
/* @jsx h */
/* @jsxFrag h.Fragment */
import { h, render, use } from "van-jsx";
const Counter = () => {
const state = { count: 0 };
const Button = use.button();
const Count = use.span();
use.mount(() => {
// ready to use vanilla.
Button.onclick = () => {
Count.innerText = (state.count += 1).toString();
};
});
return (
<Button>
Click Me <Count>{state.count}</Count>
</Button>
);
};
render(<Counter />, document.getElementById("root"));
// No problem
// render(
// <>
// <Counter />
// <Counter />
// <Counter />
// </>,
// document.getElementById("root"),
// );
SSR
/* @jsx h */
/* @jsxFrag h.Fragment */
import { h, initSSR, rewind } from "van-jsx";
import App from "./app.tsx";
// example using express
app.get("/", (req, res) => {
initSSR();
const html = (
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My App</title>
</head>
<body>
<App />
<script src="/client.js"></script>
</body>
</html>
);
res.send(html);
});
// on the client interactive
rewind(<App />);
Router
import { createRouter, Link } from "van-jsx/router";
const App: FC<{ path?: string }> = ({ path }) => {
const Route = createRouter({ name: "app", ssr_path: path });
return (
<>
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
</nav>
<Route path="/" component={() => <Home />} />
<Route path="/about" component={() => <About />} />
</>
);
};
Use
use.[HTMLElement]
Hook HTMLElement to markup.
use.element
Hook HTMLElement / FunctionComponent to markup.
use.mount
Access Dom after render.
Options Hook
Options.elem
Attach where element is created.
options.elem = (data) => {
console.log(data);
};
Options.fc
Attach where FunctionComponent is created.
options.fc = (data) => {
console.log(data);
};
Lazy
const Home = lazy(() => import("./home.tsx"));
Example Todo App
const Item: FC<{ name: string }> = (props) => {
const TodoItem = use.li();
const Remove = use.button();
use.mount(() => {
Remove.onclick = () => TodoItem.remove();
});
return (
<TodoItem>
<span>{props.name}</span>
<Remove>remove</Remove>
</TodoItem>
)
}
const Todo: FC<{ data: string[] }> = (props) => {
// inital state from server
const state = { todos: props.data };
const Form = use.form();
const TodoInput = use.input();
const TodoList = use.div();
use.mount(() => {
Form.onsubmit = (e) => {
e.preventDefault();
TodoList.append(<Item name={TodoInput.value}/>);
TodoInput.value = "";
TodoInput.focus();
};
});
return (
<>
<h1>Welcome Todo</h1>
<Form>
<TodoInput placeholder="text..." />
<button type="submit">Submit</button>
</Form>
<TodoList>{state.todos.map((name) => <Item name={name}/>)}</TodoList>
</>
);
};