web php
Progressive Enhancement And Server-Rendered UI
Progressive enhancement means the core page works with normal HTML and server-side PHP first. JavaScript then improves the experience where it is available.
This style is a strong fit for PHP because PHP is good at rendering HTML responses. Forms, links, redirects, validation errors, and flash messages can all work without requiring a client-side application.
Start with a working HTML flow
A normal server-rendered form should submit to a server route. The server validates, saves, redirects, and renders the next page.
<?php
declare(strict_types=1);
$taskId = 42;
echo '<form method="post" action="/tasks/' . $taskId . '/complete">' . PHP_EOL;
echo ' <button type="submit">Mark complete</button>' . PHP_EOL;
echo '</form>' . PHP_EOL;
// Prints:
// <form method="post" action="/tasks/42/complete">
// <button type="submit">Mark complete</button>
// </form>
That form is already usable. JavaScript can later intercept it to show a spinner, submit with fetch(), or update a row without a full page reload.
JavaScript enhances, the server remains responsible
Client-side code can improve interaction, but it must not be the only place validation or authorization happens. Users can disable JavaScript, requests can be forged, and clients can be modified.
<?php
declare(strict_types=1);
function completeTask(int $taskId, bool $canEdit): string
{
if (!$canEdit) {
return 'Forbidden';
}
return 'Task ' . $taskId . ' completed';
}
echo completeTask(42, true) . PHP_EOL;
// Prints:
// Task 42 completed
The same server-side permission check is needed whether the request came from a normal form or JavaScript.
Design useful server responses
Progressive enhancement works best when server responses are meaningful.
For a normal form submission, a successful POST often redirects to another page. This is the Post/Redirect/Get pattern.
For a JavaScript request, the same route might return JSON if the request asks for it, or you might create a separate endpoint.
<?php
declare(strict_types=1);
function responseForCompletedTask(bool $wantsJson): array
{
if ($wantsJson) {
return ['status' => 200, 'body' => '{"completed":true}'];
}
return ['status' => 303, 'headers' => ['Location' => '/tasks']];
}
$response = responseForCompletedTask(false);
echo $response['status'] . ' ' . $response['headers']['Location'] . PHP_EOL;
// Prints:
// 303 /tasks
Prefer real controls
Use links for navigation and forms/buttons for actions. That gives browsers, keyboards, screen readers, and search engines a meaningful base experience.
Do not make a <div> behave like a submit button when a real <button> would work. JavaScript can listen to the real button.
Useful enhancement targets
Good enhancement examples include:
- confirmation prompts before destructive actions
- inline validation messages while the server still validates on submit
- optimistic UI updates that fall back to a normal redirect
- sortable tables where the server can also sort via query strings
- modal dialogs opened from links that still have useful destinations
What to check in a project
Check whether the feature still has a meaningful server-rendered path. Critical actions should not require JavaScript just to reach the server.
Check that server validation and authorization are complete. Client checks are user experience, not security.
Check that forms have labels, buttons, methods, and actions that make sense.
Check that JavaScript failure does not leave the user unable to complete the main task.
What you should be able to do
After this lesson, you should be able to explain progressive enhancement, build a server-rendered form flow, add JavaScript without replacing server responsibility, and choose HTML controls that work before enhancement.
Practice
Task: Enhance A Server Form
Design a small server-rendered form that works without JavaScript, then describe the JavaScript enhancement.
Requirements
- Use
declare(strict_types=1);if you include PHP code. - Render a real HTML form with
methodandaction. - Include a submit button for a state-changing action.
- Include the server-side validation or authorization rule in plain PHP.
- Describe one JavaScript enhancement that improves the experience.
- Explain what still works if JavaScript fails.
Check Your Work
Read the result and confirm the core action does not depend on JavaScript.
Show solution
This solution starts with a normal POST form. The enhancement is optional.
<?php
declare(strict_types=1);
function renderCompleteTaskForm(int $taskId): string
{
return '<form method="post" action="/tasks/' . $taskId . '/complete">'
. '<button type="submit" data-enhance="confirm-complete">Mark complete</button>'
. '</form>';
}
function completeTask(int $taskId, bool $canEdit): string
{
if (!$canEdit) {
return 'Forbidden';
}
return 'Task ' . $taskId . ' completed';
}
echo renderCompleteTaskForm(42) . PHP_EOL;
echo completeTask(42, true) . PHP_EOL;
// Prints:
// <form method="post" action="/tasks/42/complete"><button type="submit" data-enhance="confirm-complete">Mark complete</button></form>
// Task 42 completed
JavaScript enhancement: listen for clicks on [data-enhance="confirm-complete"] and show a confirmation dialog before submitting. If JavaScript fails, the form still submits to the server.
Why This Works
The HTML has a real method and action. The server still checks permission. JavaScript improves the interaction but does not become the only way to complete the task.