Weave 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

Render Html Attributes Laravel Package

piedweb/render-html-attributes

piedweb/render-html-attributes is a small PHP helper for converting arrays of attributes into safe, correctly escaped HTML attribute strings. It simplifies building reusable Blade components and tags, handling booleans, class arrays, and conditional attributes with clean, readable syntax.

View on GitHub
Deep Wiki
Context7

Getting Started

What it actually does: exposes a Twig filter/function that takes a PHP associative array and renders it as a space-separated list of key="value" attribute pairs. That's the whole surface area — treat it as a one-function helper, not a framework.

Install

composer require piedweb/render-html-attributes

Laravel reality check first. Laravel does not ship Twig. Before installing, decide which situation you're in:

  • Blade project → you almost certainly don't need this. Laravel 9+ has the built-in @attributes directive, and every version has Illuminate\Support\HtmlString / Html::attributes($array). See Gotchas below.
  • Twig project (via rcrowe/twigbridge, or a legacy Symfony/Twig app inside a Laravel monolith) → this is a drop-in convenience.

Register the extension with Twigbridge in config/twigbridge.php:

'extensions' => [
    'enabled' => [
        // whatever the extension class is named — read src/ to confirm,
        // it will be something like PiedWeb\RenderHtmlAttribute\Twig\RenderHtmlAttributeExtension
    ],
],

Then confirm the registration:

php artisan twig:clean
php artisan twig:lint resources/views

First use case — a reusable partial that needs to accept arbitrary attributes from the caller:

{# resources/views/components/button.twig #}
<button {{ attributes|render_html_attributes }}>
    {{ slot }}
</button>

Called as {% include 'components/button.twig' with { attributes: { class: 'btn btn-primary', disabled: true } } %}.

Where to look first: the README (it's tiny), then src/ to confirm the exact filter name and how it handles null/false/true. The implementation is likely < 40 lines, so read it before you rely on it — 5 stars and 0 dependents means you are the QA team.

Implementation Patterns

Conditional attributes. The main reason to want an array-based renderer is that you can build the array in PHP/Twig and let null/false values disappear. This is the pattern that pays for itself:

{% set attrs = {
    class: ['btn', is_active ? 'btn-active' : ''],
    'data-id': item.id,
    disabled: not item.canEdit,
    title: item.tooltip,   {# null when absent #}
} %}
<button {{ attrs|render_html_attributes }}>Edit</button>

Verify in the source that null and false are skipped rather than rendered as title="" — this is the single behavioral detail that determines whether the package is useful or a liability. If it doesn't handle it, wrap it.

Passing attributes through Blade → Twig boundaries. If you're mid-migration and a Blade view includes a Twig partial (or vice versa), normalize to an array at the boundary and render once. Don't assemble attribute strings by hand in one layer and pass them as arrays in another.

Component/partial props pattern. The idiomatic use is a "leaf" component that forwards unknown props to the root element:

{# card.twig #}
{% set root_attrs = { class: 'card' }|merge(attributes ?? {}) %}
<div {{ root_attrs|render_html_attributes }}>
    {% block content %}{% endblock %}
</div>

This keeps the component API open-ended (data-*, aria-*, id) without enumerating every prop.

Integration with form/HTML builders. If you're generating field arrays from a schema (labels, validation state, aria-invalid, aria-describedby), build the attribute array in the same place you build the field definition and render it in the view. It keeps accessibility wiring out of template conditionals.

Wrap it, don't sprinkle it. Create one Twig macro or a single Blade @attributes equivalent and use that everywhere:

{% macro attrs(array) %}{{ array|render_html_attributes }}{% endmacro %}

If the package is abandoned tomorrow (plausible at 5 stars), you swap one file.

Test it in your own suite. Since there are 0 dependents, there's no ecosystem signal that edge cases work. Add one test asserting the output for: string value, numeric value, null, false, true, empty string, and a data-* key with a value containing a quote.

Gotchas and Tips

You probably already have this. If you're on Blade, don't add a dependency for attribute rendering. Use:

<button {{ $attributes->merge(['class' => 'btn']) }}>…</button>  {{-- Blade components, L7+ --}}
<div @attributes(['class' => 'card', 'data-id' => $id])>       {{-- @attributes directive, L9+ --}}

Illuminate\View\ComponentAttributeBag handles merging, class lists, and escaping better than any single-filter Twig extension. The only genuinely valid reason to install this package in a Laravel app is a real Twig dependency.

Escaping is the security question. HTML attributes are an injection surface. Confirm the extension escapes values (Twig's escape('html_attr') or htmlspecialchars(..., ENT_QUOTES)). If it does not escape, you must pipe through |e('html_attr') before or after — and if it does escape and you also escape, you get double-encoded values like &amp;quot; in title and data-*. Check this with a value containing " and & before shipping. Attribute names are a second surface: never let user input reach the array keys.

Boolean attributes. disabled, checked, selected, required, multiple should render bare (disabled) and disappear entirely when false — not disabled="1" or disabled="false". HTML treats any value as true, so disabled="false" disables the element. If the package renders true => "1", normalize booleans yourself before passing in.

class and style arrays. You'll want class: ['a', 'b'] to flatten to class="a b". Most simple renderers will output class="Array" and emit a notice. Flatten with |join(' ') explicitly rather than assuming.

Numeric keys. Passing a list instead of a map (['class', 'id']) will produce garbage or an error. Always pass an associative array.

Empty array. {{ {}|render_html_attributes }} should output nothing, not a stray leading space inside your tag, which produces <button >. Harmless but noisy in snapshot tests.

Data attributes with objects. If a data-* value is an array/object (common for JSON payloads on data-config), you need |json_encode first, and you need the renderer to not re-escape the quotes into &quot;. This combination breaks in most naive implementations — test it.

Maintenance posture. 5 stars, 0 dependents, single-author. Pin the version (^1.0, whatever the tags show), commit the lockfile, and keep the wrapper macro so replacing it is a 5-minute job. Don't build a design system on top of it.

Composer/repo naming mismatch. The GitHub repo is RenderHtmlAttribute, the package is piedweb/render-html-attributes. Don't chase the wrong package name in composer require; confirm the exact name via composer show -a or the packagist page before guessing.

Extension points. There won't be meaningful ones. If you need custom behavior (attribute ordering, custom boolean list, x- attribute handling), fork the ~40-line class into app/Support/ and register it yourself — that's cheaper than patching a dependency and keeps you off an unmaintained fork.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource