Creating a custom html attribute

Hello everyone!

I’m wondering if there is any guide or post explaining how to create custom HTML attributes (or directives? - I’m not sure what the correct term is) like :if, :for, :let. I would like to have a custom attribute that I can use on any existing component.

I would appreciate any advice or guidance.

Thanks!!

Docs just call them “special attributes” :slight_smile: In short, you cannot. What are you looking to accomplish?

1 Like

I wanted to explore the idea of adding some RBAC capabilities into an attribute. I’m currently showing/hiding UI elements using the following:

<.card :if={can?(@context, "project.delete")} title="Danger zone">
  <button>Delete Project</button>
</.card>

@context holds some basic information, like the user role. So, I was hoping to move that logic into something more like the following:

<.card :if_user_can="projects.create">
  <button>Create Project</button>
</.card> 

This way, I don’t have to repeat that logic all over the place. This is the first time I’m exploring this kind of control on the UI, so if there is a better way to handle this, please let me know!

EDIT: Had a brainf*rt and the original code I posted made no sense :dizzy_face:

While it’s probably not quite what you want, you can do something like this:

attr :can?, :tuple

def card(assigns) do
  ~H"""
  <div :if={can?(@context, @ability)}>
    <%= render_slot(@inner_block) %>
  </div>
  """
end

<div can?={{@context, "project.delete"}>
  ...
</div>

That isn’t buying you much in terms of saving characters. Assuming @context is React-like context, you would have to use Surface if you want that. It’s unavailable in HEEx and no clue if there are any plans for it.

Yeah, I was looking for a way to deal with components whose internals I don’t have access to. But no worries, thanks for trying to help—I really appreciate it!

1 Like

I mean, I haven’t looked at how Surface does it but I assume it just stuffs context in a GenServer… maybe ETS… so you could always do that. But you may as well just use Surface at that point. Personally I just keep passing the current_user, though I’ve never been in the situation where I have very many of these checks on a single page. I prefer to create different routes based on ability and share via components when I can and have the odd piece hidden for certain users.

1 Like