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 Element Laravel Package

spatie/html-element

Generate dynamic HTML in PHP with a hyperscript-style API plus Emmet-like selectors. Build elements and attributes with a simple render helper (often wrapped as el()) to produce nested markup cleanly and programmatically, ideal for small view components.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/html-element
    

    No additional configuration is required—just autoload.

  2. First Render: Use the static HtmlElement::render() method or create a helper function:

    use Spatie\HtmlElement\HtmlElement;
    
    // Direct usage
    echo HtmlElement::render('div', ['class' => 'container'], 'Hello');
    
    // Recommended helper (add to a service provider or helper file)
    function el(...$args) {
        return HtmlElement::render(...$args);
    }
    
  3. First Use Case: Render a Bootstrap card with nested elements:

    echo el('div.card',
        el('div.card-header', 'Title'),
        el('div.card-body', 'Content goes here')
    );
    

Implementation Patterns

Core Workflows

  1. Element Creation:

    • Basic: el('tag', ['attr' => 'value'], 'Content')
    • Nested: Chain elements via arguments:
      el('div.container',
          el('h1', 'Title'),
          el('p', 'Body')
      )
      
    • Emmet-like Syntax: Use > for nesting or + for siblings:
      el('div.container > div.row + div.footer')
      
  2. Dynamic Attributes:

    • Merge attributes dynamically:
      $attrs = ['class' => 'btn', 'data-id' => $id];
      el('button', $attrs, 'Click Me');
      
    • Use closures for dynamic content:
      el('div', [], function($el) {
          $el->setAttribute('data-user', auth()->id());
      });
      
  3. Event Handling: Attach JavaScript events via onclick, onchange, etc.:

    el('button', ['onclick' => 'alert("Clicked!")'], 'Submit');
    
  4. Integration with Blade: Create a Blade directive for reusable components:

    // In a service provider
    Blade::directive('element', function ($expression) {
        return "<?php echo \\Spatie\\HtmlElement\\HtmlElement::render($expression); ?>";
    });
    

    Usage:

    @element('div.alert', ['class' => 'success'], 'Success!')
    
  5. Component-Based Rendering: Encapsulate complex elements in functions:

    function card($title, $content) {
        return el('div.card',
            el('div.card-header', $title),
            el('div.card-body', $content)
        );
    }
    

Gotchas and Tips

Pitfalls

  1. Attribute Escaping:

    • All attributes and content are auto-escaped for security. To disable escaping (use cautiously):
      el('div', [], 'Raw <script>alert("XSS")</script>', false);
      
  2. Emmet Syntax Limitations:

    • Emmet-like syntax (>, +) only works for the first argument. Nested elements must use explicit chaining:
      // Works
      el('div.container > div.row')
      
      // Fails (use chaining instead)
      el('div.container', 'div.row > div.col')
      
  3. Closure Scope:

    • Closures passed to setAttribute or setContent run after the element is created. Avoid relying on parent scope variables:
      $user = auth()->user();
      el('div', [], function($el) use ($user) {
          $el->setAttribute('data-id', $user->id); // Correct
      });
      
  4. Performance:

    • Avoid deeply nested el() calls in loops. Pre-render static HTML and concatenate:
      // Bad (nested calls in loop)
      foreach ($items as $item) {
          el('div.item', [], $item);
      }
      
      // Good (pre-render)
      $html = '';
      foreach ($items as $item) {
          $html .= HtmlElement::render('div.item', [], $item);
      }
      

Debugging Tips

  1. Inspect Rendered HTML: Use HtmlElement::renderToString() to debug output:

    $html = HtmlElement::renderToString('div', [], 'Test');
    dd($html); // Inspect raw HTML
    
  2. Attribute Conflicts: If attributes are ignored, check for typos or reserved keywords (e.g., class vs className).

  3. Closure Debugging: Add dd($el) inside closures to inspect the element state:

    el('div', [], function($el) {
        dd($el->attributes); // Debug attributes
    });
    

Extension Points

  1. Custom Elements: Extend Spatie\HtmlElement\HtmlElement to add methods:

    class CustomElement extends HtmlElement {
        public static function button($text, $callback) {
            return static::render('button', [
                'onclick' => "{$callback}()"
            ], $text);
        }
    }
    
  2. Attribute Modifiers: Use the modifyAttributes method to transform attributes:

    el('input', ['type' => 'text'], '', function($attrs) {
        $attrs['data-processed'] = 'true';
        return $attrs;
    });
    
  3. Event Delegation: For complex event handling, attach data attributes and use JavaScript:

    el('div', [
        'data-on-click' => 'handleClick',
        'data-id' => $id
    ], 'Clickable');
    

    Then use JavaScript to listen for data-on-click events.

  4. Integration with Laravel Collectives: Combine with HTML facade for seamless Blade integration:

    use Collective\Html\Html as HtmlHelper;
    
    echo HtmlHelper::script(HtmlElement::renderToString('script', [], 'alert("Hello")'));
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport