Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/reggi/htmx-components

🧩 Async HTMX + JSX
https://github.com/reggi/htmx-components

deno deno-deploy htmx

Last synced: 3 months ago
JSON representation

🧩 Async HTMX + JSX

Lists

README

        

# HTMX Components

I think of it as:
1. Async Server Components
2. HTMX in JSX (Fully typed JSX for all HTMX attributes without the `hx` prefix.)
3. Dynamic routing / nesting / serving (no files / folders)

To run all the examples below in one server run:

```bash
deno task all-examples
```

## "Click To Edit" Example

This example acts as the "rosetta stone" it's a near 1:1 with the first example in the HTMX docs:

* Start the server `deno task click-to-edit`
* Original HTMX code found here: https://htmx.org/examples/click-to-edit/
* Open the code on github https://github.com/reggi/htmx-components/blob/main/examples/1.click-to-edit.tsx
* Open the file locally `code ./examples/1.click-to-edit.tsx`
* Navigate to http://localhost:8000/contacts/1
* Navigate to http://localhost:8000/contacts/1/edit
* Web https://reggi-htmx-components.deno.dev/contacts/1
* Web https://reggi-htmx-components.deno.dev/contacts/1/edit

## "Bulk Update" Example

* Start the server `deno task bulk-update`
* Original HTMX code found here: https://htmx.org/examples/bulk-update/
* Open the code on github https://github.com/reggi/htmx-components/blob/main/examples/2.bulk-update.tsx
* Open the file locally `code ./examples/2.bulk-update.tsx`
* Navigate to http://localhost:8000/people
* Web https://reggi-htmx-components.deno.dev/people

## "Click To Load" Example

* Start the server `deno task click-to-load`
* Original HTMX code found here: https://htmx.org/examples/click-to-load/
* Open the code on github https://github.com/reggi/htmx-components/blob/main/examples/3.click-to-load.tsx
* Open the file locally `code ./examples/3.click-to-load.tsx`
* Navigate to http://localhost:8000/click-to-load
* Web https://reggi-htmx-components.deno.dev/click-to-load

## Philosophy / Anatomy / Ergonomics

This is an HTMX component:

```tsx
const Contact = component('/contacts/:identifier', async ({ identifier }: { identifier: string }, ctx) => {
const { firstName, lastName, email } = await getOrUpdate({ identifier }, ctx.request)
return (

First Name: {firstName}

Last Name: {lastName}

Email: {email}


Click To Edit


)
})
```

It's a wrapped component that couples the `URLPattern` route with the markup. This is an essential philosphy of HTMX Components, and complements HTMX well, why? Because HTMX is HTML over the wire, in HTMX the endpoints themselves are "components". Deeply coupling the markup with the route is a no-brainer, this also provides a number of benifits.

Did you know that the JavaScript `string` (like the primative) object has a [method called `link`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/link), like... (`'hello".link()`) which returns a DOM element 🤯. Obviously this is a odd feature for a programming language but not _the_ programmming language of the web. It's long deprecated now but it gives us a glimpse into the fossil record of what was going through the early developers of the webs minds. While I have a love / hate relationship with this `link` method, I'm paying homage to it in this library. Every HTMX Component returns a normal JSX element totally as you'd expect except with two exceptions, they can run async code (like next.js / react 18), they also return extra "function" properties that return other JSX elements. That allows you to target them in specific typesafe ways. For instance you can do `Contact.href`, now this may not be great if there's a param in the url, but for that there's `Contact.getPath({ typesafety! })`, there's also nested JSX elements like `` and ``, these allow you to target the route of a component in a typesafe way.

---

Default Example (more chaotic example)

* `deno task start`
* http://localhost:8000/nest/bob
* http://localhost:8000/nest/alice/matt
* http://localhost:8000/registry/@reggi/alicebob

# Default Example:

![](./screenshots/J9x_9P1Y.jpg)
![](./screenshots/DR2PrQJK.png)
w
```tsx
import { HTMX, HTMXComponents, serve, Fragment } from "./mod.tsx"

// http://localhost:8000/registry/@reggi/alicebob
const { component, routes, context } = new HTMXComponents('@reggi/alicebob')

const Alice = component('/alice/:name', async ({ name }: { name: string}, ctx) => {
const _name = await Promise.resolve(name)
const req = new URL(ctx.request.url)
const query = req.searchParams.get('meow')
return (


This is {_name} + {ctx.data.love} {ctx.id} {query}


)
})

const Bob = component('/bob', async (_p, ctx) => {
const name = await Promise.resolve('bob')
return (

Different
Alice Button
Alice Link
Alice Link

This is {name} {ctx.id}



)
})

const e = context({
nestPath: '/nest',
love: 'lauriel'
})

await serve(e)

// or
// export default routes // like express routes
```