hx-prompt
Prompt before requests with hx-prompt='Reason?'
The hx-prompt extension restores htmx 2’s hx-prompt attribute.
Before each request, it pops up a browser prompt. The answer becomes the HX-Prompt header. If the user cancels, the request never fires.
Installing
<script src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0/dist/htmx.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0/dist/ext/hx-prompt.js"></script>
Usage
<button hx-delete="/items/1" hx-prompt="Reason for deletion?">
Delete
</button> On click:
- Browser asks
Reason for deletion?. - Cancel aborts.
- Any answer (even empty) fires a cancelable
htmx:promptevent carrying it inevent.detail.prompt. - If nothing cancels it, htmx sends the request with the
HX-Promptheader set to the answer.
htmx:prompt event
The htmx:prompt event fires on the source element after a valid answer.
Listen with hx-on::prompt and call event.preventDefault() to abort:
<button hx-delete="/items/1"
hx-prompt="Reason?"
hx-on::prompt="if (prompt.length < 3) event.preventDefault()">
Delete
</button> event.detail carries { prompt, target }. hx-on exposes it directly, so they’re in scope without unwrapping.
Inheritance
The hx-prompt attribute supports inheritance.
<div hx-prompt:inherited="Reason?">
<button hx-delete="/items/1">Delete</button>
<button hx-delete="/items/2">Delete</button>
</div> Composing with hx-confirm
hx-prompt runs before hx-confirm. Both must pass for the request to proceed:
<button hx-delete="/items/1"
hx-prompt="Reason?"
hx-confirm="Are you sure?">
Delete
</button> If the user cancels the prompt, the confirm dialog is not shown.
Custom Dialogs
Assign a function to window.htmxPrompt to use a custom (synchronous) dialog.
// receives the question, returns the answer string or null to cancel window.htmxPrompt = (question) => myCustomSyncDialog(question);
The extension uses window.prompt by default.
Server-Side Example
HX-Prompt is a regular request header. Read it however your server reads headers.
def delete_item(request, id):
reason = request.headers.get("HX-Prompt", "")
Item.objects.filter(id=id).delete(reason=reason)
return HttpResponse("") # empty response removes the row Without the extension
If you’d rather skip the extension, a single hx-on can do the same thing:
<button hx-delete="/items/1"
hx-on::config:request="ctx.request.headers['HX-Prompt'] = prompt('Reason?') ?? event.preventDefault()">
Delete
</button>
Licensed under the Zero-Clause BSD License.
https://four.htmx.org/extensions/hx-prompt/