hypertext icon indicating copy to clipboard operation
hypertext copied to clipboard

Setting default value for web component attributes

Open bshankar opened this issue 5 months ago • 6 comments

Say I have a component with optional fields:

#[component]
fn input<'a>(name: &'a str, value: Option<&'a str>, error: Option<&'a str>, max_length: u8, ...) -> impl Renderable {
  ...
}

It's tedious to enter values of all fields (rsx syntax) each time I use this component.

<Input name="email" value=None error=None max_length=32 ...>

I would like to propose a way to set default values for each attribute. The syntax could look like this:

#[component]
fn input<'a>(
    name: &'a str,
    #[default] value: Option<&'a str>, 
    #[default] error: Option<&'a str>, 
    #[default(32)] max_length: u8,
   ...
) -> impl Renderable {
  ...
}

#[default] uses the Default trait to get the value. You can also specify a value using #[default(value)]. Then you can just use Input component without repetition. You can only specify the attributes you want to override.

<Input name="email" value=(Some("John"))>

What do you think?

bshankar avatar Jul 31 '25 13:07 bshankar

@bshankar thank you for the idea!

an oversight on my end is that it is missing from the docs, but components actually do support a Default syntax.

rsx! { <Input value=(Some("John")) .. /> }

will use ..Default::default() to fill the rest of the struct. As for the implementation, you can manually impl Default for Input under the component function. Would that be an acceptable solution?

vidhanio avatar Jul 31 '25 17:07 vidhanio

I don't mind the syntax of using .. or implementing Default for the struct but this automatically gives a default value for all attributes - making all of them optional. I prefer some attributes / props to be mandatory and some optional.

(Sorry my example was bad. I updated it)

bshankar avatar Aug 01 '25 02:08 bshankar

Ah I see. Unfortunately there is no real way to communicate to the struct from the declaration to the component usage which fields are required and which aren't. How would you suggest this is resolved?

IMO the best way to do this currently would be to just create a couple constructors like such:

#[component]
fn input<'a>(
    name: &'a str,
    value: Option<&'a str>, 
    error: Option<&'a str>, 
    max_length: u8,
) -> impl Renderable {
  // ...
}

impl<'a> Input<'a> {
    fn new(name: &'a str) -> Self {
		Self {
			name,
			// fill rest with your defaults here
		}
	}

	fn with_value(mut self, value: &'a str) -> Self {
		self.value = Some(value)
		self
	}

	// ...

and forgo the entire "component" syntax, instead just desugaring it into what the component syntax would eventually become:

rsx! {
	<div>
		(Input::new("input name").with_value(...))
	</div>
}

You could even use a crate like bon to simplify the builder generating, and instead of #[component] use #[derive(Renderable)]

vidhanio avatar Aug 01 '25 03:08 vidhanio

Yea that's a good way to do this currently. I'm thinking of another usage pattern too. We can combine the optional fields into it's own type which implements Default.

struct OptionalProps<'a> {
    value: Option<&'a str>, 
    error: Option<&'a str>, 
    max_length: u8,
}

impl Default for OptionalProps {
    fn default() -> Self {
        Self {
         max_length: 32,
         ..Default::default()
        }
    }
}

#[component]
fn input<'a>(
    name: &'a str,
    optional_props: &OptionalProps,

) -> impl Renderable {
  // ...
}

Then we don't need to use the desugared syntax or bon.

rsx! {
    <Input
		name="email"
        optional_props=(OptionalProps {
			value: Some("[email protected]"),
			..Default::default()
		})
	/>
}

BTW you can declare default values in a struct in nightly Rust. It was planned for Rust 1.85 IIRC but ended up being delayed. https://github.com/rust-lang/rust/issues/132162

Maybe we can have a more elegant solution then?

bshankar avatar Aug 01 '25 09:08 bshankar

Yes, that RFC would definitely simplify this. Your idea would also work great, it's basically the current best way to have a couple default fields. This wouldn't require any changes to hypertext either.

vidhanio avatar Aug 01 '25 16:08 vidhanio

closing this for now, it can be revisited when https://github.com/rust-lang/rust/issues/132162 is added to stable rust.

vidhanio avatar Aug 03 '25 16:08 vidhanio