Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Html Builder Laravel Package

21torr/html-builder

Fluent HTML builder for Laravel/PHP. Programmatically compose tags, attributes, and nested elements with a clean API to generate consistent markup without mixing large HTML strings into your views or controllers.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require 21torr/html-builder
    

    No additional configuration is required—just autoload the package.

  2. First Use Case: Generate a simple HTML element (e.g., a button) with attributes and nested content:

    use HtmlBuilder\Html;
    
    $button = Html::tag('button')
        ->withAttributes(['class' => 'btn btn-primary'])
        ->withText('Click Me')
        ->render();
    
    echo $button;
    

    Output:

    <button class="btn btn-primary">Click Me</button>
    
  3. Key Classes to Explore:

    • Html::tag(): Start building an element.
    • ->withAttributes(): Add attributes (e.g., class, id, data-*).
    • ->withText()/->withHtml(): Add content (sanitized or raw).
    • ->render(): Output the final HTML string.
    • New in 2.1.0: ->getParent(): Retrieve the parent element of a nested child.

Implementation Patterns

Common Workflows

  1. Dynamic Element Generation: Use loops or conditionals to build reusable components:

    $items = ['Home', 'About', 'Contact'];
    $nav = Html::tag('nav');
    
    foreach ($items as $item) {
        $nav->addChild(
            Html::tag('a')
                ->withAttributes(['href' => route('page', $item)])
                ->withText($item)
        );
    }
    
  2. Nested Structures with Parent Access: Build complex HTML hierarchies and traverse upward using getParent():

    $card = Html::tag('div', ['class' => 'card']);
    $body = Html::tag('div', ['class' => 'card-body']);
    $card->addChild($body);
    
    $body->addChild(
        Html::tag('h5')->withText('Title')
    );
    
    // Access parent from child
    $parentClass = $body->getParent()->getAttributes()['class'];
    // $parentClass = 'card'
    
  3. Integration with Laravel Blade: Create helper functions in app/Helpers/html.php:

    if (!function_exists('btn')) {
        function btn(string $text, array $attrs = []): string {
            return Html::tag('button')
                ->withAttributes($attrs)
                ->withText($text)
                ->render();
        }
    }
    

    Usage in Blade:

    {!! btn('Submit', ['class' => 'btn-danger']) !!}
    
  4. Form Handling: Generate forms with CSRF protection and validation:

    $form = Html::tag('form', [
        'action' => route('submit'),
        'method' => 'POST',
    ])->withHtml(csrf_field());
    
    $form->addChild(
        Html::tag('input')
            ->withAttributes([
                'type' => 'text',
                'name' => 'email',
                'value' => old('email'),
            ])
    );
    

Integration Tips

  • Sanitization: Use ->withText() for auto-escaping; ->withHtml() for raw output (be cautious with user input).
  • Laravel Collective: Combine with Form/Html helpers for consistency:
    use HtmlBuilder\Html;
    use Illuminate\Support\Facades\Html as LaravelHtml;
    
    $link = Html::tag('a')
        ->withAttributes([
            'href' => LaravelHtml::route('profile'),
        ])
        ->withText('Profile');
    
  • Testing: Mock Html instances in unit tests:
    $htmlMock = Mockery::mock('overload:\HtmlBuilder\Html');
    $htmlMock->shouldReceive('tag')->andReturnSelf();
    $htmlMock->shouldReceive('render')->andReturn('<div>Test</div>');
    $htmlMock->shouldReceive('getParent')->andReturnNull();
    

Gotchas and Tips

Pitfalls

  1. Double Escaping: Chaining withText() and withHtml() may lead to double-escaping. Prefer one or the other per element:

    // ❌ Avoid:
    Html::tag('div')->withText('<strong>Bold</strong>')->withHtml('...');
    
    // ✅ Do:
    Html::tag('div')->withHtml('<strong>Bold</strong>');
    
  2. Attribute Injection: User-provided attributes (e.g., from requests) can introduce XSS. Sanitize or whitelist:

    $safeAttrs = collect($request->input('attrs', []))
        ->filter(fn($v) => !str_starts_with($v, 'on'))
        ->toArray();
    
  3. Memory Leaks: Avoid storing large Html instances in session/cache. Render to string immediately:

    // ❌ Bad:
    $session->put('html', $complexHtmlInstance);
    
    // ✅ Good:
    $session->put('html', $complexHtmlInstance->render());
    
  4. Parent Access Edge Cases: Calling getParent() on a root element (not added as a child) returns null. Always check:

    if ($child->getParent()) {
        $parentAttrs = $child->getParent()->getAttributes();
    }
    

Debugging

  • Inspect Attributes: Use getAttributes() to debug attribute bags:
    $element = Html::tag('div')->withAttributes(['data-id' => 1]);
    dd($element->getAttributes()); // ['data-id' => '1']
    
  • Render Early: Call render() at each step to catch errors:
    $element = Html::tag('div');
    $element->withText('Test')->render(); // Fail fast if invalid.
    
  • Parent Chain Inspection: Traverse upward to debug nested structures:
    $child = Html::tag('span');
    $parent = Html::tag('div')->addChild($child);
    
    $current = $child;
    while ($current->getParent()) {
        $current = $current->getParent();
        dd($current->getAttributes()); // Inspect each parent
    }
    

Extension Points

  1. Custom Tags: Extend the builder for domain-specific tags (e.g., Html::tag('alert')):

    Html::macro('alert', function($type, $message) {
        return Html::tag('div', ['class' => "alert alert-$type"])
            ->withText($message);
    });
    

    Usage:

    Html::alert('danger', 'Error!')->render();
    
  2. Attribute Modifiers: Add methods to modify attributes dynamically:

    Html::macro('addClass', function($class) {
        $this->withAttributes(['class' => $this->getAttribute('class', '') . ' ' . $class]);
        return $this;
    });
    

    Usage:

    Html::tag('div')->addClass('active')->render();
    
  3. Event Listeners: Hook into the rendering process for analytics or logging:

    Html::macro('onRender', function($callback) {
        $originalRender = $this->render;
        return function() use ($originalRender, $callback) {
            $html = $originalRender();
            return $callback($html, $this);
        };
    });
    

    Usage:

    $element->onRender(function($html, $element) {
        // Log element structure.
        return $html;
    });
    
  4. Parent-Aware Macros: Leverage getParent() to create macros that interact with the DOM hierarchy:

    Html::macro('getGrandParent', function() {
        return $this->getParent()?->getParent();
    });
    

    Usage:

    $grandParentClass = $child->getGrandParent()?->getAttributes()['class'] ?? null;
    

Configuration Quirks

  • No Global Config: The package is stateless; all behavior is method-based.
  • Namespace Collisions: Prefix custom macros to avoid conflicts:
    Html::macro('myApp\alert', function(...) { ... });
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity