Skip to content

Commit c11e47c

Browse files
authored
wip: define elements
1 parent 7c7dda3 commit c11e47c

File tree

5 files changed

+125
-36
lines changed

5 files changed

+125
-36
lines changed

README.md

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
# Template Custom Element
1+
# HTMX Validate Element
22

3-
[![Node CI](https://github.com/ZEISS/template-element/actions/workflows/main.yml/badge.svg)](https://github.com/ZEISS/template-element/actions/workflows/main.yml)
3+
[![Node CI](https://github.com/ZEISS/htmx-validate/actions/workflows/main.yml/badge.svg)](https://github.com/ZEISS/htmx-validate/actions/workflows/main.yml)
44
[![Taylor Swift](https://img.shields.io/badge/secured%20by-taylor%20swift-brightgreen.svg)](https://twitter.com/SwiftOnSecurity)
55
[![Volkswagen](https://auchenberg.github.io/volkswagen/volkswargen_ci.svg?v=1)](https://github.com/auchenberg/volkswagen)
6-
[![GitHub License](https://img.shields.io/github/license/zeiss/template-element)]
6+
[![GitHub License](https://img.shields.io/github/license/ZEISS/htmx-validate)]
77

8-
This is a template for creating a custom element using the [Web Component API](https://developer.mozilla.org/en-US/docs/Web/Web_Components).
8+
This is a simple example of how to use HTMX to validate a form element.
9+
10+
## Getting Started
11+
12+
`htmx-validate` is a simple example of how to use HTMX to validate a form element.
13+
14+
```html
15+
<div htmx-error-for="email-input" is="htmx-validate"></div>
16+
```
17+
18+
The element listens for the following events.
19+
20+
* `htmx-validate:error` - Triggered when the input is invalid.
21+
* `htmx-validate:success` - Triggered when the input is valid.
922

1023
## License
1124

examples/index.html

+40-20
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,42 @@
11
<!doctype html>
2-
<html>
3-
<head>
4-
<title>example-element examples</title>
5-
<link href="https://unpkg.com/[email protected]/dist/out.css" rel="stylesheet">
6-
</head>
7-
<body>
8-
<div class="container py-4">
9-
<example-element></example-element>
10-
</div>
11-
<script>
12-
const script = document.createElement('script')
13-
if (window.location.hostname.endsWith('github.io') || window.location.hostname.endsWith('github.com')) {
14-
script.src = "https://unpkg.com/example-element@latest/dist/index.js"
15-
} else {
16-
script.src = "../dist/index.js"
17-
}
18-
script.type = 'module'
19-
document.body.appendChild(script)
20-
</script>
21-
</body>
2+
<html data-theme="light">
3+
4+
<head>
5+
<title>example-element examples</title>
6+
<link href="https://unpkg.com/[email protected]/dist/out.css" rel="stylesheet">
7+
</head>
8+
9+
<body>
10+
<style>
11+
input:invalid+.text-error {
12+
border-color: red;
13+
}
14+
</style>
15+
<div class="container py-4">
16+
<form id="example-form" class="form" novalidate>
17+
<div class="form-group">
18+
<label for="example-input">
19+
<input id="example-input" name="example-input" class="input input-bordered" required>
20+
</label>
21+
<div class="text-error" htmx-validate-for="example-input" is="htmx-validate" class="invalid-feedback">Example
22+
Input is
23+
required</div>
24+
</div>
25+
<button type="submit" class="btn btn-primary">Submit</button>
26+
</form>
27+
</div>
28+
<example-element></example-element>
29+
</div>
30+
<script>
31+
const script = document.createElement('script')
32+
if (window.location.hostname.endsWith('github.io') || window.location.hostname.endsWith('github.com')) {
33+
script.src = "https://unpkg.com/htmx-validate@latest/dist/index.js"
34+
} else {
35+
script.src = "../dist/index.js"
36+
}
37+
script.type = 'module'
38+
document.body.appendChild(script)
39+
</script>
40+
</body>
41+
2242
</html>

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import {fixture, html} from '@open-wc/testing-helpers'
2-
import {ExampleElement} from './index'
2+
import {HTMXValidateElement} from './index'
33
import {describe, it, expect, beforeEach} from 'vitest'
44

5-
describe('example-element', () => {
6-
let element: ExampleElement
5+
describe('htmx-validate', () => {
6+
let element: HTMXValidateElement
77

88
beforeEach(async () => {
9-
element = await fixture(html`<example-element></example-element>`)
9+
element = await fixture(html`<htmx-validate></htmx-validate>`)
1010
})
1111

1212
it('should render the element', () => {

src/index.ts

+62-6
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,81 @@ export {}
22

33
declare global {
44
interface Window {
5-
ExampleElement: typeof ExampleElement
5+
HTMXValidate: typeof HTMXValidateElement
66
}
77
interface HTMLElementTagNameMap {
8-
'example-element': ExampleElement
8+
'htmx-validate': HTMXValidateElement
99
}
1010
}
1111

12-
export class ExampleElement extends HTMLElement {
12+
type HTMXValidateError = {
13+
name: string
14+
message: string
15+
}
16+
17+
type HTMXValidateSuccess = {
18+
name: string
19+
message: string
20+
}
21+
22+
export class HTMXValidateElement extends HTMLDivElement {
1323
constructor() {
1424
super()
1525
}
1626

27+
get htmxSuccessFor(): string {
28+
return this.getAttribute('htmx-success-for') || ''
29+
}
30+
31+
get htmxErrorFor(): string {
32+
return this.getAttribute('htmx-error-for') || ''
33+
}
34+
35+
showError(e: CustomEvent<HTMXValidateError>): void {
36+
if (!this.htmxErrorFor) {
37+
return
38+
}
39+
40+
const el = document.getElementById(this.htmxErrorFor)
41+
if (!el) {
42+
return
43+
}
44+
45+
el.classList.remove('hidden')
46+
el.textContent = e.detail.message
47+
}
48+
49+
showSuccess(e: CustomEvent<HTMXValidateError>): void {
50+
if (!this.htmxSuccessFor) {
51+
return
52+
}
53+
54+
const el = document.getElementById(this.htmxSuccessFor)
55+
if (!el) {
56+
return
57+
}
58+
59+
el.classList.remove('hidden')
60+
el.textContent = e.detail.message
61+
}
62+
1763
connectedCallback() {
18-
this.textContent = 'Hello, World!'
64+
window.addEventListener('htmx-validate:error', ((e: CustomEvent<HTMXValidateError>) =>
65+
this.showError(e)) as EventListener)
66+
window.addEventListener('htmx-validate:success', ((e: CustomEvent<HTMXValidateSuccess>) =>
67+
this.showSuccess(e)) as EventListener)
68+
}
69+
70+
disconnectedCallback(): void {
71+
window.removeEventListener('htmx-validate:error', ((e: CustomEvent<HTMXValidateError>) =>
72+
this.showError(e)) as EventListener)
73+
window.removeEventListener('htmx-validate:success', ((e: CustomEvent<HTMXValidateSuccess>) =>
74+
this.showSuccess(e)) as EventListener)
1975
}
2076
}
2177

22-
customElements.define('example-element', ExampleElement)
78+
customElements.define('htmx-validate', HTMXValidateElement, {extends: 'div'})
2379

2480
export const defineExampleElement = () => {
25-
customElements.define('example-element', ExampleElement)
81+
customElements.define('htmx-validate', HTMXValidateElement)
2682
}

0 commit comments

Comments
 (0)