Skip to content

Instantly share code, notes, and snippets.

@therealparmesh
Created December 21, 2024 13:37
Show Gist options
  • Save therealparmesh/6c5909dc0f9afd3fffa52cb9111d9131 to your computer and use it in GitHub Desktop.
Save therealparmesh/6c5909dc0f9afd3fffa52cb9111d9131 to your computer and use it in GitHub Desktop.
HTMX multi-step form
// `bun run index.js`
// localhost:3000
Bun.serve({
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/step") {
const currentStep = url.searchParams.get("to");
return new Response(
renderStepFragment(Number(currentStep, false, false)) +
renderStepFragment(Number(currentStep) - 1, true, true),
{ headers: { "Content-Type": "text/html" } },
);
}
if (url.pathname === "/pop") {
const currentStep = url.searchParams.get("to");
return new Response(
renderStepFragment(Number(currentStep), false, false) +
renderStepFragment(Number(currentStep) + 1, true, true),
{ headers: { "Content-Type": "text/html" } },
);
}
if (url.pathname === "/submit") {
return new Response(
html`
<div>
<h2>Form submitted successfully!</h2>
</div>
`,
{ headers: { "Content-Type": "text/html" } },
);
}
return new Response(
html`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Wizard Form</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
/>
<script>
window.me = (previous) =>
previous
? window.document.currentScript?.previousElementSibling
: window.document.currentScript?.parentElement;
</script>
<script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
<main>
<form id="wizard" hx-post="/submit" hx-swap="innerHTML">
<!-- current step -->
${renderStepFragment(1, false, false)}
<!-- hidden step -->
${renderStepFragment(2, true, false)}
<!-- hidden step -->
${renderStepFragment(3, true, false)}
</form>
</main>
</body>
</html>
`,
{ headers: { "Content-Type": "text/html" } },
);
},
});
function renderStepFragment(step, disabled, oob) {
switch (step) {
case 1:
return html`
<fieldset
id="wizard-step-1"
${disabled ? "disabled" : ""}
${disabled ? "hidden" : ""}
${oob ? `hx-swap-oob="true"` : ""}
>
<h2>Step 1</h2>
<input
type="text"
id="first_name"
name="first_name"
placeholder="First Name"
required
hx-preserve="true"
/>
<button
type="${disabled ? "button" : "submit"}"
hx-get="/step?to=2"
hx-target="#wizard-step-2"
hx-swap="outerHTML"
>
Next
<script>
// prevent form submission if invalid
me().addEventListener("htmx:beforeRequest", function (event) {
if (!event.detail.elt.form.reportValidity()) {
event.preventDefault();
}
});
</script>
</button>
</fieldset>
`;
case 2:
return html`
<fieldset
id="wizard-step-2"
${disabled ? "disabled" : ""}
${disabled ? "hidden" : ""}
${oob ? `hx-swap-oob="true"` : ""}
>
<h2>Step 2</h2>
<input
type="text"
id="last_name"
name="last_name"
placeholder="Last Name"
required
hx-preserve="true"
/>
<button
type="button"
hx-get="/pop?to=1"
hx-target="#wizard-step-1"
hx-swap="outerHTML"
>
Back
</button>
<button
type="${disabled ? "button" : "submit"}"
hx-get="/step?to=3"
hx-target="#wizard-step-3"
hx-swap="outerHTML"
>
Next
<script>
// prevent form submission if invalid
me().addEventListener("htmx:beforeRequest", function (event) {
if (!event.detail.elt.form.reportValidity()) {
event.preventDefault();
}
});
</script>
</button>
</fieldset>
`;
case 3:
return html`
<fieldset
id="wizard-step-3"
${disabled ? "disabled" : ""}
${disabled ? "hidden" : ""}
${oob ? `hx-swap-oob="true"` : ""}
>
<h2>Step 3</h2>
<input
type="email"
id="email"
name="email"
placeholder="Email"
required
hx-preserve="true"
/>
<button
type="button"
hx-get="/pop?to=2"
hx-target="#wizard-step-2"
hx-swap="outerHTML"
>
Back
</button>
<button type="${disabled ? "button" : "submit"}">Submit</button>
</fieldset>
`;
}
}
function html(strings, ...expressions) {
let result = "";
for (let i = 0; i < strings.length; i++) {
result += strings[i];
if (i < expressions.length) {
result += expressions[i];
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment