Intuitive & reusable HTML components in PHP

March 30, 2026 · View on GitHub

A practical component system for PHP – write reusable, class-based UI components with props, children, and safe rendering.

Features

  • Components as PHP classes
  • Props and children
  • Escaped-by-default output
  • Self-closing and paired syntax
  • No templating engine – 100% native PHP

Installation

composer require nititech/html-components

Usage

Creating components

Write components directly using native PHP syntax — similar to how JSX mixes HTML and logic:

<?php

namespace components;

class Message extends \HTML\Component {
  public function render() {
    $style = match ($this->variant) {
      'success'
        => 'background-color: #e6ffed; color: #2f855a; border: 1px solid #c6f6d5;',
      'error'
        => 'background-color: #ffe6e6; color: #c53030; border: 1px solid #feb2b2;',
      'info'
        => 'background-color: #ebf8ff; color: #2b6cb0; border: 1px solid #bee3f8;',
      default
        => 'background-color: #f7fafc; color: #2d3748; border: 1px solid #e2e8f0;',
    }; ?>
    <div style="padding: 1rem; margin-bottom: 1rem; border-radius: 6px; <?= $style ?>">
        <div style="font-weight: bold; margin-bottom: 0.5rem;">
            <?= ucfirst($this->variant ?? 'Note') ?> 🔔
        </div>
        <div>
            <?= $this->children ?>
        </div>
    </div>
<?php
  }
}

Rendering components

<?php $msg = new \components\Message(['variant' => 'success']); ?>
    Your profile was updated successfully.<br />
    <a href="/cool">Continue</a>
<?php $msg->close(); ?>

💡 More convenient component usage

We have written several plugins for Vite.
To use these components more convenient follow the guide of the vite-plugin-php-components plugin.
This plugin allows you to use these components as regular HTML elements and rewrites those up on compilation into real PHP calls:

<component.ButtonComponent class="btn-main">
  Button Label
</component.ButtonComponent>

👇

<?php $c_234546546 = new \components\ButtonComponent(['class' => 'btn-main']); ?>
  Button Label
<?php $c_234546546->close(); ?>

Alternative usage

Self-Closing Component

<?php \components\Example::closed(['foo' => 'bar', 'class' => 'test']); ?>

With JSON Props

<?php \components\Example::closed('{"foo":"bar","class":"test"}'); ?>

Output Modes

Components can either echo directly or return a string for further processing (e.g. passing into templates or APIs).

With closing tag

<?php $msg = new \components\Message(['variant' => 'success']); ?>
    Your profile was updated successfully.<br />
    <a href="/cool">Continue</a>
<?php $html = $msg->close(true); // Returns HTML string instead of echoing
?>

Self-closing

$html = \components\Message::closed(
  ['variant' => 'success', 'children' => 'Something went wrong.'],
  true, // Set last parameter to return as HTML string
);

Notes

  • HTML is written inline using regular PHP – no templating language required
  • <?= $this->children; ?> is unescaped inner content, other properties are escaped and can be safely used in the HTML context
  • You can mix control logic, conditions, and loops directly in PHP

Props & Escaping

AccessEscaped?Example
$this->foo✅ YesSafe for direct HTML injection
$this->__props__->safe('foo')✅ YesSafe for direct HTML injection
$this->__props__->__toString()✅ YesFormatted and HTML-safe string of attributes, that can be directly injected into the attributes of an element.
$this->__props__->foo or $this->__props__['foo']❌ NoUse for raw values (e.g. JSON, IDs)
$this->__props__->filter(['*', '!class'])❌ NoUse for getting an iterable array of raw values (e.g. to pass to child components) (excludes the children prop)
$this->__props__->__toUnsafeString()❌ NoFormatted and not HTML-safe string of attributes, that can be printed into the attributes of a component.
[...$this->__props__]❌ NoYou can also spread the props into an array - those props are not HTML-safe!
$this->children❌ NoDirect inner content (slot-like)

Note: Only children is unescaped by default. All other props accessed as $this->prop_name are HTML-escaped for safety.

Utilities

Components
  • HTML.Element A ready-to-use component for rendering dynamic standard HTML elements with declarative props.
    Usage:

    <HTML.Element element="button" type="submit" class="container">
        Click me
    </HTML.Element>
    

    or

    <?php \HTML\Element::closed(['element' => 'img', 'src' => '/some-pic.jpg']); ?>
    

    Props:

    • element: string (required) – the HTML tag to render (e.g., "div", "section", "button")
    • other attributes – pass-through attributes/handlers (style, class, data-, aria-, etc.)

    Behavior:

    • Renders a DOM element matching element
    • Forwards additional props to the underlying element
    • Keeps semantics and browser behavior of native HTML tags
Methods
  • \HTML\Utils::encode_output($input) Method to escape user-supplied or dynamic text before injecting it into HTML content, preventing XSS vulnerabilities.
    Arguments:

    • $input: mixed (required) – the data to escape

    Behavior:

    • Escapes supplied input
    • If $input is an array it concatenates all elements to a single string

Issues

If you encounter any other bugs or need some other features feel free to open an issue.


Support

Love open source? Enjoying my project?
Your support can keep the momentum going! Consider a donation to fuel the creation of more innovative open source software.

via Ko-Fi Buy me a coffee via PayPal
Ko-Fi Buy Me A Coffee PayPal