← Back to Blog

htmx for Small and Medium Businesses: Deployment, Upgrades and Costs

· 21 min read A wall of tan square tiles on a dark wooden bench, with one bright new tile sliding toward its slot along a thin rod that runs from a small brass box.

htmx is a small JavaScript library that lets ordinary HTML elements send requests to your server and swap the returned HTML into part of a page, using attributes such as hx-get, hx-post, hx-trigger, hx-target and hx-swap. It fits a business with a server rendered website or internal tool that needs live search, inline edits, filters and partial page updates without building a single page app. It is a poor fit for offline first applications, heavy client side editors, collaborative canvases, or replacing a healthy React or Vue codebase without a business reason.

Think of a dispatcher who changes a job status and waits for the whole screen to reload. The useful purchase is a status field that saves correctly, keeps the current filter and explains failures. You may already have almost everything needed on the server. htmx gives that existing application another way to talk to its pages.

It does not supply your database, staff permissions or scheduling rules. Someone still writes and maintains those. The opportunity is to keep more of that work in the backend your developer already knows.

We read the primary sources on November 1, 2026 and tested the interaction examples in a small browser test application. The businesses below are made up illustrations. Development hours are our own low and high assumptions, so treat them as planning numbers and get a quote before you budget.

Which htmx version should you use?

There are two current choices to understand. The npm registry marks 2.0.11 as latest, published September 22, 2026, and 4.0.0 as next, published August 28, 2026. There is no intervening htmx 3 release in the registry. The tag called next does not mean this 4.0.0 release is a beta.

The project homepage explains that 4 is not latest "so that people using the 2.x line are not accidentally upgraded." It says the tag will change at some point in 2027. This matters if an old page loads an unversioned CDN address or a build installs whatever npm currently calls latest.

The 4.0 release announcement is equally direct about existing sites: "htmx 2 will continue to be supported indefinitely so don’t feel any pressure to upgrade." That is a statement of intent from an open source project. It carries no contracted response time for your business.

Our recommendation is to evaluate 4.0.0 for a new application, with its own documentation and extension checks. Keep a working 2.x application on a tested, pinned 2.x release unless a specific improvement earns the migration work. We found no official requirement that every new project use 4, nor a requirement to migrate an existing site immediately. Make that call per application. The npm tag exists to stop accidental upgrades, and it tells you nothing else.

Version 4 rewrites the request machinery around fetch(), changes attribute inheritance and event names, and changes history restoration. It also includes morphing swaps that reconcile existing elements. Read the migration guide before changing a script URL. A page can appear to work while its inherited CSRF header or error handler has stopped working.

How small is the download?

We downloaded the two npm tarballs, verified each against the registry's dist.integrity, and measured dist/htmx.min.js. These are byte counts only; they say nothing about how fast your pages feel. GNU gzip used -9 -n, omitting the filename and timestamp; Brotli used quality 11.

Scroll to compare columns and rows when the table extends beyond the box.

Release Minified file Gzip Brotli
2.0.11 52,182 bytes 16,826 bytes 15,259 bytes
4.0.0 36,716 bytes 13,014 bytes 11,737 bytes

The 2.x homepage says approximately 16k minified and gzipped. The 4.0.0 README says approximately 12k. Our exact measurements sit beside those rounded claims because compression settings and units matter. Extensions, your own scripts, HTML responses and images add to the real transfer.

What happens when somebody clicks?

The browser sends a request. Your server checks the session, permissions and input, then renders a small piece of HTML. htmx puts that piece into the selected part of the existing page. The browser does not need a separate JSON model of the same screen.

For example, an inventory search can return table rows instead of a complete document. The 2.x reference and 4.x documentation describe HX-Request: true, which lets the server distinguish an htmx request from an ordinary page visit. That header is a rendering hint. Anyone can forge it; it grants no access.

Both versions support response headers such as HX-Redirect for a browser redirect and HX-Trigger for a client event. A saved order might trigger a refresh of the order count. Send those headers on an appropriate nonredirect response: browser handling of a normal HTTP redirect means htmx does not receive the original redirect response headers in the usual way.

These four patterns use attributes on the element that makes the request, avoiding the inheritance difference between versions. The downloadable kit includes server fragments, CSRF setup and additional patterns. The snippets show the interaction rather than a complete production application.

Search without reloading the table

<label for="query">Find a job</label>
<input id="query" name="q"
       hx-get="/jobs/search" hx-trigger="input changed delay:300ms"
       hx-target="#job-results">
<table>
  <caption>Jobs</caption>
  <thead><tr><th>Job</th><th>Status</th></tr></thead>
  <tbody id="job-results"><tr><td colspan="2">Type to search</td></tr></tbody>
</table>
<p id="search-status" role="status" aria-live="polite"></p>

The delay waits for a pause in typing. The server returns rows such as <tr><td>Filter replacement</td><td>Booked</td></tr>, escaping any customer supplied text. Keep a normal search form as a fallback where search must work without JavaScript. For production, handle overlapping requests so an older response cannot replace a newer result.

Save one section and show its validation errors

<section id="contact">
  <form hx-post="/contact" hx-target="#contact" hx-swap="outerHTML">
    <input type="hidden" name="csrf" value="test-token">
    <label for="name">Name</label>
    <input id="name" name="name">
    <button>Save</button>
  </form>
</section>

The endpoint returns a success message or a replacement section containing the form and field errors. Replace the test token with the framework's real token and field name; the fixed value is only for the test application. This example uses 200 for rendered validation results under both versions. By default, 2.x does not swap 422 responses, while 4.x does. If your framework uses 422, configure and test that swap explicitly. A rejected value must never be saved merely because the response is 200.

Load another group of records

<div id="more">
  <button hx-get="/orders?page=2"
          hx-target="#more" hx-swap="outerHTML">Load more</button>
</div>

The endpoint returns the next records followed by a new more container with an advanced page number. Replacing only that container preserves earlier records. Remove the control at the end. Pagination with ordinary links is often easier to operate than endless scrolling, especially when staff need to return to a particular record.

Delete a row after confirmation

<table><caption>Draft quotes</caption><tbody>
  <tr id="quote-7">
    <td>Draft 7</td>
    <td><button hx-delete="/quotes/7" hx-confirm="Delete draft 7?"
                hx-target="closest tr" hx-swap="outerHTML"
                hx-headers='{"X-CSRF-Token":"test-token"}'>Delete</button></td>
  </tr>
</tbody></table>

Again, replace the fixture token with a real server-issued token. After checking permission and the token, the endpoint deletes the allowed draft and returns an empty 200 response. That removes the row; 204 means no swap. Confirmation cannot enforce retention or authorization. Version 4 changes which form values accompany DELETE requests, so put required tokens on the issuing element or use an explicitly inherited header.

For ordinary links and forms, hx-boost can add partial navigation while retaining meaningful href, action and method attributes. In 4.x, inheritance is explicit; use its documented inherited form when applying behavior to descendants. Test with JavaScript disabled before calling a page progressively enhanced.

Three ways to install it

The 4.x installation documentation provides a CDN snippet with Subresource Integrity:

<script src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0"
        integrity="sha384-BvJpBiO8Kh31EqtJe5DRIeWrHWnCGkwytKs9NKFi86Hhw96dEqdEMzZDeK9iEGTc"
        crossorigin="anonymous"></script>

The hash makes the browser reject different bytes. Keep the version and hash together when upgrading. Kit 1 also includes the official 2.0.11 snippet. Never combine the hash for a minified file with its unminified counterpart.

Our default for a business site is self hosting. The official example is <script src="/js/htmx.min.js"></script>. This removes the third party CDN from page loads and makes a same-origin Content Security Policy easier to maintain. Download the pinned file into your project's asset directory, then verify it before publishing:

curl -fL https://cdn.jsdelivr.net/npm/htmx.org@4.0.0/dist/htmx.min.js -o htmx.min.js
printf '%s  %s\n' 'e484d9171a9db30a39c8f16e3d709d4137f3211c659f8e6125816635033d593f' 'htmx.min.js' | sha256sum -c -

That SHA-256 is our own measurement of the integrity-verified npm file. The project does not publish it, so record your own value when you pin a different release. Use a versioned asset filename in production when assets have long cache lifetimes. Keep the previous file for rollback.

If the application already has a bundler, the official npm approach is straightforward:

npm install htmx.org@4.0.0
import 'htmx.org';

Commit the dependency lockfile and use reproducible builds. Do not add a bundler solely to load this library. Installing htmx through npm does not turn a static host into an application server.

Keep the backend you already understand

Any host that runs your server code can serve the HTML fragments. A static only host needs functions or a separate backend for dynamic data and changes. The useful question is who maintains that backend, database, authentication and backups.

Scroll to compare columns and rows when the table extends beyond the box.

Existing stack Practical server work
WordPress A plugin AJAX handler returns HTML, using WordPress's supplied endpoint and action. Verify its nonce and check permissions.
Laravel A controller renders a Blade partial. Preserve escaping and CSRF protection.
Django A view renders a template partial. Keep autoescaping and the CSRF middleware and token.
Rails Render a partial and retain the framework's forgery protection.
ASP.NET Core Return a partial view, using configured antiforgery tokens and validation.
Flask Render a Jinja HTML template. CSRF protection needs additional implementation.
Express Render an escaping template and parse form bodies. Supply session and CSRF protections; Express does not add those automatically.
Go Handle routes with net/http and render through html/template. Do not mark untrusted content as trusted HTML.
Plain PHP Return HTML with escaped values. Implement authentication, authorization and CSRF protection explicitly.

These approaches need no htmx integration package. A wrapper can be convenient, but adopting one adds its own release and support checks. Existing Laravel Livewire or Rails Turbo applications deserve particular care: running two libraries against the same form or navigation can produce duplicate requests. Choose which library owns each interaction.

What six businesses could actually build

The following sizes and effort ranges are our assumptions. Small changes use the $63.63 web developer rate explained below; larger application work uses $93.40. These first-release estimates include implementation and testing, but exclude substantial data cleanup, training and specialist assessments. Hosting and upkeep remain additional.

A nine person HVAC contractor: the complaint might be, “I lose my place every time I change a quote status.” Add delayed search, status edits and a filtered work list to the existing Laravel quote tracker. The dispatcher can update a quote while keeping the current technician filter. Allow 24 to 40 hours, or $1,527 to $2,545, for that narrow change. It belongs in Example A's incremental approach; replacing dispatch software is a different project.

A six person property manager: the daily problem is, “The repair list takes too many clicks to sort.” Add status filters and inline assignment to an existing Django maintenance portal. The coordinator sees unassigned requests and updates one card without restarting the search. Our assumption is 32 to 56 hours, or $2,036 to $3,563. Existing tenant permissions and document storage must remain intact. Avoid duplicating the rent ledger.

A self storage operator with four staff and two locations: the owner might say, “People call about a unit that has already gone.” Add size filters to a PHP availability page backed by the real inventory system. Customers see the relevant units, while staff keep using their established booking process. Allow 20 to 36 hours, or $1,273 to $2,291. Filtering does not reserve a unit; the booking endpoint still needs a transaction that prevents double selling.

A twelve person print shop: the complaint is, “We refresh the board to see if artwork was approved.” Add a Rails order board with an approval form and restrained status polling. During the day, staff see changed orders while the server remains responsible for approvals and an audit trail. Our assumption is 40 to 64 hours, or $2,545 to $4,072. Polling every few seconds across many open screens adds real server load, so set a request budget before turning it on.

A 120 person distributor: the problem could be, “Only one person understands the Access file, and the spreadsheet stock counts disagree.” Build an ASP.NET Core inventory lookup with server rendered filters and authorized adjustments, reading from a designated stock system. Warehouse staff get one current view. Allow 160 to 280 hours, or $14,944 to $26,152, for a limited internal tool. Data migration, barcode equipment and replacing inventory accounting are outside that allowance. Example C shows the ongoing staffing decision.

A 300 person manufacturer: the supervisor might say, “We walk across the floor to find which jobs are waiting.” Build a Go status board and simple update forms, using a database of approved job states. Operators update one job; supervisors filter by work center. Our assumption is 200 to 360 hours, or $18,680 to $33,624. A browser status board is unsuitable for controlling machinery or safety interlocks. If the floor loses connectivity, that is a reason to preserve an offline workflow or choose software designed for it.

The 36 month bill

The BLS May 2025 national median hourly wages are $44.54 for Web Developers, SOC 15-1254 and $65.38 for Software Developers, SOC 15-1252. Divide by the private industry wage share of compensation, 0.700: $44.54 / 0.700 = $63.63/hour, and $65.38 / 0.700 = $93.40/hour, rounded to cents.

Server administration uses our shared $68.09/hour assumption, based on the systems administrator median of $47.66 / 0.700, read October 29. These are employee compensation estimates. An outside provider charges for overhead, risk and profit too; get a quote. We use the same developer rate on both sides of each comparison.

DigitalOcean Basic Regular costs $24/month for 4 GiB RAM, 2 vCPU and 80 GiB disk, or $48/month for 8 GiB, 4 vCPU and 160 GiB. Backblaze B2 lists $6.95/TB/month with the first 10 GB free. Our assumed 100 GB of retained backups costs (100 minus 10) x $0.00695 = $0.6255, budgeted at $0.63/month; 500 GB costs $3.4055, budgeted at $3.41. Both cases assume no chargeable extra transfer or API use.

These are USD before tax, read November 1, 2026, with monthly billing. Hosts have usage limits and additional charges. The selected sizes are planning assumptions, not measured capacity requirements. Low and high cases use the same server and backup volumes to isolate the labor uncertainty.

For each example, setup = development hours x developer rate + server setup hours x admin rate. Monthly = hosting + backups + admin hours x admin rate + development upkeep hours x developer rate + platform fees. The 36 month total is setup + 36 x monthly. Calculations retain cents; displayed totals round to whole dollars.

A. Improve the existing tool or rebuild its frontend

Our assumption: add htmx in 40 to 80 hours with 1 to 2 development upkeep hours monthly, versus a React frontend and separate API in 120 to 240 hours with 3 to 6 upkeep hours monthly. Both use $63.63/hour, retain the $24 server and $0.63 backups, and allow 1 to 3 monthly admin hours. Existing server setup cancels.

Scroll to compare columns and rows when the table extends beyond the box.

Choice Setup, low / high Monthly, low / high 36 months, low / high
Add htmx $2,545 / $5,090 $156 / $356 $8,174 / $17,912
React plus separate API $7,636 / $15,271 $284 / $611 $17,846 / $37,256
Difference $9,672 / $19,344

For example, the htmx low case is 40 x $63.63 + 36 x ($24 + $0.63 + $68.09 + $63.63) = $8,174. Break even is month 0 under these assumptions: htmx starts cheaper and remains cheaper. The gap comes from our scope assumptions; we did not measure anyone's productivity. A reusable API and existing React components can reverse it.

B. One server or a managed frontend plus that server

Vercel Pro lists $20/month. Its plan documentation includes one deploying seat and a $20 monthly usage credit; additional deploying seats cost $20/month each and usage above the allowance adds charges. Our comparison assumes one deploying seat and no overage. Site visitors are not deploying seats.

Both layouts retain the same $24 backend and $0.63 backups. Our assumption is 4 to 12 server setup hours and 1 to 3 monthly admin hours at $68.09. Application development is identical and excluded from this hosting-only comparison.

Scroll to compare columns and rows when the table extends beyond the box.

Hosting layout Setup, low / high Monthly, low / high 36 months, low / high
VPS serves the whole application $272 / $817 $93 / $229 $3,610 / $9,057
Vercel Pro frontend plus same backend $272 / $817 $113 / $249 $4,330 / $9,777

The combined low case is 4 x $68.09 + 36 x ($24 + $0.63 + $68.09) = $3,610. Adding Vercel costs 36 x $20 = $720; break even is month 0 for the combined server under matched labor. This does not price a fully managed database or application. Vercel's deployment tools can earn the fee: $20 / $68.09 is about 0.294 admin hours saved monthly. The platform route wins if its actual benefits exceed its added costs.

C. One application team or separately maintained frontend and API

For the medium business, our assumption is 400 to 800 initial hours and 12 to 24 development upkeep hours monthly for one server rendered codebase. Separate frontend and backend work totals 600 to 1,200 initial hours and 20 to 40 upkeep hours monthly. Both use $93.40/hour. These count assigned hours; neither side assumes anyone works on the project full time.

Both include one $48 server, $3.41 backups, 4 to 12 infrastructure setup hours and 1 to 3 monthly admin hours. There is no invented license fee for either library.

Scroll to compare columns and rows when the table extends beyond the box.

Choice Setup, low / high Monthly, low / high 36 months, low / high
One server rendered codebase $37,632 / $75,537 $1,240 / $2,497 $82,283 / $165,439
Separate frontend and API $56,312 / $112,897 $1,988 / $3,992 $127,862 / $256,598
Difference $45,579 / $91,158

The low case is 400 x $93.40 + 4 x $68.09 + 36 x ($48 + $3.41 + $68.09 + 12 x $93.40) = $82,283. Break even is month 0 with these hours. If the API already serves mobile applications or necessary integrations, you cannot count its removal as a saving. Major data cleanup, training, compliance reviews and serious incidents remain outside all three models.

Production details that belong in the quote

Start with output escaping. htmx inserts HTML, so untrusted text must pass through the template engine's escaping. If the application accepts rich HTML, use an allowlist sanitizer that also removes unwanted htmx attributes. The 2.x security guidance and 4.x security guidance explain why ordinary HTML injection becomes more capable when attributes can issue requests.

In 2.x, selfRequestsOnly:true, allowScriptTags:false, allowEval:false and historyCacheSize:0 are useful settings for the kit's simple patterns. Disable injected indicator CSS and provide your own stylesheet when enforcing a strict style policy. hx-disable prevents htmx processing inside a subtree; it does not sanitize dangerous HTML.

Those are not interchangeable 4.x configuration names. Version 4 uses mode:"same-origin" to constrain requests and hx-ignore for ignored subtrees. It no longer uses the 2.x localStorage history cache. Its optional hx-on, event filters and js: expressions still need evaluation; our examples avoid them. Its configuration reference and documented hx-csp extension are the right starting points for more involved policies.

Use a Content Security Policy that allows your own scripts and connections, without broadly enabling inline scripts or eval. Kit 1 supplies the exact version-specific settings and a browser-tested policy. A policy is only useful if the site's other widgets can also work under it. Test reporting before enforcing it on an established site.

CSRF protection remains the server framework's job. Render its real token as a form field or a correctly escaped hx-headers value and validate it on every state-changing request. In 4.x, a header on an ancestor needs explicit inheritance, such as hx-headers:inherited. Never disable middleware to make a demo pass. The kit has Django, Laravel, Rails and Express examples.

If one URL returns either a full page or a fragment according to HX-Request, send Vary: HX-Request on both representations and preserve any existing Vary fields. MDN explains the cache contract. Use different validators for different representations. Personal records generally need private or no-store caching as appropriate; Vary does not separate customers by itself.

Test the back button and a pasted URL. In 2.x, set historyRestoreAsHxRequest:false when using that header to choose fragments; otherwise a history cache miss can request the wrong representation. Version 4 normally refetches history rather than restoring HTML from localStorage. It sends HX-Request-Type: full for body-level and hx-select requests; handle full and history requests before selecting a fragment. Add every header used to choose the representation to Vary, including HX-Request-Type when applicable. A history address must still work as an ordinary full-page visit.

Accessibility needs deliberate work. Preserve useful element IDs, move focus when the active control disappears, and return focus after closing a dialog. Use a small aria-live region for status messages instead of announcing a whole table on every keystroke. Keyboard and screen reader checks belong in acceptance testing; a successful swap proves neither.

Show a useful failure state and preserve unsaved input. In 2.x, listen for documented events such as htmx:responseError and htmx:sendError. Version 4 uses htmx:response:error and the general htmx:error, as its events reference describes. Test slow responses, expired sessions, denied access and repeated submissions. Retrying a read is different from retrying a payment or stock adjustment.

Where htmx helps, and where a framework earns its keep

The strongest benefit is organizational. A team can keep the business rules and page templates together. A modest enhancement needs no build step, and an existing page can be upgraded one form at a time. Meaningful full-page URLs remain available for people and search engines when the server actually renders the content there. Crawlability still depends on how you design those pages; no attribute guarantees it.

The cost is dependence on the server for these interactions. Slow mobile connections make round trips noticeable. Offline work requires another design. Fragment endpoints multiply, markup becomes attribute heavy, and complex client state can become harder to reason about than a dedicated client application. Budget for backend load and for the 2.x to 4.x migration if you choose it. Do not tell an owner that a small download means free maintenance.

For a dropdown or a few local toggles, plain JavaScript may be enough. Alpine's local state model can pair with htmx when the server owns records and Alpine owns temporary display state. Decide which library owns each DOM area, and test its CSP requirements. Two state systems updating the same element can undo the simplicity you wanted.

A framework is the better choice when the application depends on substantial local state, rich editing, offline synchronization or complicated client interactions. A successful existing React or Vue team has tools and experience you would pay to replace. The project's own discussion of when to use hypermedia acknowledges that React developers are easier to hire. React-specific components such as shadcn also cannot simply be dropped into an htmx page. Ask the people who would maintain your system about the components they need.

Upgrade the library, or upgrade one page

Those are separate jobs. To identify a library version, inspect the script address, package manifest and lockfile, then check htmx.version in the browser console. A renamed vendor file may hide an old release. Check the deployed bytes as well as the repository.

The 1.x to 2.x guide covers dropped Internet Explorer support, extensions moving out of core, changed defaults and deprecated features. The 2.x to 4.x work includes inheritance, events, history, error swaps, request parameters and configuration. Our sensible staging order is to stabilize and test the latest 2.x release before evaluating 4; that order is our recommendation, and we found no official rule requiring it.

For an existing jQuery page or a small React widget, keep the ordinary endpoint working and add a fragment response using the same template partial. Start with one low-risk lookup. Record page transfer, request count and task completion before and after, with comparable data and network conditions. Lighthouse scores are lab measurements. They cannot tell you how many minutes staff saved.

Keep the old template and asset available for rollback. A migration has earned expansion when permissions, validation, keyboard use, history and failure handling work as well as the happy path.

Download the three kits

The useful habit behind The $97 Launch applies here: choose a small job that earns its cost before buying a larger project. A working search or approval form gives you something concrete to judge.

Related reading

  1. Laravel for small business, for deciding which parts need custom application work.
  2. Going frameworkless on Cloudflare and understanding vendor lock in, for the hosting and maintenance tradeoffs.
  3. WordPress and WooCommerce audit guide, when the established site should remain the starting point.
  4. Apache web servers and API gateways, for the infrastructure underneath a server rendered application.
  5. A private development server, for keeping a staging copy separate from customer traffic.

Fact-check notes and sources

Prices and technical documentation were read November 1, 2026 unless noted below. Prices were also checked in a browser. Sizes are our measurements of verified release files; labor hours and workload quantities are our assumptions. The tests ran the examples in a small test application; we did not deploy them for a customer.

  1. npm registry. Read November 1, 2026, 17:54 UTC.

  2. project homepage. Read November 1, 2026, 17:54 UTC.

  3. 4.0 release announcement. Read November 1, 2026, 17:55 UTC.

  4. migration guide. Read November 1, 2026, 17:55 UTC.

  5. 4.0.0 README. Read November 1, 2026, 17:55 UTC.

  6. 2.x reference. Read November 1, 2026, 17:54 UTC.

  7. 4.x documentation. Read November 1, 2026, 17:55 UTC.

  8. WordPress. Read November 1, 2026, 17:56 UTC.

  9. Laravel. Read November 1, 2026, 17:56 UTC.

  10. CSRF protection. Read November 1, 2026, 17:56 UTC.

  11. Django. Read November 1, 2026, 17:56 UTC.

  12. CSRF middleware and token. Read November 1, 2026, 17:55 UTC.

  13. Rails. Read November 1, 2026, 17:56 UTC.

  14. forgery protection. Read November 1, 2026, 17:56 UTC.

  15. ASP.NET Core. Read November 1, 2026, 17:56 UTC.

  16. antiforgery tokens and validation. Read November 1, 2026, 17:56 UTC.

  17. Flask. Read November 1, 2026, 17:56 UTC.

  18. CSRF protection needs additional implementation. Read November 1, 2026, 17:56 UTC.

  19. Express. Read November 1, 2026, 17:56 UTC.

  20. Go. Read November 1, 2026, 17:57 UTC.

  21. html/template. Read November 1, 2026, 17:56 UTC.

  22. Plain PHP. Read November 1, 2026, 17:56 UTC.

  23. $44.54 for Web Developers, SOC 15-1254. Read November 1, 2026, 17:54 UTC.

  24. $65.38 for Software Developers, SOC 15-1252. Read November 1, 2026, 17:54 UTC.

  25. private industry wage share of compensation, 0.700. Read November 1, 2026, 17:55 UTC.

  26. systems administrator median. Read October 29, 2026, 21:12 UTC; shared labor assumption.

  27. DigitalOcean Basic Regular. Read November 1, 2026, 17:55 UTC.

  28. Backblaze B2. Read November 1, 2026, 17:55 UTC.

  29. Vercel Pro. Read November 1, 2026, 17:55 UTC.

  30. plan documentation. Read November 1, 2026, 17:55 UTC.

  31. 2.x security guidance. Read November 1, 2026, 17:54 UTC.

  32. configuration reference. Read November 1, 2026, 17:55 UTC.

  33. Content Security Policy. Read November 1, 2026, 17:55 UTC.

  34. MDN explains the cache contract. Read November 1, 2026, 17:55 UTC.

  35. aria-live region. Read November 1, 2026, 17:55 UTC.

  36. Alpine's local state model. Read November 1, 2026, 17:55 UTC.

  37. discussion of when to use hypermedia. Read November 1, 2026, 17:59 UTC.

  38. 1.x to 2.x guide. Read November 1, 2026, 17:54 UTC.

  39. GitHub releases. Read November 1, 2026, 17:55 UTC; cross-checked against npm publication metadata.

  40. 4.x events reference. Read November 1, 2026, 18:00 UTC.

This post is informational, not legal or financial advice. Product names identify the products discussed. No affiliation or endorsement is implied.

← Back to Blog

Accessibility Options

Text Size
High Contrast
Reduce Motion
Reading Guide
Link Highlighting
Accessibility Statement

J.A. Watte is committed to ensuring digital accessibility for people with disabilities. This site conforms to WCAG 2.1 and 2.2 Level AA guidelines.

Measures Taken

  • Semantic HTML with proper heading hierarchy
  • ARIA labels and roles for interactive components
  • Color contrast ratios meeting WCAG AA (4.5:1)
  • Full keyboard navigation support
  • Skip navigation link
  • Visible focus indicators (3:1 contrast)
  • 44px minimum touch/click targets
  • Dark/light theme with system preference detection
  • Responsive design for all devices
  • Reduced motion support (CSS + toggle)
  • Text size customization (14px–20px)
  • Print stylesheet

Feedback

Contact: jwatte.com/contact

Full Accessibility Statement • Privacy Policy

Last updated: April 2026