hytypemedia
Version:
Minimal typed HTML templating helpers for Hono/Workers/HTMX. JSX-free, type-safe HTML generation with automatic escaping.
372 lines (270 loc) • 8.81 kB
Markdown
# HyTypeMedia
[](https://www.npmjs.com/package/hytypemedia)
[](https://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
Minimal typed HTML templating helpers specifically designed for **Hono**, **Cloudflare Workers**, and **HTMX**. A JSX-free approach to HTML templating that generates safe, escaped HTML strings with full TypeScript support.
## Features
- **Type-Safe**: Full TypeScript support with IntelliSense for all HTML elements and attributes
- **Secure**: Automatic HTML escaping prevents XSS attacks
- **Minimal**: Zero dependencies, optimized for edge runtimes
- **Complete**: Support for all HTML5 elements (67+ elements)
- **Targeted**: Built specifically for Hono/Workers/HTMX workflows
- **Modern**: ESM-first with tree-shaking support
## Quick Start
```bash
npm install hytypemedia
```
```typescript
import { div, h1, p, button, html, head, title, body } from 'hytypemedia';
// Simple elements
const greeting = h1('Hello, World!');
// → <h1>Hello, World!</h1>
// Elements with attributes
const styledDiv = div({ class: 'container', id: 'main' }, 'Content');
// → <div class="container" id="main">Content</div>
// Complete HTML documents
const page = html({ lang: 'en' },
head(title('My Page')),
body(
h1('Welcome'),
p('This is a typed HTML template.')
)
);
```
## Core Concepts
### Element Functions
Every HTML tag has a corresponding function:
```typescript
import { div, span, a, img, input } from 'hytypemedia';
div('Hello') // <div>Hello</div>
span({ class: 'highlight' }, 'Text') // <span class="highlight">Text</span>
a({ href: '/home' }, 'Home') // <a href="/home">Home</a>
img({ src: 'logo.png', alt: 'Logo' }) // <img src="logo.png" alt="Logo">
input({ type: 'email', required: true }) // <input type="email" required>
```
### Automatic Escaping
All content is automatically escaped for security:
```typescript
import { div, raw } from 'hytypemedia';
// Automatically escaped
div('<script>alert("xss")</script>')
// → <div><script>alert("xss")</script></div>
// Explicit raw HTML (use only with trusted content)
div(raw('<strong>Bold</strong>'))
// → <div><strong>Bold</strong></div>
```
### Class and Style Normalization
```typescript
import { div } from 'hytypemedia';
// String classes
div({ class: 'btn primary' })
// → <div class="btn primary"></div>
// Array classes
div({ class: ['btn', 'primary'] })
// → <div class="btn primary"></div>
// Object classes (conditional)
div({ class: { btn: true, primary: true, disabled: false } })
// → <div class="btn primary"></div>
// Object styles (camelCase → kebab-case)
div({ style: { fontSize: '16px', backgroundColor: 'blue' } })
// → <div style="font-size:16px;background-color:blue"></div>
```
### Content Types
Supports multiple content types:
```typescript
import { div } from 'hytypemedia';
div('string') // Strings
div(42) // Numbers
div(['hello', ' ', 'world']) // Arrays (flattened)
div(null) // null/undefined (ignored)
div(raw('<em>html</em>')) // SafeHtml objects
```
## Advanced Usage
### Document Structure with Direct Nesting
```typescript
import { html, head, meta, title, body, h1, p } from 'hytypemedia';
const document = html({ lang: 'en' },
head(
meta({ charset: 'utf-8' }),
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1' }),
title('My App')
),
body(
h1('Welcome to My App'),
p('Built with HyTypeMedia')
)
);
```
### Forms and Inputs
```typescript
import { form, label, input, textarea, button, select, option } from 'hytypemedia';
const contactForm = form({ method: 'post', action: '/contact' },
label({ for: 'email' }, 'Email:'),
input({
type: 'email',
id: 'email',
name: 'email',
required: true
}),
label({ for: 'message' }, 'Message:'),
textarea({
id: 'message',
name: 'message',
rows: 4
}),
select({ name: 'country' },
option({ value: 'us' }, 'United States'),
option({ value: 'uk' }, 'United Kingdom')
),
button({ type: 'submit' }, 'Send Message')
);
```
### Data Attributes and ARIA
```typescript
import { button, div } from 'hytypemedia';
// Data attributes
const component = div({
'data-testid': 'user-card',
'data-user-id': 123,
'data-active': 'true'
});
// ARIA attributes
const accessibleButton = button({
'aria-label': 'Close dialog',
'aria-expanded': false,
'aria-controls': 'menu'
}, '×');
```
### Custom Elements
```typescript
import { customElement } from 'hytypemedia';
const myCustomElement = customElement('my-component');
const result = myCustomElement({ prop: 'value' }, 'Content');
// → <my-component prop="value">Content</my-component>
```
## Framework Integration
### Hono Example
```typescript
import { Hono } from 'hono';
import { div, h1, p, a } from 'hytypemedia';
const app = new Hono();
app.get('/', (c) => {
const html = div({ class: 'container' },
h1('Welcome to My Site'),
p('Built with Hono and HyTypeMedia'),
a({ href: '/about' }, 'Learn More')
);
return c.html(html);
});
```
### HTMX Integration
```typescript
import { div, button, form, input } from 'hytypemedia';
const htmxForm = form({
'hx-post': '/api/users',
'hx-target': '#user-list',
'hx-swap': 'beforeend'
},
input({ type: 'text', name: 'name', placeholder: 'Enter name' }),
button({ type: 'submit' }, 'Add User')
);
const htmxButton = button({
'hx-get': '/api/data',
'hx-target': '#content',
'hx-indicator': '#spinner'
}, 'Load Data');
```
## API Reference
### Element Functions
All HTML5 elements are available as functions:
**Text Content**: `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `p`, `span`, `div`, `a`, `strong`, `em`, `code`, etc.
**Form Elements**: `form`, `input`, `textarea`, `select`, `option`, `button`, `label`, `fieldset`, `legend`
**Table Elements**: `table`, `thead`, `tbody`, `tfoot`, `tr`, `th`, `td`, `caption`, `colgroup`, `col`
**Media Elements**: `img`, `video`, `audio`, `source`, `track`, `canvas`, `svg`
**Semantic Elements**: `main`, `section`, `article`, `aside`, `header`, `footer`, `nav`, `figure`, `figcaption`
**Meta Elements**: `head`, `title`, `meta`, `link`, `style`, `script`, `base`
### Helper Functions
#### `Fragment(...children)`
Combines multiple elements without a wrapper:
```typescript
Fragment(h1('Title'), p('Content'))
// → <h1>Title</h1><p>Content</p>
```
#### `doctype()`
Returns HTML5 doctype:
```typescript
doctype()
// → <!doctype html>
```
#### `raw(html)`
Marks HTML as safe (no escaping):
```typescript
raw('<strong>Bold</strong>')
// → <strong>Bold</strong>
```
#### `safeText(text)`
Explicitly escapes text:
```typescript
safeText('<script>')
// → <script>
```
#### `customElement(tagName)`
Creates a custom element function:
```typescript
const myEl = customElement('my-element');
myEl({ prop: 'value' }, 'content')
// → <my-element prop="value">content</my-element>
```
### Types
```typescript
// Main function type
type HtmlFunction = (...args: [GlobalAttrs, ...Content[]] | Content[]) => string;
// Global attributes
type GlobalAttrs = {
id?: string;
class?: ClassValue;
style?: StyleValue;
role?: string;
tabindex?: number;
title?: string;
[k: `data-${string}`]: unknown;
[k: `aria-${string}`]: unknown;
} & Record<string, unknown>;
// Class values
type ClassValue = string | string[] | Record<string, boolean>;
// Style values
type StyleValue = string | Record<string, string | number>;
// Content types
type Content = string | number | boolean | null | undefined | SafeHtml | Content[];
```
## Browser Support
- **Node.js**: >= 18.0.0
- **TypeScript**: >= 4.9.0
- **Runtimes**: Node.js, Cloudflare Workers, Deno, Bun
- **Bundlers**: Vite, esbuild, Rollup, Webpack, Parcel
## Contributing
1. Fork the repository
2. Create your feature branch: `git checkout -b feature/amazing-feature`
3. Run tests: `npm test`
4. Commit your changes: `git commit -m 'Add amazing feature'`
5. Push to the branch: `git push origin feature/amazing-feature`
6. Open a Pull Request
## Development
```bash
# Install dependencies
npm install
# Run tests
npm test
# Build
npm run build
# Type checking
npm run typecheck
# Linting
npm run lint
```
## License
MIT © [Terence Stupple](https://github.com/telstupps)
## Related Projects
- [Hono](https://hono.dev/) - Web framework for edge runtimes
- [HTMX](https://htmx.org/) - HTML over the wire
- [Cloudflare Workers](https://workers.cloudflare.com/) - Edge computing platform