webfiori / ui
A library that provides basic utilities for creating HTML documents.
Fund package maintenance!
paypal.me/IbrahimBinAlshikh
www.buymeacoffee.com/ibrahimdev
Ko Fi
Installs: 41 162
Dependents: 3
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 0
Open Issues: 1
Requires
- php: >=8.1
- webfiori/collections: 2.0.x
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.86
- phpunit/phpunit: ^10
- dev-master
- dev-main
- 3.0.0
- 2.6.4
- v2.6.3
- v2.6.2
- v2.6.1
- v2.5.6
- v2.5.5
- v2.5.4
- v2.5.3
- v2.5.2
- v2.5.1
- v2.5.0
- v2.4.0
- v2.3.5
- v2.3.4
- v2.3.3
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.9.7
- v1.9.6
- v1.9.5
- v1.9.4
- v1.9.3
- v1.9.2
- v1.9.1
- v1.9.0
- v1.8.9
- v1.8.8
- v1.8.7
- v1.8.6
- v1.8.5
- v1.8.4
- v1.8.3
- v1.8.2
- v1.8.1
- dev-release-please--branches--main
- dev-dev
- dev-release-please--branches--master
- dev-github-actions
- dev-bug-fix
This package is auto-updated.
Last update: 2025-08-27 15:45:58 UTC
README
A PHP library for creating HTML documents and DOM manipulation with an object-oriented approach. Build dynamic web pages, forms, tables, and complex UI components programmatically with clean, readable code.
✨ Features
- 🏗️ Object-Oriented DOM Creation - Build HTML elements using intuitive PHP classes
- 🎨 Template System - Support for both HTML templates with slots and PHP templates
- 🔄 Iterator Support - Traverse child nodes using foreach loops
- 🎯 Type Safety - Full type hints and comprehensive PHPDoc documentation
- 🛡️ Security First - Built-in HTML entity escaping
- 🌐 XML Support - Generate both HTML and XML documents
📋 Table of Contents
- Installation
- Quick Start
- Core Concepts
- HTML Document Creation
- Working with Elements
- Forms and Input
- Tables and Data
- Lists and Navigation
- Images and Media
- Template System
- Styling and CSS
- Advanced Features
- Performance Tips
- API Reference
- Examples
- Contributing
🚀 Installation
Install via Composer:
composer require webfiori/ui
Or add to your composer.json
:
{ "require": { "webfiori/ui": "^3.0" } }
Requirements
- PHP 8.1 or higher
- No additional dependencies required
⚡ Quick Start
Create Your First HTML Document
<?php require_once 'vendor/autoload.php'; use WebFiori\UI\HTMLDoc; // Create a complete HTML5 document $doc = new HTMLDoc(); $doc->getHeadNode()->setPageTitle('My First Page'); $doc->setLanguage('en'); // Add content to the body $body = $doc->getBody(); $body->addChild('h1')->text('Welcome to WebFiori UI!'); $body->addChild('p')->text('Building HTML has never been easier.'); // Output the complete document echo $doc;
Build Elements Programmatically
use WebFiori\UI\HTMLNode; // Create a navigation menu $nav = new HTMLNode('nav', ['class' => 'main-nav']); $ul = $nav->addChild('ul', ['class' => 'nav-list']); $menuItems = ['Home', 'About', 'Services', 'Contact']; foreach ($menuItems as $item) { $li = $ul->li(['class' => 'nav-item']); $li->anchor($item, [ 'href' => '#' . strtolower($item), 'class' => 'nav-link' ]); } echo $nav->toHTML(true);
🧠 Core Concepts
HTMLNode - The Foundation
Every HTML element is represented by an HTMLNode
object:
// Basic element creation $div = new HTMLNode('div'); // <div></div> $div = new HTMLNode('div', ['id' => 'main']); // <div id="main"></div> // Add content $div->text('Hello World'); // <div id="main">Hello World</div> // Chain operations $div->setAttribute('class', 'container') ->setStyle(['padding' => '20px']) ->addChild('p')->text('Nested paragraph');
Method Chaining
Most methods return the HTMLNode instance, enabling fluent interfaces:
$card = new HTMLNode('div'); $card->setClassName('card') ->setStyle(['border' => '1px solid #ccc', 'padding' => '1rem']) ->addChild('h3')->text('Card Title')->getParent() ->addChild('p')->text('Card content goes here.');
Parent-Child Relationships
$parent = new HTMLNode('div'); $child = $parent->addChild('span'); // Navigate relationships $parent === $child->getParent(); // true $parent->hasChild($child); // true $parent->childrenCount(); // 1
📄 HTML Document Creation
Complete Document Structure
use WebFiori\UI\HTMLDoc; $doc = new HTMLDoc(); // Configure document $doc->getHeadNode()->setPageTitle('My Application'); $doc->setLanguage('en'); $head = $doc->getHeadNode(); $head->addMeta('description', 'A powerful web application') ->addMeta('keywords', 'php, html, webfiori') ->addCSS('styles/main.css') ->addJs('scripts/app.js'); // Add structured content $body = $doc->getBody(); // Header section $header = $body->addChild('header', ['class' => 'site-header']); $header->addChild('h1')->text('My Application'); // Main content $main = $body->addChild('main', ['class' => 'main-content']); $main->addChild('h2')->text('Welcome'); $main->addChild('p')->text('This is the main content area.'); // Footer $footer = $body->addChild('footer', ['class' => 'site-footer']); $footer->addChild('p')->text('© 2024 My Application'); echo $doc;
Head Section Management
$head = $doc->getHeadNode(); // Add stylesheets $head->addCSS('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'); $head->addCSS('assets/custom.css', ['media' => 'screen']); // Add JavaScript $head->addJs('https://code.jquery.com/jquery-3.6.0.min.js'); $head->addJs('assets/app.js', ['defer' => '']); // Meta tags $head->addMeta('viewport', 'width=device-width, initial-scale=1.0'); $head->addMeta('author', 'Your Name'); // Custom head content $head->addChild('link', [ 'rel' => 'icon', 'type' => 'image/x-icon', 'href' => '/favicon.ico' ]);
🔧 Working with Elements
Element Creation and Manipulation
use WebFiori\UI\HTMLNode; // Create elements with attributes $container = new HTMLNode('div', [ 'id' => 'main-container', 'class' => 'container-fluid', 'data-role' => 'main' ]); // Add multiple children $container->addChild('h1', ['class' => 'title'])->text('Page Title'); $container->addChild('p', ['class' => 'description'])->text('Page description here.'); // Create complex nested structures $section = $container->addChild('section', ['class' => 'content']); $article = $section->addChild('article'); $article->addChild('h2')->text('Article Title'); $article->addChild('p')->text('Article content...');
Attribute Management
$element = new HTMLNode('div'); // Set single attributes $element->setAttribute('id', 'unique-id'); $element->setAttribute('class', 'btn btn-primary'); $element->setAttribute('data-toggle', 'modal'); // Set multiple attributes $element->setAttributes([ 'role' => 'button', 'tabindex' => '0', 'aria-label' => 'Close dialog' ]); // Get and check attributes if ($element->hasAttribute('id')) { $id = $element->getAttribute('id'); echo "Element ID: $id"; } // Remove attributes $element->removeAttribute('data-toggle');
Text Content and HTML Entities
$paragraph = new HTMLNode('p'); // Safe text (HTML entities escaped by default) $paragraph->text('User input: <script>alert("xss")</script>'); // Output: User input: <script>alert("xss")</script> // Raw HTML (use with caution) $paragraph->text('<strong>Bold text</strong>', false); // Output: <strong>Bold text</strong> // Add text nodes $container = new HTMLNode('div'); $container->addTextNode('Plain text content'); $container->addTextNode(' More text', true); // HTML entities escaped
Element Traversal and Manipulation
$list = new HTMLNode('ul'); $list->li('Item 1'); $list->li('Item 2'); $list->li('Item 3'); // Iterate over children foreach ($list as $index => $child) { echo "Child $index: " . $child->getText() . "\n"; } // Find specific children $firstChild = $list->getChild(0); $lastChild = $list->getChild($list->childrenCount() - 1); // Find by ID $specificElement = $list->getChildByID('special-item'); // Count children echo "Total items: " . count($list); // Countable interface echo "Total items: " . $list->childrenCount(); // Direct method
📝 Forms and Input
Complete Form Creation
use WebFiori\UI\HTMLDoc; $doc = new HTMLDoc(); $body = $doc->getBody(); // Create form container $formContainer = $body->div(['class' => 'form-container']); $formContainer->addChild('h2')->text('User Registration'); $form = $formContainer->form([ 'method' => 'post', 'action' => '/register', 'class' => 'registration-form', 'novalidate' => '' ]); // Personal Information Section $personalSection = $form->div(['class' => 'form-section']); $personalSection->addChild('h3')->text('Personal Information'); // First Name $firstNameGroup = $personalSection->div(['class' => 'form-group']); $firstNameGroup->addChild('label', ['for' => 'first-name'])->text('First Name *'); $firstNameGroup->input('text', [ 'id' => 'first-name', 'name' => 'first_name', 'required' => '', 'placeholder' => 'Enter your first name', 'class' => 'form-control' ]); // Email $emailGroup = $personalSection->div(['class' => 'form-group']); $emailGroup->addChild('label', ['for' => 'email'])->text('Email Address *'); $emailGroup->input('email', [ 'id' => 'email', 'name' => 'email', 'required' => '', 'placeholder' => 'your.email@example.com', 'class' => 'form-control' ]); // Password $passwordGroup = $personalSection->div(['class' => 'form-group']); $passwordGroup->addChild('label', ['for' => 'password'])->text('Password *'); $passwordGroup->input('password', [ 'id' => 'password', 'name' => 'password', 'required' => '', 'minlength' => '8', 'placeholder' => 'Minimum 8 characters', 'class' => 'form-control' ]); // Country Selection $countryGroup = $personalSection->div(['class' => 'form-group']); $countryGroup->addChild('label', ['for' => 'country'])->text('Country'); $countrySelect = $countryGroup->addChild('select', [ 'id' => 'country', 'name' => 'country', 'class' => 'form-control' ]); $countries = ['USA', 'Canada', 'UK', 'Germany', 'France', 'Japan']; $countrySelect->addChild('option', ['value' => ''])->text('Select a country'); foreach ($countries as $country) { $countrySelect->addChild('option', ['value' => strtolower($country)])->text($country); } // Bio/Comments $bioGroup = $personalSection->div(['class' => 'form-group']); $bioGroup->addChild('label', ['for' => 'bio'])->text('Bio (Optional)'); $bioGroup->addChild('textarea', [ 'id' => 'bio', 'name' => 'bio', 'rows' => '4', 'placeholder' => 'Tell us about yourself...', 'class' => 'form-control' ]); // Newsletter Subscription $newsletterGroup = $personalSection->div(['class' => 'form-group checkbox-group']); $newsletterGroup->input('checkbox', [ 'id' => 'newsletter', 'name' => 'newsletter', 'value' => '1' ]); $newsletterGroup->addChild('label', ['for' => 'newsletter'])->text('Subscribe to newsletter'); // Form Actions $actionsGroup = $form->div(['class' => 'form-actions']); $actionsGroup->input('submit', [ 'value' => 'Create Account', 'class' => 'btn btn-primary' ]); $actionsGroup->input('reset', [ 'value' => 'Clear Form', 'class' => 'btn btn-secondary' ]); echo $doc;
Advanced Input Types
// File upload $fileGroup = $form->div(['class' => 'form-group']); $fileGroup->addChild('label', ['for' => 'avatar'])->text('Profile Picture'); $fileGroup->input('file', [ 'id' => 'avatar', 'name' => 'avatar', 'accept' => 'image/*', 'class' => 'form-control' ]); // Range slider $rangeGroup = $form->div(['class' => 'form-group']); $rangeGroup->addChild('label', ['for' => 'experience'])->text('Years of Experience'); $rangeGroup->input('range', [ 'id' => 'experience', 'name' => 'experience', 'min' => '0', 'max' => '50', 'value' => '5', 'class' => 'form-control' ]); // Color picker $colorGroup = $form->div(['class' => 'form-group']); $colorGroup->addChild('label', ['for' => 'favorite-color'])->text('Favorite Color'); $colorGroup->input('color', [ 'id' => 'favorite-color', 'name' => 'favorite_color', 'value' => '#3498db', 'class' => 'form-control' ]); // Hidden fields $form->input('hidden', ['name' => 'csrf_token', 'value' => 'abc123']); $form->input('hidden', ['name' => 'form_id', 'value' => 'registration']);
📊 Tables and Data
Dynamic Data Tables
use WebFiori\UI\HTMLNode; // Create responsive data table $tableContainer = new HTMLNode('div', ['class' => 'table-responsive']); $table = $tableContainer->table([ 'class' => 'table table-striped table-hover', 'id' => 'users-table' ]); // Table header $thead = $table->addChild('thead', ['class' => 'table-dark']); $headerRow = $thead->tr(); $headerRow->addChild('th', ['scope' => 'col'])->text('#'); $headerRow->addChild('th', ['scope' => 'col'])->text('Name'); $headerRow->addChild('th', ['scope' => 'col'])->text('Email'); $headerRow->addChild('th', ['scope' => 'col'])->text('Role'); $headerRow->addChild('th', ['scope' => 'col'])->text('Status'); $headerRow->addChild('th', ['scope' => 'col'])->text('Actions'); // Table body with sample data $tbody = $table->addChild('tbody'); $users = [ ['id' => 1, 'name' => 'John Doe', 'email' => 'john@example.com', 'role' => 'Admin', 'status' => 'Active'], ['id' => 2, 'name' => 'Jane Smith', 'email' => 'jane@example.com', 'role' => 'Editor', 'status' => 'Active'], ['id' => 3, 'name' => 'Bob Johnson', 'email' => 'bob@example.com', 'role' => 'User', 'status' => 'Inactive'], ['id' => 4, 'name' => 'Alice Brown', 'email' => 'alice@example.com', 'role' => 'Moderator', 'status' => 'Active'] ]; foreach ($users as $user) { $row = $tbody->tr(['data-user-id' => $user['id']]); // ID column $row->addChild('td')->text($user['id']); // Name column $nameCell = $row->addChild('td'); $nameCell->text($user['name']); // Email column $emailCell = $row->addChild('td'); $emailCell->anchor($user['email'], [ 'href' => 'mailto:' . $user['email'], 'class' => 'text-decoration-none' ]); // Role column with badge $roleCell = $row->addChild('td'); $roleClass = match($user['role']) { 'Admin' => 'bg-danger', 'Editor' => 'bg-warning', 'Moderator' => 'bg-info', default => 'bg-secondary' }; $roleCell->addChild('span', ['class' => "badge $roleClass"])->text($user['role']); // Status column $statusCell = $row->addChild('td'); $statusClass = $user['status'] === 'Active' ? 'text-success' : 'text-muted'; $statusIcon = $user['status'] === 'Active' ? '●' : '○'; $statusCell->addChild('span', ['class' => $statusClass])->text("$statusIcon {$user['status']}"); // Actions column $actionsCell = $row->addChild('td'); $actionGroup = $actionsCell->div(['class' => 'btn-group btn-group-sm']); $actionGroup->addChild('button', [ 'class' => 'btn btn-outline-primary', 'data-bs-toggle' => 'tooltip', 'title' => 'Edit User' ])->text('Edit'); $actionGroup->addChild('button', [ 'class' => 'btn btn-outline-secondary', 'data-bs-toggle' => 'tooltip', 'title' => 'View Details' ])->text('View'); $actionGroup->addChild('button', [ 'class' => 'btn btn-outline-danger', 'data-bs-toggle' => 'tooltip', 'title' => 'Delete User' ])->text('Delete'); } echo $tableContainer->toHTML(true);
📋 Lists and Navigation
Navigation Menus
use WebFiori\UI\HTMLNode; // Main navigation $nav = new HTMLNode('nav', ['class' => 'navbar navbar-expand-lg navbar-dark bg-dark']); $container = $nav->div(['class' => 'container']); // Brand $brand = $container->anchor('WebFiori UI', [ 'class' => 'navbar-brand', 'href' => '/' ]); // Toggle button for mobile $toggleBtn = $container->addChild('button', [ 'class' => 'navbar-toggler', 'type' => 'button', 'data-bs-toggle' => 'collapse', 'data-bs-target' => '#navbarNav' ]); $toggleBtn->addChild('span', ['class' => 'navbar-toggler-icon']); // Navigation items $collapseDiv = $container->div([ 'class' => 'collapse navbar-collapse', 'id' => 'navbarNav' ]); $navList = $collapseDiv->ul(['class' => 'navbar-nav me-auto']); $menuItems = [ ['text' => 'Home', 'href' => '/', 'active' => true], ['text' => 'Documentation', 'href' => '/docs'], ['text' => 'Examples', 'href' => '/examples'], ['text' => 'API Reference', 'href' => '/api'] ]; foreach ($menuItems as $item) { $li = $navList->li(['class' => 'nav-item']); $linkClass = 'nav-link' . (isset($item['active']) ? ' active' : ''); $link = $li->anchor($item['text'], [ 'class' => $linkClass, 'href' => $item['href'] ]); if (isset($item['active'])) { $link->setAttribute('aria-current', 'page'); } } echo $nav->toHTML(true);
Nested Lists
// Complex nested list structure $nestedList = new HTMLNode('ul', ['class' => 'nested-list']); // Programming Languages $langItem = $nestedList->li('Programming Languages'); $langSublist = $langItem->ul(['class' => 'nested-sublist']); $frontendItem = $langSublist->li('Frontend'); $frontendSublist = $frontendItem->ul(); $frontendSublist->li('JavaScript'); $frontendSublist->li('TypeScript'); $frontendSublist->li('CSS/SCSS'); $backendItem = $langSublist->li('Backend'); $backendSublist = $backendItem->ul(); $backendSublist->li('PHP'); $backendSublist->li('Python'); $backendSublist->li('Node.js'); echo $nestedList->toHTML(true);
🖼️ Images and Media
Image Galleries and Media Components
use WebFiori\UI\HTMLNode; // Hero section with background image $hero = new HTMLNode('section', ['class' => 'hero-section']); $hero->setStyle([ 'background-image' => 'url("images/hero-bg.jpg")', 'background-size' => 'cover', 'background-position' => 'center', 'min-height' => '500px' ]); $heroContent = $hero->div(['class' => 'hero-content']); $heroContent->addChild('h1', ['class' => 'hero-title'])->text('Welcome to Our Site'); $heroContent->addChild('p', ['class' => 'hero-subtitle'])->text('Discover amazing content'); // Responsive image with multiple sources $picture = new HTMLNode('picture', ['class' => 'responsive-image']); $picture->addChild('source', [ 'media' => '(min-width: 1200px)', 'srcset' => 'images/large.jpg' ]); $picture->addChild('source', [ 'media' => '(min-width: 768px)', 'srcset' => 'images/medium.jpg' ]); $picture->img([ 'src' => 'images/small.jpg', 'alt' => 'Responsive image', 'class' => 'img-fluid' ]); // Image gallery $gallery = new HTMLNode('div', ['class' => 'image-gallery']); $galleryTitle = $gallery->addChild('h2', ['class' => 'gallery-title'])->text('Photo Gallery'); $galleryGrid = $gallery->div(['class' => 'gallery-grid']); $images = [ ['src' => 'gallery/photo1.jpg', 'alt' => 'Beautiful landscape', 'caption' => 'Mountain View'], ['src' => 'gallery/photo2.jpg', 'alt' => 'City skyline', 'caption' => 'Urban Life'], ['src' => 'gallery/photo3.jpg', 'alt' => 'Ocean waves', 'caption' => 'Peaceful Waters'] ]; foreach ($images as $image) { $galleryItem = $galleryGrid->div(['class' => 'gallery-item']); $imageLink = $galleryItem->anchor('', [ 'href' => $image['src'], 'class' => 'gallery-link', 'data-lightbox' => 'gallery', 'data-title' => $image['caption'] ]); $imageLink->img([ 'src' => str_replace('.jpg', '_thumb.jpg', $image['src']), 'alt' => $image['alt'], 'class' => 'gallery-thumbnail', 'loading' => 'lazy' ]); $caption = $galleryItem->div(['class' => 'gallery-caption']); $caption->text($image['caption']); } echo $hero->toHTML(true); echo $picture->toHTML(true); echo $gallery->toHTML(true);
🎨 Template System
HTML Templates with Slots
Create reusable HTML templates with placeholder slots:
template.html:
<!DOCTYPE html> <html lang="{{lang}}"> <head> <title>{{page-title}}</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="{{page-description}}"> </head> <body> <header class="{{header-class}}"> <h1>{{site-name}}</h1> <nav>{{navigation}}</nav> </header> <main class="{{main-class}}"> <section class="hero"> <h2>{{hero-title}}</h2> <p>{{hero-subtitle}}</p> </section> <section class="content"> {{main-content}} </section> </main> <footer class="{{footer-class}}"> <p>© {{current-year}} {{site-name}}. All rights reserved.</p> </footer> </body> </html>
Using the template:
use WebFiori\UI\HTMLNode; $document = HTMLNode::fromFile('template.html', [ 'lang' => 'en', 'page-title' => 'Welcome to WebFiori UI', 'page-description' => 'A powerful PHP library for HTML generation', 'site-name' => 'WebFiori UI', 'header-class' => 'site-header bg-primary', 'main-class' => 'main-content container', 'footer-class' => 'site-footer bg-dark text-white', 'hero-title' => 'Build Amazing Web Pages', 'hero-subtitle' => 'With object-oriented PHP and clean code', 'navigation' => '<a href="/">Home</a> | <a href="/docs">Docs</a>', 'main-content' => '<p>Welcome to our amazing website built with WebFiori UI!</p>', 'current-year' => date('Y') ]); echo $document;
PHP Templates with Logic
Create dynamic templates with PHP logic:
blog-post.php:
<article class="blog-post"> <header class="post-header"> <h1 class="post-title"><?= htmlspecialchars($title) ?></h1> <div class="post-meta"> <span class="author">By <?= htmlspecialchars($author) ?></span> <span class="date"><?= date('F j, Y', strtotime($publishDate)) ?></span> <?php if (!empty($tags)): ?> <div class="tags"> <?php foreach ($tags as $tag): ?> <span class="tag"><?= htmlspecialchars($tag) ?></span> <?php endforeach; ?> </div> <?php endif; ?> </div> </header> <div class="post-content"> <?= $content ?> </div> <?php if (!empty($comments)): ?> <section class="comments"> <h3>Comments (<?= count($comments) ?>)</h3> <?php foreach ($comments as $comment): ?> <div class="comment"> <div class="comment-author"><?= htmlspecialchars($comment['author']) ?></div> <div class="comment-date"><?= date('M j, Y', strtotime($comment['date'])) ?></div> <div class="comment-content"><?= htmlspecialchars($comment['content']) ?></div> </div> <?php endforeach; ?> </section> <?php endif; ?> </article>
Using the PHP template:
$blogPost = HTMLNode::fromFile('blog-post.php', [ 'title' => 'Getting Started with WebFiori UI', 'author' => 'John Developer', 'publishDate' => '2024-01-15', 'tags' => ['PHP', 'HTML', 'Web Development', 'Tutorial'], 'content' => '<p>WebFiori UI is a powerful library...</p><p>In this tutorial, we will explore...</p>', 'comments' => [ [ 'author' => 'Jane Reader', 'date' => '2024-01-16', 'content' => 'Great tutorial! Very helpful.' ], [ 'author' => 'Bob Coder', 'date' => '2024-01-17', 'content' => 'Thanks for sharing this. Looking forward to more posts.' ] ] ]); echo $blogPost->toHTML(true);
🎨 Styling and CSS
CSS Management
use WebFiori\UI\HTMLNode; $element = new HTMLNode('div'); // Set individual styles $element->setStyle([ 'background-color' => '#f8f9fa', 'border' => '1px solid #dee2e6', 'border-radius' => '0.375rem', 'padding' => '1rem', 'margin-bottom' => '1rem', 'box-shadow' => '0 0.125rem 0.25rem rgba(0, 0, 0, 0.075)' ]); // Add more styles without overriding $element->setStyle([ 'transition' => 'all 0.3s ease', 'cursor' => 'pointer' ], false); // Override specific styles $element->setStyle([ 'background-color' => '#e9ecef' ], true); // CSS classes management $element->setClassName('card'); $element->applyClass('shadow-sm'); $element->applyClass('hover-effect'); // Conditional styling $isActive = true; if ($isActive) { $element->applyClass('active'); $element->setStyle(['border-color' => '#0d6efd']); } echo $element->toHTML(true);
Responsive Design
// Create responsive grid $container = new HTMLNode('div', ['class' => 'container-fluid']); $row = $container->div(['class' => 'row']); // Responsive columns $columns = [ ['size' => 'col-12 col-md-6 col-lg-4', 'content' => 'Column 1'], ['size' => 'col-12 col-md-6 col-lg-4', 'content' => 'Column 2'], ['size' => 'col-12 col-md-12 col-lg-4', 'content' => 'Column 3'] ]; foreach ($columns as $col) { $column = $row->div(['class' => $col['size']]); $card = $column->div(['class' => 'card h-100']); $cardBody = $card->div(['class' => 'card-body']); $cardBody->addChild('p', ['class' => 'card-text'])->text($col['content']); } // Responsive utilities $hiddenOnMobile = new HTMLNode('div', ['class' => 'd-none d-md-block']); $hiddenOnMobile->text('This content is hidden on mobile devices'); $visibleOnMobile = new HTMLNode('div', ['class' => 'd-block d-md-none']); $visibleOnMobile->text('This content is only visible on mobile devices'); echo $container->toHTML(true); echo $hiddenOnMobile->toHTML(true); echo $visibleOnMobile->toHTML(true);
🚀 Advanced Features
Iterator and Countable Interfaces
WebFiori UI implements PHP's Iterator and Countable interfaces for seamless traversal:
use WebFiori\UI\HTMLNode; $menu = new HTMLNode('ul', ['class' => 'main-menu']); $menu->li('Home'); $menu->li('About'); $menu->li('Services'); $menu->li('Contact'); // Iterate using foreach foreach ($menu as $index => $menuItem) { echo "Menu item $index: " . $menuItem->getText() . "\n"; // Add CSS class to each item $menuItem->applyClass('menu-item'); // Add click handler $menuItem->setAttribute('onclick', "handleMenuClick('$index')"); } // Count children echo "Total menu items: " . count($menu) . "\n"; echo "Using childrenCount(): " . $menu->childrenCount() . "\n"; // Manual iteration control $menu->rewind(); while ($menu->valid()) { $current = $menu->current(); $key = $menu->key(); echo "Processing item at position $key\n"; $menu->next(); }
XML Document Generation
use WebFiori\UI\HTMLNode; // Create SAML assertion $assertion = new HTMLNode('saml:Assertion', [ 'xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion', 'xmlns:xs' => 'http://www.w3.org/2001/XMLSchema', 'ID' => '_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75', 'Version' => '2.0', 'IssueInstant' => '2004-12-05T09:22:05Z' ]); // Add issuer $assertion->addChild('saml:Issuer')->text('https://idp.example.org/SAML2'); // Add subject $subject = $assertion->addChild('saml:Subject'); $nameId = $subject->addChild('saml:NameID', [ 'Format' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' ]); $nameId->text('user@example.com'); // Add conditions $conditions = $assertion->addChild('saml:Conditions', [ 'NotBefore' => '2004-12-05T09:17:05Z', 'NotOnOrAfter' => '2004-12-05T09:27:05Z' ]); $audienceRestriction = $conditions->addChild('saml:AudienceRestriction'); $audienceRestriction->addChild('saml:Audience')->text('https://sp.example.com/SAML2'); // Generate XML echo $assertion->toXML(true);
⚡ Performance Tips
Optimizing HTML Output
use WebFiori\UI\HTMLNode; // For production: Use unformatted output $container = new HTMLNode('div'); $container->addChild('p')->text('Content here'); // Compact output (recommended for production) $compactHTML = $container->toHTML(false); echo "Compact size: " . strlen($compactHTML) . " bytes\n"; // Formatted output (for development/debugging) $formattedHTML = $container->toHTML(true); echo "Formatted size: " . strlen($formattedHTML) . " bytes\n"; // Size difference can be significant with large DOMs echo "Size difference: " . (strlen($formattedHTML) - strlen($compactHTML)) . " bytes\n";
Memory Management
// Batch operations for better performance $largeList = new HTMLNode('ul', ['class' => 'large-list']); // Instead of adding children one by one: // for ($i = 0; $i < 10000; $i++) { // $largeList->li("Item $i"); // } // Use build() method for batch operations: $items = []; for ($i = 0; $i < 10000; $i++) { $items[] = ['li', ['class' => 'list-item'], "Item $i"]; } $largeList->build($items); // Clean up large objects when done unset($largeList); // Use text nodes for plain text content $textNode = new HTMLNode(HTMLNode::TEXT_NODE); $textNode->setText('Large amount of plain text content...');
Efficient Styling
// Prefer CSS classes over inline styles $element = new HTMLNode('div'); // Less efficient (inline styles) $element->setStyle([ 'color' => 'red', 'font-size' => '14px', 'margin' => '10px' ]); // More efficient (CSS classes) $element->setClassName('text-danger fs-6 m-2'); // Batch style operations $styles = [ 'background-color' => '#f8f9fa', 'border' => '1px solid #dee2e6', 'border-radius' => '0.375rem', 'padding' => '1rem' ]; $element->setStyle($styles); // Single operation instead of multiple calls
📚 API Reference
Core Classes
HTMLNode
The foundation class for all HTML elements.
Constructor:
public function __construct(string $name = 'div', array $attrs = [])
Key Methods:
Method | Parameters | Return | Description |
---|---|---|---|
addChild() |
$node, $attrs = [], $chainOnParent = false |
HTMLNode |
Adds a child element |
setAttribute() |
string $name, mixed $val = null |
HTMLNode |
Sets an attribute |
setAttributes() |
array $attrs |
HTMLNode |
Sets multiple attributes |
getAttribute() |
string $name |
string|null |
Gets attribute value |
hasAttribute() |
string $name |
bool |
Checks if attribute exists |
removeAttribute() |
string $name |
HTMLNode |
Removes an attribute |
setStyle() |
array $styles, bool $override = false |
HTMLNode |
Sets CSS styles |
setClassName() |
string $class, bool $override = true |
HTMLNode |
Sets CSS class |
applyClass() |
string $class, bool $override = true |
HTMLNode |
Applies CSS class |
text() |
string $text, bool $escEntities = true |
HTMLNode |
Sets text content |
setText() |
string $text, bool $escEntities = true |
HTMLNode |
Sets text content |
getText() |
- | string |
Gets text content |
toHTML() |
bool $formatted = false, int $initTab = 0 |
string |
Generates HTML |
toXML() |
bool $formatted = false |
string |
Generates XML |
Element Creation Methods:
Method | Parameters | Return | Description |
---|---|---|---|
div() |
array $attrs = [] |
HTMLNode |
Creates div element |
form() |
array $attrs = [] |
HTMLNode |
Creates form element |
input() |
string $type = 'text', array $attrs = [] |
HTMLNode |
Creates input element |
table() |
array $attrs = [] |
HTMLNode |
Creates table element |
tr() |
array $data = [], array $attrs = [], bool $headerRow = false |
HTMLNode |
Creates table row |
ul() |
array $items = [], array $attrs = [] |
HTMLNode |
Creates unordered list |
ol() |
array $items = [], array $attrs = [] |
HTMLNode |
Creates ordered list |
li() |
$body, array $attrs = [] |
HTMLNode |
Creates list item |
img() |
array $attrs = [] |
HTMLNode |
Creates image element |
anchor() |
string|HTMLNode $body, array $attrs = [] |
HTMLNode |
Creates anchor element |
paragraph() |
string|HTMLNode $body = '', array $attrs = [], bool $escEntities = true |
HTMLNode |
Creates paragraph |
HTMLDoc
Represents a complete HTML document.
Constructor:
public function __construct()
Key Methods:
Method | Parameters | Return | Description |
---|---|---|---|
getBody() |
- | HTMLNode |
Gets the body element |
getHeadNode() |
- | HeadNode |
Gets the head element |
setPageTitle() |
string $title |
HTMLDoc |
Sets document title |
getPageTitle() |
- | string |
Gets document title |
setLanguage() |
string $lang |
HTMLDoc |
Sets document language |
getLanguage() |
- | string |
Gets document language |
HeadNode
Represents the HTML head section.
Key Methods:
Method | Parameters | Return | Description |
---|---|---|---|
addCSS() |
string $href, array $attrs = [] |
HeadNode |
Adds CSS file |
addJs() |
string $src, array $attrs = [] |
HeadNode |
Adds JavaScript file |
addMeta() |
string $name, string $content, array $attrs = [] |
HeadNode |
Adds meta tag |
setPageTitle() |
string $title |
HeadNode |
Sets page title |
Constants
Constant | Value | Description |
---|---|---|
HTMLNode::COMMENT_NODE |
'#COMMENT' |
Identifies comment nodes |
HTMLNode::TEXT_NODE |
'#TEXT' |
Identifies text nodes |
HTMLNode::VOID_TAGS |
array |
List of void HTML tags |
Static Methods
Method | Parameters | Return | Description |
---|---|---|---|
HTMLNode::fromFile() |
string $path, array $vars = [] |
HTMLNode|HTMLDoc|array |
Creates nodes from template |
Interfaces
WebFiori UI implements standard PHP interfaces:
- Iterator: Allows foreach loops over child nodes
- Countable: Enables
count()
function on nodes
🎯 Examples
Complete Web Page
<?php require_once 'vendor/autoload.php'; use WebFiori\UI\HTMLDoc; // Create a complete responsive web page $doc = new HTMLDoc(); $doc->getHeadNode()->setPageTitle('WebFiori UI Demo'); $doc->setLanguage('en'); // Add CSS and JavaScript $head = $doc->getHeadNode(); $head->addCSS('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'); $head->addCSS('assets/custom.css'); $head->addJs('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js'); $body = $doc->getBody(); // Navigation $nav = $body->addChild('nav', ['class' => 'navbar navbar-expand-lg navbar-dark bg-primary']); $navContainer = $nav->div(['class' => 'container']); $navContainer->anchor('WebFiori UI Demo', ['class' => 'navbar-brand', 'href' => '#']); // Hero section $hero = $body->addChild('section', ['class' => 'hero bg-light py-5']); $heroContainer = $hero->div(['class' => 'container text-center']); $heroContainer->addChild('h1', ['class' => 'display-4'])->text('Welcome to WebFiori UI'); $heroContainer->addChild('p', ['class' => 'lead'])->text('Build amazing web interfaces with PHP'); $heroContainer->addChild('button', ['class' => 'btn btn-primary btn-lg'])->text('Get Started'); // Features section $features = $body->addChild('section', ['class' => 'features py-5']); $featuresContainer = $features->div(['class' => 'container']); $featuresContainer->addChild('h2', ['class' => 'text-center mb-5'])->text('Features'); $featuresRow = $featuresContainer->div(['class' => 'row']); $featuresList = [ ['title' => 'Object-Oriented', 'description' => 'Clean, maintainable code with OOP principles'], ['title' => 'Template Support', 'description' => 'HTML and PHP templates with variable injection'], ['title' => 'Type Safety', 'description' => 'Full type hints and comprehensive documentation'] ]; foreach ($featuresList as $feature) { $col = $featuresRow->div(['class' => 'col-md-4 mb-4']); $card = $col->div(['class' => 'card h-100']); $cardBody = $card->div(['class' => 'card-body']); $cardBody->addChild('h5', ['class' => 'card-title'])->text($feature['title']); $cardBody->addChild('p', ['class' => 'card-text'])->text($feature['description']); } // Footer $footer = $body->addChild('footer', ['class' => 'bg-dark text-white py-4']); $footerContainer = $footer->div(['class' => 'container text-center']); $footerContainer->addChild('p')->text('© 2024 WebFiori UI. Built with ❤️ and PHP.'); echo $doc; ?>
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Clone the repository
- Install dependencies:
composer install
- Run tests:
composer test
- Check code style:
composer cs-check
📄 License
This library is licensed under the MIT License. See the LICENSE file for details.