Skip to content

Conversation

NickSdot
Copy link
Contributor

@NickSdot NickSdot commented Oct 1, 2025

This PR adds a new @maybe directive that conditionally renders HTML attributes with values, complementing the existing boolean attribute directives like @checked, @selected, @disabled, @required, and @readonly.

Problem

While we have directives for boolean attributes, we still need verbose @if ... @endif blocks for attributes with values:

<a href="#" @if($title) title="{{ $title }}" @endif>Link</a>

We cannot keep adding specific directives for every possible attribute, so we need a dynamic solution.

Solution

The @maybe directive renders an attribute with a value only when the value is not null, not an empty string, and not whitespace-only:

<a href="#" @maybe('title', $title)>Link</a>

Before/After

{{-- before --}}
<a href="{{ $link->route }}" @if($link->title) title="{{ $link->title }} @endif" @if($link->rel) rel="{{ $link->rel }} @endif">
    {{ $link->label }}
</a>


{{-- after --}}
<a href="{{ $link->route }}" @maybe('title', $link->title) @maybe('rel', $link->rel)>
    {{ $link->label }}
</a>

{{-- before --}}
<img src="{{ $image->url }}" @if($image->alt) alt="{{ $image->alt }}" @endif @if($image->caption) data-caption="{{ $image->caption }}" @endif />

{{-- after --}}
<img src="{{ $image->url }}" @maybe('alt', $image->alt) @maybe('data-caption', $image->caption) />

Behaviour Matrix

The directive intentionally differs from a simple @if() check by treating 0 and false as valid values, since these are common in data attributes for counts, flags, and boolean states.

Value Renders
'foo' data-attribute="foo"
0 data-attribute="0"
false data-attribute="false"
true data-attribute="true"
'' (nothing)
null (nothing)
' ' (nothing)

Naming

I considered several alternatives: @when (too generic, likely better for other future use cases), @flag (implies boolean values only, whereas this handles strings, numbers, bools), @attribute and @optional (too long), @attr and @set (don’t make the conditional nature clear).

@has was tempting as it reads well: “has $title, then render title”. However, the parameter order would need reversing to @has($title, 'title'), which breaks the pattern of other Blade directives where the static value comes first.

@opt is appealingly terse but perhaps too cryptic.

@maybe has the right balance. It’s short, clearly conditional, and reads naturally with the attribute name first: “maybe render title if $title”.

@shaedrich
Copy link
Contributor

To me, the naming is not intuitive. I would call it @flag() or the like

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 1, 2025

To me, the naming is not intuitive. I would call it @flag() or the like

@flag would work well if this was exclusively for boolean data attributes, but since it handles any attribute with any value type, @maybe, @when or @optional and obviously @attribute (both too long, IMO) are more accurate. A title="" or target="" attribute aren't flags, though. Also flag doesn't really make it clear that it is conditional.

I appreciate the feedback, but I'll leave the naming to Taylor.

@shaedrich
Copy link
Contributor

It'd be fine with @optional

@faissaloux
Copy link
Contributor

Good one! One problem is the naming, I think @attribute would be better.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 1, 2025

I updated the naming section of the PR description.

@shaedrich
Copy link
Contributor

Thanks a lot 👍🏻

@imacrayon
Copy link
Contributor

I think this should mirror @class, there’s precedent with that directive:

<a href="{{ $link->route }}" @attr(['title' => $link->title, 'rel' => $link->rel])>
    {{ $link->label }}
</a>

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 2, 2025

I think this should mirror @class, there’s precedent with that directive:


<a href="{{ $link->route }}" @attr(['title' => $link->title, 'rel' => $link->rel])>

    {{ $link->label }}

</a>

It is different in the sense that the @class directive always has at least two entries.

For this use case here it makes it longer by 6 chars for the majority of situations where we have one data attribute. Don't really like it because the reason for the PR is to make things less verbose.

That said, I'll have a look if we can support both.

Edit:
@imacrayon it's easy to support both, passing as initially proposed here and as array. I think it's important to keep the initally proposed syntax too, because it's shorter for the majority case. As the below example shows the array syntax only really is adding it's marginal value >1 entries.

Happy to implement. For now I'll leave it to Taylor to decide first.

{{-- Attributes: 1 --}}
<a @if($link->title) title="{{ $link->title }} @endif">
<a @maybe('title', $link->title)>
<a @maybe(['title' => $link->title])>

{{-- Attributes: 2 --}}
<a @if($link->title) title="{{ $link->title }} @endif" @if($link->rel) rel="{{ $link->rel }} @endif>
<a @maybe('title', $link->title) @maybe('rel', $link->rel)>
<a @maybe(['title' => $link->title, 'rel' => $link->rel])>

{{-- Attributes: 3 --}}
<a @if($link->title) title="{{ $link->title }} @endif" @if($link->rel) rel="{{ $link->rel }} @endif  @if($link->clickId) data-tracker="{{ $link->clickId }} @endif">
<a @maybe('title', $link->title) @maybe('rel', $link->rel) @maybe('data-tracker', $link->clickId)>
<a @maybe(['title' => $link->title, 'rel' => $link->rel, 'data-tracker' => $link->clickId])>

@shaedrich
Copy link
Contributor

fyi, previous unsuccessful attempt at @attributes: #52783

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 2, 2025

fyi, previous unsuccessful attempt at @attributes: #52783

Similar. Mine is minus the complexity. Though, apparently high demand for a solution.

@hctorres02
Copy link

I tried using $attributes->merge([ ... ]), but there's no way to apply a condition to data-* attributes. The filter must be done elsewhere.

This directive is quite valid. It could be expanded to include conditions like the @class directive, but implementation requires care.

@timacdonald
Copy link
Member

I haven't dug deep into how this renders attributes, but I would expect the following to happen for these different attribute types.

[
    'crossorigin',                            // crossorigin
    'data-persistent-across-pages' => 'YES',  // data-persistent-across-pages="YES"
    'remove-me' => false,                     // [removed]
    'keep-me' => true,                        // keep-me
    'null' => null,                           // [removed]
    'empty-string' => '',                     // empty-string=""
    'spaced-string' => '   ',                 // empty-string="   "
    'zero' => 0,                              // zero="0"
    'one' => 1,                               // zero="1"
];
<div
    crossorigin
    data-persistent-across-pages="YES"
    keep-me
    empty-string=""
    spaced-string="   "
    zero="0"
    one="1"
/>

This will keep it inline with how Vite handles attribute types and values.

@timacdonald
Copy link
Member

See arbitrary attributes in #43442 for more on these decisions.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 7, 2025

I haven't dug deep into how this renders attributes, but I would expect the following to happen for these different attribute types.

[

    'crossorigin',                            // crossorigin

    'data-persistent-across-pages' => 'YES',  // data-persistent-across-pages="YES"

    'remove-me' => false,                     // [removed]

    'keep-me' => true,                        // keep-me

    'null' => null,                           // [removed]

    'empty-string' => '',                     // empty-string=""

    'spaced-string' => '   ',                 // empty-string="   "

    'zero' => 0,                              // zero="0"

    'one' => 1,                               // zero="1"

];
<div

    crossorigin

    data-persistent-across-pages="YES"

    keep-me

    empty-string=""

    spaced-string="   "

    zero="0"

    one="1"

/>

This will keep it inline with how Vite handles attribute types and values.

Hey Tim! I already read that in your comment to the PR linked above. But I kindly disagree. Personally I don't care what Vite does, what I care about is how I can add my own attributes in a non-verbose way.

This PR seeks to handle the majority case we deal with every single day, not to be "aligned" with the @class directive, nor be "unified" with Vite. Because it doesn't make sense for many situations.

Differences:

  • It intentionally will render false, and true as strings.
  • It will not render space only strings.
  • It doesn't have value-less attributes at all, because it's shorter to simply add it in your HTML. There is no value in having a always renderable attribute in the array even.
  • It doesn't support array syntax at all; I showed above how array syntax does not really add value compared to multiple @maybe.

As I mentioned in my PR description, I would name this @maybe to keep @attributes for future use cases (perhaps like yours).

Both concepts are valid, but they cannot be merged in one (one wants to render false, one doesn't). Hence, what you are asking for is unfortunately nothing for this PR. 🙏

@timacdonald
Copy link
Member

Appreciate you pushing back, @NickSdot! Always appreciated.

To clarify, when I say Vite, I mean what we do in Laravel itself. Having different attribute rendering mechanics for two Laravel features seems like a footgun.

But even taking the stand that we don't want to be inline with Laravel's attribute handling in the Vite space, I would still push back on the current rendering proposal. If nothing else, we should respect HTML itself. It explicitly mentions that true and false are not valid for boolean attributes.

Screenshot 2025-10-07 at 14 07 00

@timacdonald
Copy link
Member

timacdonald commented Oct 7, 2025

I think my brain goes to tooling like jQuery when I see that we don't render empty strings and whitespace only strings. I probably need to think on that some more to come up with a compelling argument as my brain is deep in other stuff right now.

None of this is a hill I wanna die on, btw. Just sharing a perspective and prior art in Laravel related to the feature to ensure we keep the framework cohesive when and where it makes sense.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 7, 2025

Having different attribute rendering mechanics for two Laravel features seems like a footgun.

@timacdonald well, as I mentioned above, there is no way to satisfy two completely contrary concepts in one solution. Below I make a point why both are valid (+ spec conform) and why we need two mechanisms.

But even taking the stand that we don't want to be inline with Laravel's attribute handling in the Vite space, I would still push back on the current rendering proposal. If nothing else, we should respect HTML itself. It explicitly mentions that true and false are not valid for boolean attributes.

Screenshot 2025-10-07 at 14 07 00

I knew that this will be the next argument. :) For the follwing reasons I need to push back again:

1) There are more than one relevant spec here.

The ARIA spec for instance. Accessibility APIs expect explicit tokens. E.g:

aria-hidden="false"
aria-expanded="false"

2) Only valid for presence indicators (boolean attributes)

What you are quoting is a separate concept with explicit behaviour. This, however, does not mean that I cannot use true/false in enumerated attributes (next section after the one on your screenshot: 2.3.3 Keywords and enumerated attributes). True/False are not forbidden values for enumerated attributes. We can do whatever we want, just cannot expect "boolean attributes" behaviour from it.

To bring a simple example; you will agree that the folowing is neater

foo.active = foo.active === 'true' ? 'false' : 'true';

than

if (foo.hasAttribute('data-active')) {
  foo.removeAttribute('data-active');
} else {
  foo.setAttribute('data-active', '');
}

Enumerated attributes allow us excactly that. And here we are also back to the previous point: ARIA attributes are enumerated attributes, not boolean ones. Both ways are HTML spec conform, even if we ignore that ARIA is a separate spec.

3) Third Party Expectations

I am all for following specs. And I also have proven above that we are aligned with the spec. However, I still would like to throw in third party stuff. If a third party expects explicit true/false I cannot change that. You mentioned jQuery, JQuery Mobile expects it. The same is true for Bootstrap in many cases.

I think my brain goes to tooling like jQuery when I see that we don't render empty strings and whitespace only strings.

Yes, again, I don't object. Both concepts have their place. That's why we need two solutions for it. I believe we shouldn't try too hard to unify something that cannot be unified. It's like in the real world, we have a Slotted screwdriver and a Phillips screwdriver. Both aren't footguns, but solutions for different problems.

4) Last but not least
We are pretty focused on custom attributes right now. But please don't forget, I should totally be able to decide on my own if I want to have title="false" to show "false" in a little tooltip in a, for instance, in classifier interface. And I should be able to hide a title tooltip on something if, for whatever reason, the value in title is .

You get the point: this is not only for custom data attributes.


I probably need to think on that some more to come up with a compelling argument as my brain is deep in other stuff right now.

None of this is a hill I wanna die on, btw. Just sharing a perspective and prior art in Laravel related to the feature to ensure we keep the framework cohesive when and where it makes sense.

Unfortunately, it (subjectively) feels like Taylor tends to close PRs when you hop in with objections. So if your objections are not fully thougt out... it's demotivating to be closed just because. No offense, of course! ❤️

I hope my arguments above are compelling enough to "book a win" here.

@timacdonald
Copy link
Member

timacdonald commented Oct 7, 2025

Unfortunately, it (subjectively) feels like Taylor tends to close PRs when you hop in with objections. So if your objections are not fully thougt out... it's demotivating to be closed just because. No offense, of course! ❤️

No offense taken. It is my job to offer opinions here and there. Sorry if I've put you off here or on other PRs.

I can see utility in a feature of this shape. FWIW, I hope some form of this gets merged.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 7, 2025

Sorry if I've put you off here or on other PRs.

No, it's also not like that. Wasn't put off myself. So far you luckily been supportive to all my PRs. Sorry if I didn't express myself clear enough. 🙏

@timacdonald
Copy link
Member

Awesome!

@willrowe
Copy link
Contributor

willrowe commented Oct 8, 2025

I fully agree with @timacdonald and would rather see a single @attributes directive that consistently handles this in a way that aligns with how you would expect it to when coming from the JavaScript/Vue/Vite side of things. Having too many ways to do essentially the same thing, but in slightly different ways makes it more difficult to learn. This feels too tailored to how one person may like to do things as opposed to something more general, powerful, and predictable.

@rodrigopedra
Copy link
Contributor

Adding to @willrowe's comment, the true and false as strings case can be easily handled by a user on their codebase:

@attrs([
    'aria-hidden' => $hidden ? 'true' : 'false',
    'aria-expanded' => $expanded ? 'true' : 'false',
])

One can easily add a helper to their code base if wanted. Or just use json_encode:

@attr([
    // json_encode will output booleans, numbers and null as a unquoted strings
    'aria-hidden' => json_encode($hidden), 
    'aria-expanded' => json_encode($expanded),
])

But attribute toggling, as @timacdonald described, would be very awkward to accomplish with the current proposal.

Also, calling the directive @maybe is a nay from me. Intent is unclear and confusing.

Mind that Blade's directives can also be used for non-HTML content, like markdown emails and Envoy tasks.

I'd prefer, if added, for it to be called something like @attr(), or anything that closely resembles its intent.

If different behavior due to aria- and data- attributes is desirable, why can't we have both?

Insert "Why not both?" meme here

We could add a @attr directive that behaves like @timacdonald described and like our Vite plugin already does, and a @aria or @dataset directive that behaves like this PR is proposing.

A @aria or @dataset directive could even auto-prefix its attributes and behave however it is needed for those cases.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 8, 2025

JavaScript/Vue

This is Blade. Just saying.


Y'all keep discussing things that this PR doesn't seek to solve. As we now already know there must be two different solutions because both concepts are diametrical to each other. This isn't "tailored" to one persons requirements, this is the majority use case. We all set title and rel attributes all the time.

The alternative examples proposed above are hilarious. You realise that they are longer than writing the actual control flows this PR attempts to get rid off?

About naming, I repeat, I leave that to Taylor.

Guys, keep on bike shedding unrelated stuff instead of working on a complementing PR to add the other missing piece. I am sure that's how we will get good things! ✌️❤️

Edit:
Imagine having json_encode in your Blade files.

Edit 2:

If different behavior due to aria- and data- attributes is desirable, why can't we have both?

And then a @title, @rel, @target etc. directives, right?

@rodrigopedra
Copy link
Contributor

And then a @title, @rel, @target etc. directives, right?

Of course not.

Those would be covered in the behavior everyone would expect a @attr directive to behave.

With sane rendering rules that follow the HTML spec, minus aria- or data- attributes, which were later additions.

Imagine having json_encode in your Blade files.

Sure, mate. It is such an odd case it got a custom directive, a wrapper class, and a section on docs.

https://laravel.com/docs/12.x/blade#rendering-json

This isn't "tailored" to one persons requirements, this is the majority use case. We all set title and rel attributes all the time.

Yes, it is. Or at least when one prioritizes aria- and data- attributes rules over all other HTML attributes.

The gripe is not on the value of the directive, as I, and I am sure others who commented out, like the proposed shorthand syntax in general.

The gripe is on the proposed esoteric rendering rules.

This argument doesn't make any sense on the title or rel attributes, as they would be fine if the rendering rules followed the HTML spec, as proposed by many commenters, and what we also already have for our Vite plugin.

But whatever, you do you.

Good luck with your PR. I like the idea, just not the oddities, such as treating booleans as strings (which is perplexing).

If not merged, consider publishing it as a package. I am sure many other developers would benefit from it for aria- and data- attributes.

Have a nice day =)

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 8, 2025

I answered the HTML spec question above in detail. This is spec conform. Read up enumeration attributes instead of ignoring it and liking comments which also got it wrong.

Enumeration example from ARIA:
true; false; undefined

Enumeration example from app:
true; false; unsure

These have nothing to do with boolean attributes.

Unfortunately, I cannot do more to help you to understand the difference.

I am sure many other developers would benefit from it for aria- and data- attributes.

Thanks for making the argument for getting this merged. And yet you don't want to see it merged. Because it isn't tailored to your use case? ;)

I wish you the same!

@rodrigopedra
Copy link
Contributor

rodrigopedra commented Oct 8, 2025

And yet you don't want to see it merged.

I do want to see it merged. Just not with such esoteric rendering rules.

I find the syntax great:

<a href="..." @attr('title', $title)>{{ $label }}</a>

Where the title attribute is not rendered at all if $title is null or empty or false, and thus does not overshadow the <a> tag's content for a screen reader with an empty string.

The proposed syntax is very handy. Just not your particular use case for rendering attribute values in such a manner no one would expect.

Because it isn't tailored to your use case? ;)

Not my use case. HTML attributes spec.

Imagine someone using Web Components opening issue after issue as they expect boolean attributes to behave conforming to the spec.

Enumeration attributes are another spec suitable to specific use cases. It is not the general use case. And as such, IMO, it could be subject to a future addition, as I believe the general use case would benefit more developers. Or even provided by a 3rd-party package.

I am sorry. I won't spend more of my time trying to help you bring this addition to the framework.

I wish you the best luck.

@taylorotwell
Copy link
Member

taylorotwell commented Oct 8, 2025

Has anyone tried building this as a simple package that registers the directive as a Blade extension?

I think I do find the true / false behavior a bit unintuitive, but it may not be solvable for all use cases. The example that came to mind for me:

<div class="something something-else" @attribute('wire:poll', $shouldPoll)>
    ...
</div>

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 8, 2025

Has anyone tried building this as a simple package that registers the directive as a Blade extension?

I think I do find the true / false behavior a bit unintuitive, but it may not be solvable for all use cases. The example that came to mind for me:

<div class="something something-else" @attribute('wire:poll', $shouldPoll)>

    ...

</div>

Not as a package, but I have it in service providers in the hope to get rid of it when this gets merged.

The attribute you mention, by spec, is an enumeration attribute because it also allows other values like wire:poll="refreshSubscribers". Your example would render wire:poll="true".

You probably didn't read all the comments here. My personal conclusion was that we need @maybe and @attribute to cover both concepts, because they are diametrical to each other.

Think of ARIA attributes like aria-hidden="true" that expect explicit tokens like true/false. Or what Tim brought up, he would expect an empty string to render. But we definitely don't want that with, for instance, the title/rel attributes which we all use all the time; including people that never touched Livewire.

By adding @maybe and @attribute we will be able to cover every single use case. Though, @attributes would be more complex than what I propose here. There were previous PR attempts, perhaps one of them could be retried after this here is merged and acceptance was signalled.

@taylorotwell
Copy link
Member

I definitely think @maybe is too broad of a word for what we want to do here. I wouldn't want to use it for this feature. Need a better name for it IMO.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 9, 2025

I definitely think @maybe is too broad of a word for what we want to do here. I wouldn't want to use it for this feature. Need a better name for it IMO.

How would you feel about calling this one @attr to keep it nicely terse and have @attributes free for the potential other addition that handles the more complex situations which will be more verbose anyway?

@riyuk
Copy link
Contributor

riyuk commented Oct 10, 2025

i just wanted to drop a comment because i really like this PR.

i think @attr and @attributes feel a bit ambiguous to handle that two use cases.

Hot take: personally, i would actually prefer if blade components stopped using @props and switched to something like @params instead.

That way, @prop could be available for this PR (@props could still work for blade components for compatibility reasons but would be too ambiguous again), and @attr or @attribute could be used for the other case mentioned.
To me, @prop feels more intuitive than @maybe, mb because of good old jquery times - though i get that its currently too close to the reserved @props keyword used by blade components.

@imhayatunnabi
Copy link

I'd like to offer some feedback that might help move this forward:

The Good

  • The syntax @maybe('title', $title) is clean and intuitive
  • Addresses a real pain point in Blade templates
  • The behavior matrix clearly shows intent (treating 0 and false as valid values makes sense for data attributes)

Considerations

  1. Naming: While @maybe is concise, @attr might be more immediately clear about its purpose. Since this is specifically for attributes, the name should reflect that.

  2. HTML Spec Alignment: I understand the need to handle ARIA attributes like aria-hidden="false", but perhaps we could have a more predictable default behavior that follows HTML specs, with an optional parameter or separate directive for ARIA/data attributes that need string representations of booleans?

  3. Array Syntax Support: The comparison to @class is valid. Supporting both syntaxes would provide flexibility:

    {{-- Single attribute --}}
    @attr('title', $title)
    
    {{-- Multiple attributes --}}
    @attr(['title' => $title, 'rel' => $rel])
  4. Package First?: Given the ongoing debate about behavior, perhaps releasing this as a package first would allow real-world usage to inform the final implementation. This could help validate which approach developers prefer in practice.

Suggestion

What if we had two complementary directives:

  • @attr - follows standard HTML behavior (removes falsy values, treats true as boolean attribute)
  • @data or @aria - handles data/aria attributes with string representations of all values

This would give us the best of both worlds without forcing one behavior to handle incompatible use cases.

Overall, I think this feature would be valuable for the framework. The key is finding the right balance between convenience and predictability. Keep up the great work!

@shaedrich
Copy link
Contributor

The syntax @maybe('title', $title) is clean and intuitive

More than one person already disagreed with the naming being intuitive (you have addressed that further down 👍)

4. Package First?: Given the ongoing debate about behavior, perhaps releasing this as a package first would allow real-world usage to inform the final implementation. This could help validate which approach developers prefer in practice.

I'd assume that Taylor is less likely to merge this since he then can simply refer to an existing package.

@AhmedAlaa4611
Copy link
Contributor

AhmedAlaa4611 commented Oct 13, 2025

Hello @NickSdot

I have read all the comments here and I think the current state of the PR is fine as it is, including the directive name.

@NickSdot
Copy link
Contributor Author

@imhayatunnabi, I appreciate the productive feedback.

1) Naming & General

I agree with you that @attr, @data and @aria would feel neat to have. However, this still doesn't really solve what we are stuck with right now:

"@attr and @attributes or a completely different name?"

Why: given what you propose I would expect that the following directives would not required us to prefix with data/aria like so:

@data('tracking', $value)
-> data-tracking="value"

@aria('hidden', false)
-> aria-hidden="false"

Which makes them unusable for everything else. This means for everything non-data and non-aria, potentially vendored, we still would need to use @attr.

So what would we win? We still have the problem that we need solutions for different use cases, like rendering enumeration attributes that require false, not rendering empty strings for something like title or rendering wire:poll without value (boolean attributes) while others need a value.

2) Package First

I am really having a hard time to agree that this should be package functionality. These are such common cases that I actually believe it should be explicitly discouraged to have them in packages.

a) we will end up with several community implementations that work slightly different. Each time you work on something you first must find out which flavour is used.

b) if Laravel ever will have it in core, ecosystem implementations will break. In fact one of the reasons why I prefer to not have it in a service provider.

I cannot help but believe it's a bad idea.


Curren Status

We have 10 positive reactions in the form of emojis, 4 positive reactions via comment.

There are only 3 negative reactions with concerns regarding the functionality. These 3 could and should be addressed with a second implementation, IMHO.

Some more comments have concerns only with the name.


I understand that @maybe isn't everyone's cup of tea. On the other hand we have methods like "chaperone". I, personally, cannot really come up with something that is less "broad" and wouldn't close the door for other similar additions in the future.

If anyone has naming ideas please step forward.

@shaedrich
Copy link
Contributor

shaedrich commented Oct 13, 2025

I understand that @maybe isn't everyone's cup of tea. On the other hand we have methods like "chaperone". I, personally, cannot really come up with something that is less "broad" and wouldn't close the door for other similar additions in the future.

Yeah, chaperone sure is somewhat outlandish, however, when given a second glance, I think, one can derive the intended meaning thereof, whereas @maybe sounds like it calls Lottery

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 13, 2025

I understand that @maybe isn't everyone's cup of tea. On the other hand we have methods like "chaperone". I, personally, cannot really come up with something that is less "broad" and wouldn't close the door for other similar additions in the future.

Yeah, chaperone sure is somewhat outlandish, however, when given a second glance, I think, one can derive the intended meaning thereof, whereas @maybe sounds like it calls Lottery

Fair. But what are our options?

Taylor wants it less broad, so everything from @setif, @add to @has also isn't a fit. Other combinations make it so long that the objective of the PR, making it less verbose, would be defeated.

You proposed @flag. But given how the discussion played out I believe you will agree that something that indicates boolean attributes behaviour is at this point even less of a fit than I believed in the beginning.

@filled would fit because it's the exact behaviour, as Rodrigo noted. However, we print an HTML attribute and filled very likely could be a more general directive in the future. The same applies to @optional.

I had @literal in mind (because it prints literally what you pass--even false). This, however, doesn't indicate the conditional nature, which I think would somewhat be important if we already have no link to "attribute". The same applies to @inline.

Unfortunately, I am really not sure how "too broad" can be avoided here.

Any other ideas?

@shaedrich
Copy link
Contributor

what about something like @ifAttr()?

@willrowe
Copy link
Contributor

I still do not understand why you cannot just pass true and false as a string if that is what you want the value of the attribute to be? In HTML if an attribute has a value, it is always a string. The value of that string may denote something that is interpreted as a boolean, but there is no concept of an attribute having any other value than a string. It is more clear to explicitly pass the value as a string instead of having it handled differently by different directives. As I said in my original comment, these inconsistencies start to add up and make it harder for people to learn.

@NickSdot
Copy link
Contributor Author

what about something like @ifAttr()?

Sure. Similar to @attributes and @attr we need to know from Taylor if he considers it too close or is ok with it.

@NickSdot
Copy link
Contributor Author

I still do not understand why you cannot just pass true and false as a string if that is what you want the value of the attribute to be? In HTML if an attribute has a value, it is always a string. The value of that string may denote something that is interpreted as a boolean, but there is no concept of an attribute having any other value than a string. It is more clear to explicitly pass the value as a string instead of having it handled differently by different directives. As I said in my original comment, these inconsistencies start to add up and make it harder for people to learn.

Because it is convenient for a feature that we use all the time. The whole promise of Laravel is to make things more convenient. So, when an easy to understand helper can safe us from casting things all the time I believe it should do so.

You actually make the point for it yourself, because as you correctly note it is always a string what we want.

Taylor seems to agree. As far as I understand this is about naming now.

@willrowe
Copy link
Contributor

I think the main issue here is that if I'm using the directive like this:

@php
$opt_in = false;
@endphp
<input @maybe('checked', $opt_in) name="opt_in" type="checkbox" />

I would expect it to render this HTML:

<input name="opt_in" type="checkbox" />

However, I would get this instead:

<input checked="false" name="opt_in" type="checkbox" />

Which is the opposite of what I want. There is a @checked directive which would work for this, but if I'm not aware of that directive I would think that @maybe would be the more general way to do all of my attributes. This is what I mean about being consistently explicit.

@NickSdot
Copy link
Contributor Author

NickSdot commented Oct 13, 2025

I think the main issue here is that if I'm using the directive like this:

@php

$opt_in = false;

@endphp

<input @maybe('checked', $opt_in) name="opt_in" type="checkbox" />

I would expect it to render this HTML:

<input name="opt_in" type="checkbox" />

However, I would get this instead:

<input checked="false" name="opt_in" type="checkbox" />

Which is the opposite of what I want. There is a @checked directive which would work for this, but if I'm not aware of that directive I would think that @maybe would be the more general way to do all of my attributes. This is what I mean about being consistently explicit.

You again repeat the same point that was discussed in length.

Yes, your expectation is valid.

Yes, my expectation is valid.

That's why there is no way to get two diametrical different functionalities into one directive.

It's impossible.

That's why we need two directives to cover all cases.

I don't understand how that is not absolutely obvious to everyone at this point.


Additionally, and ignoring that we already have all the boolean directives, what is the whole point of what you want to do here?

@if($opt_in) someBoolean @endif
vs.
@maybe(someBoolean, $opt_in)

@if($link->title) title="{{ $link->title }} @endif
vs.
@maybe('title', $link->title)

You are literally making an argument for a problem that doesn't exist for boolean attributes. This PR solves a verbosity problem that we don't have with boolean attributes. But you want to "unsolve" that by making dealing with the actual verbose attributes more complicated by forcing us to cast every time manually.

Please tell me that you realise how little sense this makes.

@AhmedAlaa4611
Copy link
Contributor

Hello @NickSdot what about something like this:

if (in_array($parts[0], ['checked', 'selected', 'disabled', 'required', 'readonly'])) {
    // Throw an exception...
}

@NickSdot
Copy link
Contributor Author

Hello @NickSdot what about something like this:

if (in_array($parts[0], ['checked', 'selected', 'disabled', 'required', 'readonly'])) {

    // Throw an exception...

}

For the built-in booleans this would make things perfectly clear. But different story for vendor and custom booleans.

Not sure if we really need to babysit to such an extend. HTML itself doesn't prevent us from writing broken HTML, though.

Two people here act like this is a massively complicated directive while it's not. It basically mirrors the exact behaviour of the filled helper and can be documented exactly like that; it still would be one of the Blade docs shortest entries.

Probably it's just good as is, but if Taylor wants me to add it I can do that of course.

@riyuk
Copy link
Contributor

riyuk commented Oct 13, 2025

To be honest, I think the real discussion here shouldn’t be about the feature itself, but rather about its wording or naming.

If everyone reads through the entire pull request and its comments, it should be crystal clear that we do need this — as well as the alternative solution — since there are two valid use cases. Both currently lead to bloated and messy code, with multiple @if statements cluttering up the HTML elements.

Maybe all of the negative comments could have been avoided if this PR had included the other helper as well - but then again, that might have made the PR too large to implement in one go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.