im3000

im3000

Hello!

I am stuck figuring out how to set a custom CSS classes for text inputs in Surface. Basically, I would like to add a red border for the invalid text field. I can probably use class={invalid: @field_status}, but I am wondering if there is somehow a way to make this apply for all fields by creating some kind of helper or wrapper. For the reference, I am using Ecto and there are changesets involved for the forms in question.

Any help, pointers, links are much appreciated. Thank you!

Showing Posts 1 to 6

Malian

Malian

Hi @im3000 !

Thanks for using Surface!

If the ErrorTag does not fit your needs, you could indeed dynamically add a class to the TextInput component with the class prop like you mentioned.

There is no currently no way to dynamically add a class to a component across the application. A solution could be to create your own TextInput component that is a wrapper for the Surface one, or that delegates the rendering to Phoenix (it is basically what the Surface component does). In that component, you can retrieve the form context and do what you want with it.

Take a look at https://github.com/surface-ui/surface/blob/master/lib/surface/components/form/text_input.ex, I am sure you will find what you need there.

That being said, I am curious how you imagine a “dynamically” class for one component could work? Could you explain us how you imagine the API? It will help us to evaluate the way of implementing this to Surface.

im3000

im3000 OP

Thank you for the answer @Malian!

As you suggested, I could probably get away with a derived input component. What I had in mind was a tighter coupling to Ecto changesets, but that coupling might be too tight. On the other hand all the information is already probably there.

The idea sparked after reading Dynamic forms with Phoenix « Plataformatec Blog post and especially the “Customizing Inputs” section. I am thinking if Surface has an Field tag that acts as a wrapper for inputs and error tags it might be quite easy to add an error CSS class to the inputs that the field is wrapping. With that said, I haven’t looked at the Surface’s code too close yet so take my thoughts with a pinch of salt.

What do you think? Is it doable or is it not in line with Surface’s design philosophy?

harmon25

harmon25

Very doable - but not a native surface concern.

Phoenix does a bit of magic to hide errors on fields the user has not yet interacted with.
This ‘magic’ is done with these classes when using ErrorTag:

  .phx-no-feedback .invalid-feedback {
    display: none;
  }

Obviously display:none; would not work on a border - and this will have to be modified achieve applying an error border to a field.

Think you would apply a default border if .phx-no-feedback is present, and when just .invalid-feedback is present on the field, apply the error border or similar…

Could also use more intelligent CSS selectors like if .invalid-feedback is present on a parent node - to apply certain styles…

Malian

Malian

@harmon25 correct me if I am wrong, but Phoenix add phx-no-feedback from the error_tag function in your ErrorHelpers module. Does Phoenix add phx-no-feedback on inputs as well?

harmon25

harmon25

No phoenix does not do that for you, the dom node needs an accurate phx_feedback_for attribute - Form bindings — Phoenix LiveView v0.15.7 (hexdocs.pm) to apply the phx-no-feedback class.

So a special styles like:

input .phx-no-feedback.invalid-feedback {
...
}

input .invalid-feedback {
...
}

would be required to pull this off, as display: none; is not really an option for the input itself :stuck_out_tongue:

im3000

im3000 OP

I am a bit confused. If Surface could add some kind of css class to the <form> or <div> (Field) element in case of field error it would be no problem doing a little CSS-fu to style the inputs in question. Right now the generated DOM node for ErrorTag hangs on its own and there is no easy way to find its input without doing some JS-fu.

Right now I’ve solved it with a hack adopted from the article mentioned higher up, but I feel there must be a better way.

<Form for={@changeset} change="change" submit="save" opts={autocomplete: "off"}>
   <Field name={:name}>
     <Label class="form-label" />
      <TextInput class={'font-medium', 'w-full', invalid: state_class(@changeset, :name)} />
       <ErrorTag />
    </Field>
</Form>

And I put this helper func in my LiveHelpers module that I then imported in my Surface component.

  def state_class(changeset, field) do
    cond do
      !changeset.action -> false
      changeset.errors[field] -> true
      true -> false
    end
  end

TBH I feel like that meme science dog atm .. hehe. Still learning! But something tells me that this could somehow be solved in the Surface lib itself. Either by Surface configuration or maybe in some kind of a separate helper module.

— All posts loaded —

Where Next? Top

Trending in Questions Top

water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews