Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/phpcsfixer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.1', '8.2', '8.4']
php-versions: ['8.2', '8.5']

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.1', '8.4']
php-versions: ['8.2', '8.4']

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
strategy:
matrix:
php-versions: ['8.1', '8.2', '8.3', '8.4', '8.5']
php-versions: ['8.2', '8.3', '8.4', '8.5']

steps:
- name: Free Disk Space (Ubuntu)
Expand Down
34 changes: 33 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
# Changelog
All notable changes to this project will be documented in this file.

## [Unreleased]
## [4.0.0](https://github.com/michalsn/codeigniter-htmx/compare/v2.3.0...v4.0.0) - 2026-09-02

### Breaking changes

- Requires PHP 8.2 or later.
- Requires CodeIgniter 4.7 or later.
- Drops htmx 2 support and targets the final htmx 4 request/response model and event lifecycle.
- Replaces `IncomingRequest::getTrigger()` with `getSource()` and removes `getTriggerName()` and `getTriggeringEvent()`. The `getSource()` and `getTarget()` methods now return htmx 4 element identifiers in `tag#id` format.
- Removes the third `$after` argument from `Response::triggerClientEvent()` because htmx 4 removed the `HX-Trigger-After-Swap` and `HX-Trigger-After-Settle` response headers.
- Keeps the `RedirectResponse::hxLocation()` argument order introduced in version 2.3. Its legacy `handler` position remains reserved, but passing a value now throws because final htmx 4 no longer supports that callback option.

### Enhancements

- Added `IncomingRequest::getRequestType()`, `isPartial()`, and `isFull()` for `HX-Request-Type`.
- Added the htmx 4 swap styles, including `outerSync`, morph swaps, `textContent`, and shorthand insertion styles.
- Extended `RedirectResponse::hxLocation()` with `selectOOB`, `transition`, array event data, `false` values for `push` and `replace`, and URL normalization for history options.

### Changed

- Updated the Debug Toolbar integration for the fetch-based htmx 4 request lifecycle.
- Reworked the error modal for htmx 4 error responses, including a sandboxed HTML preview and raw response source.

## [2.3.0](https://github.com/michalsn/codeigniter-htmx/compare/v2.2.0...v2.3.0) - 2026-07-24

### Fixes

- Added the missing `push`, `replace`, `select`, and `handler` parameters to `RedirectResponse::hxLocation()`.

## [2.2.0](https://github.com/michalsn/codeigniter-htmx/compare/v2.1.0...v2.2.0) - 2026-02-04

### Fixes

- Updated the Debug Toolbar integration for newer CodeIgniter releases, including the method signature required by CodeIgniter 4.7 and support for required after filters.

## [2.1.0](https://github.com/michalsn/codeigniter-htmx/compare/v2.0.0...v2.1.0) - 2024-11-06

Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# CodeIgniter HTMX

A set of methods for `IncomingRequest`, `Response` and `RedirectResponse` classes to help you work with [htmx](https://htmx.org) fluently in CodeIgniter 4 framework.
A set of methods for `IncomingRequest`, `Response` and `RedirectResponse` classes to help you work with [htmx](https://four.htmx.org/) fluently in CodeIgniter 4 framework.

It also provides some additional help with **handling errors** and **Debug Toolbar** in development mode as well as support for **view fragments**.

This version targets the htmx 4 request/response model and event lifecycle. Applications that still use htmx 2 should use the `v2` branch.

[![PHPUnit](https://github.com/michalsn/codeigniter-htmx/actions/workflows/phpunit.yml/badge.svg)](https://github.com/michalsn/codeigniter-htmx/actions/workflows/phpunit.yml)
[![PHPStan](https://github.com/michalsn/codeigniter-htmx/actions/workflows/phpstan.yml/badge.svg)](https://github.com/michalsn/codeigniter-htmx/actions/workflows/phpstan.yml)
[![Deptrac](https://github.com/michalsn/codeigniter-htmx/actions/workflows/deptrac.yml/badge.svg)](https://github.com/michalsn/codeigniter-htmx/actions/workflows/deptrac.yml)
[![Coverage Status](https://coveralls.io/repos/github/michalsn/codeigniter-htmx/badge.svg?branch=develop)](https://coveralls.io/github/michalsn/codeigniter-htmx?branch=develop)

![PHP](https://img.shields.io/badge/PHP-%5E8.0-blue)
![CodeIgniter](https://img.shields.io/badge/CodeIgniter-%5E4.3-blue)
![PHP](https://img.shields.io/badge/PHP-%5E8.2-blue)
![CodeIgniter](https://img.shields.io/badge/CodeIgniter-%5E4.7-blue)

## Installation

composer require michalsn/codeigniter-htmx

> [!NOTE]
> Remember - you still need to include the `htmx` javascript library inside the `head` tag.
> This package does not install the browser-side htmx library. Install htmx 4 explicitly - for example, `npm install htmx.org@4` - and include it in your page. An unversioned npm install may still resolve to htmx 2 during the htmx 4 release transition.

## Docs

Expand Down
10 changes: 3 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
],
"homepage": "https://github.com/michalsn/codeigniter-htmx",
"require": {
"php": "^8.0"
"php": "^8.2",
"codeigniter4/framework": "^4.7"
},
"require-dev": {
"codeigniter4/devkit": "^1.0",
"codeigniter4/framework": "^4.3"
"codeigniter4/devkit": "^1.3"
},
"minimum-stability": "dev",
"prefer-stable": true,
Expand Down Expand Up @@ -48,16 +48,12 @@
"ci": [
"Composer\\Config::disableProcessTimeout",
"@cs",
"@deduplicate",
"@inspect",
"@analyze",
"@test"
],
"cs": "php-cs-fixer fix --ansi --verbose --dry-run --diff",
"cs-fix": "php-cs-fixer fix --ansi --verbose --diff",
"style": "@cs-fix",
"deduplicate": "phpcpd app/ src/",
"inspect": "deptrac analyze --cache-file=build/deptrac.cache",
"mutate": "infection --threads=2 --skip-initial-tests --coverage=build/phpunit",
"test": "phpunit"
}
Expand Down
14 changes: 7 additions & 7 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ We will get our copy ready for modifications.

Available options:

- [$toolbarDecorator](#toolbarDecorator)
- [$errorModalDecorator](#errorModalDecorator)
- [$skipViewDecoratorsString](#skipViewDecoratorsString)
- [$toolbarDecorator](#toolbardecorator)
- [$errorModalDecorator](#errormodaldecorator)
- [$skipViewDecoratorsString](#skipviewdecoratorsstring)
- [$storePreviousURL](#storepreviousurl)

### $toolbarDecorator

Expand Down Expand Up @@ -42,7 +43,6 @@ In the `production` environment these decorators are ignored by design. So this
Specifies whether the HTMX request URL should be stored in the session, for use with the `previous_url()` helper function.
For more information, see the [user guide](https://codeigniter.com/user_guide/helpers/url_helper.html#previous_url).

Basically, if you use HTMX extensively, including for navigating your site, you will probably want to leave it as `true`,
and in cases where storing the request is not desirable, even if it uses HTMX, you can use custom header, to indicate the
AJAX call or [ajax-header](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/ajax-header/README.md) extension,
which will add the necessary headers automatically. URLs from AJAX requests are always excluded from session storage.
Basically, if you use HTMX extensively, including for navigating your site, you will probably want to leave it as `true`.
If storing the request is not desirable, mark it as a traditional AJAX request or use a custom header in your application flow.
URLs from AJAX requests are always excluded from session storage.
4 changes: 2 additions & 2 deletions docs/debug_toolbar.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Debug Toolbar

As long as you **don't use** the [head-support](https://htmx.org/extensions/head-support/) extension,
As long as you **don't use** the [hx-head](https://four.htmx.org/extensions/hx-head) extension,
the Debug Toolbar should work out of the box. It will be updated after every request, so please remember
it will only display the latest information. If you want to see what happened in earlier request,
use the `History` tab in the Toolbar.

If you're using the `head-support` extension then the Debug Toolbar rendering will not work for `htmx` requests.
If you're using the `hx-head` extension then the Debug Toolbar rendering will not work for `htmx` requests.
You can still access the toolbar for a given request by checking the URL in the `debugbar-link` response header.

This feature can be disabled in the [Config](configuration.md) file.
22 changes: 21 additions & 1 deletion docs/error_handling.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Error handling

By default, when an HTTP error response occurs, htmx is not displaying the error. This library changes it so that in the development mode, errors are displayed in a modal window.
HTMX 4 handles error responses through its response handling rules, using `hx-status:*` attributes and `htmx.config.noSwap`.

In development mode, when `errorModalDecorator` is enabled, this library overrides that default browser-side behavior for failed HTMX requests.

Instead of allowing HTMX to continue with its normal response handling, the raw response is displayed in a modal window and the normal HTMX swap is skipped.

This makes it easier to inspect exception pages, validation output, and malformed HTML returned during development, without changing the actual HTTP status code.

HTML error pages are shown in a sandboxed preview iframe, with a source view available for inspecting the raw response. JSON and plain-text responses are shown directly as source.

If you want to use HTMX's native error handling rules in development instead, disable `errorModalDecorator` in the config.

When the decorator is disabled, you can configure HTMX directly, for example:

```html
<script>
htmx.config.noSwap = [204, 304, '4xx', '5xx'];
</script>
```

You can also use `hx-status:*` attributes to define per-status error targets in your application.

This feature can be disabled in the [Config](configuration.md) file.
8 changes: 5 additions & 3 deletions docs/html_formatter.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ We should edit the `app/Config/Format.php` file to include the necessary changes

php spark htmx:publish

Since content negotiation will be triggered for any format other than `json` or `xml`, we have two options:
With HTMX 4, requests already send `Accept: text/html`, so in the most common HTMX case no extra client-side configuration is needed.

1. Set the custom headers for every request via HTML tag
If you want to use the formatter outside HTMX requests, you still have two options:

1. Set the custom headers for a request explicitly
```html
hx-headers='{"Accept":"text/html"}'
```
Expand All @@ -28,7 +30,7 @@ Since content negotiation will be triggered for any format other than `json` or

### Example

This is an sample of using HTML formatter:
This is a sample of using HTML formatter:

```php
<?php
Expand Down
78 changes: 78 additions & 0 deletions docs/htmx_4_migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Migrating from htmx 2 to htmx 4

This page covers changes in this CodeIgniter integration. Use the official [htmx 2 to htmx 4 migration guide](https://four.htmx.org/docs#migrating-from-htmx-2x-to-4x) for client-side attributes, JavaScript APIs, events, configuration, and extensions. The official [What's new in htmx 4](https://four.htmx.org/docs/whats-new-in-htmx-4) page provides additional context.

## Install htmx 4 explicitly

This package does not install the browser library. Select the htmx 4 major version explicitly; an unversioned npm install may still resolve to htmx 2 during the transition period.

```console
npm install htmx.org@4
```

## IncomingRequest API

htmx 4 renamed request headers and added a request type:

| htmx 2 package API | htmx 4 package API | Notes |
| --- | --- | --- |
| `getTrigger()` | `getSource()` | `HX-Trigger` became `HX-Source`; its value is now an element identifier such as `button#save`. |
| `getTriggerName()` | — | `HX-Trigger-Name` was removed. |
| `getTriggeringEvent()` | — | The `Triggering-Event` extension header is not part of the htmx 4 request model. Read a custom header through CodeIgniter if your application still sends one. |
| `getPrompt()` | `getPrompt()` | Retained for the optional [hx-prompt extension](https://four.htmx.org/extensions/hx-prompt). |
| — | `getRequestType()` | Returns `partial`, `full`, or `null`. |
| — | `isPartial()` / `isFull()` | Convenience checks for `HX-Request-Type`. These values also work with `is('partial')` and `is('full')`. |

`getTarget()` remains available, but `HX-Target` now contains an element identifier such as `div#results`, rather than only its ID.

The existing `isHtmx()`, `isBoosted()`, `isHistoryRestoreRequest()`, and `getCurrentUrl()` methods remain available.

## Response API

htmx 4 removed the response headers that scheduled triggers after the swap or settle phase. Consequently, the third `$after` argument was removed from `triggerClientEvent()`:

```php
$this->response->triggerClientEvent('showMessage', [
'level' => 'info',
'message' => 'Saved',
]);
```

Events are now sent through `HX-Trigger`. Listen at the appropriate point in the htmx 4 event lifecycle when later client-side handling is required.

`setReswap()` accepts the final htmx 4 swap styles, including `innerMorph`, `outerMorph`, `outerSync`, `textContent`, `before`, `after`, `prepend`, and `append`, in addition to the existing styles.

`RedirectResponse::hxLocation()` supports the serializable htmx 4 request-context options exposed by this package: `source`, `event`, `target`, `swap`, `values`, `headers`, `select`, `selectOOB`, `push`, `replace`, and `transition`.

The `push`, `replace`, and `select` parameter positions introduced in package version 2.3 are retained for positional calls. The legacy `handler` position is reserved as a migration guard, but passing a value throws an `InvalidArgumentException`: final htmx 4 no longer supports a response callback in `htmx.ajax()` options.

## Server behavior to review

htmx 4 swaps error responses by default; only `204` and `304` are excluded. If your application expects the htmx 2 behavior, either configure `htmx.config.noSwap` or use `hx-status:*` attributes. The package's development error modal continues to show error responses without changing their HTTP status.

If a cache can serve both full and partial responses for the same URL, make the variants explicit. A typical starting point is:

```http
Vary: HX-Request-Type
```

Extend `Vary` when the representation also depends on another request header.

## Client-side checklist

The following application-level changes are intentionally not duplicated here; review them in the official migration guide:

- explicit attribute inheritance and the temporary htmx 2 compatibility extension;
- renamed or removed attributes and configuration options;
- the `fetch()`-based request and event lifecycle;
- history restoration, timeouts, and out-of-band swap ordering;
- the htmx 4 extension registration model.

Use the official upgrade checker as a first pass, then test behavior that depends on inheritance, error responses, history, and custom events.

## References

- [Migrating from htmx 2.x to 4.x](https://four.htmx.org/docs#migrating-from-htmx-2x-to-4x)
- [What's new in htmx 4](https://four.htmx.org/docs/whats-new-in-htmx-4)
- [htmx 4.0.0 release notes](https://four.htmx.org/announcements/2026-08-28-htmx-4.0.0-is-released)
- [htmx 4 reference](https://four.htmx.org/reference/)
Loading
Loading