Skip to content

Comments

xilem_web: Add components example#1638

Draft
flosse wants to merge 5 commits intolinebender:mainfrom
slowtec:components
Draft

xilem_web: Add components example#1638
flosse wants to merge 5 commits intolinebender:mainfrom
slowtec:components

Conversation

@flosse
Copy link
Contributor

@flosse flosse commented Jan 30, 2026

I am trying to demonstrate how to build components that are generic,
but as soon as I define the event handler

 html::button("click").on_click(|s: &mut AppState, _| { s.clicks += 1;  }),

I get this error message that I don't understand:

error[E0161]: cannot move a value of type `impl xilem_web::interfaces::Element<&mut AppState, CardAction<()>>`
  --> xilem_web/web_examples/components/src/main.rs:52:9
   |
52 | /         card(
53 | |             "Card Example",
54 | |             state.card_collapsed,
55 | |             html::div((
...  |
60 | |             )),
61 | |         ),
   | |_________^ the size of `impl xilem_web::interfaces::Element<&mut AppState, CardAction<()>>` cannot be statically determined

Can anyone help me?

@flosse flosse added the web label Jan 30, 2026
@Philipp-M
Copy link
Member

I think this is another instance of the bug in rustc (or something related at least): #xilem > ✔ Writing a styled button helper

It does compile as expected with the new trait-solver (i.e. RUSTFLAGS="-Znext-solver" trunk serve).

Might be worth to open a minimal reproduction in rust for this issue in the old solver, but then again, it seems to be fixed in the new solver, so I don't think there's gonna be action on it anyway (at least if the new solver will be stabilized soon)...

@flosse
Copy link
Contributor Author

flosse commented Feb 4, 2026

It does compile as expected with the new trait-solver (i.e. RUSTFLAGS="-Znext-solver" trunk serve).

Thanks, that's good to know! I wouldn't have thought of that.
Can you also think of a workaround to build components in stable Rust?

Might be worth to open a minimal reproduction in rust for this issue in the old solver, but then again, it seems to be fixed in the new solver, so I don't think there's gonna be action on it anyway (at least if the new solver will be stabilized soon)...

I'll keep an eye on the process for a while, and if it looks like the feature will be stabilized this year, I'll be happy 😉

@PoignardAzur
Copy link
Contributor

but then again, it seems to be fixed in the new solver, so I don't think there's gonna be action on it anyway (at least if the new solver will be stabilized soon)...

While the trait solver in particular is more or less the top priority of the Rust maintainers and I have good hopes it's stabilized before the end of the year, as a general policy I would rather not make any assumption about future Rust improvements, because black swans happen and they can delay improvements for years.

Anyway, I'll look into that bug, hopefully tomorrow.

@PoignardAzur
Copy link
Contributor

(Quick ping to say, I haven't forgotten about this, but I've been sick for a week.)

@flosse
Copy link
Contributor Author

flosse commented Feb 10, 2026

(Quick ping to say, I haven't forgotten about this, but I've been sick for a week.)

Oh dear, I hope you're feeling better now?
No stress, there's no rush (although I am naturally curious and interested in a solution 😉 ).

@PoignardAzur
Copy link
Contributor

I am trying to demonstrate how to build components that are generic, but as soon as I define the event handler

 html::button("click").on_click(|s: &mut AppState, _| { s.clicks += 1;  }),

I get this error message that I don't understand:

Did your code compile before you added the on_click call? I couldn't reduce it to a working version.

Either way, after trying for a while to make this code compile, I think the takeaway is that we urgently need to get rid of the ViewArgument architecture.

@flosse
Copy link
Contributor Author

flosse commented Feb 14, 2026

Did your code compile before you added the on_click call?

yes!

I couldn't reduce it to a working version.

I just tried it with the current master (416c156) with the same behavior.

Either way, after trying for a while to make this code compile, I think the takeaway is that we urgently need to get rid of the ViewArgument architecture.

Good to know. Is there anything I can help?

@Philipp-M
Copy link
Member

Good to know. Is there anything I can help?

Depends on how deep you want to dive :)
There was a reason for the ViewArgument trait, but I'm also not sure whether the original reason ever came to action (probably because it was never promoted, didn't have approachable docs/examples etc.), nor whether the drawbacks are worth it. See: #xilem > A mirage of a future Xilem or the actual PR implementing that: #1444. In short: to allow splitting app state to components that are not composed in one type (e.g. being able to change a global background color and have local checkbox state for a hypothetical "change background checkbox component" or something like that.).

Also related: #xilem > Adapting non-trivial State

I still think it's worth it to explore: #xilem > Removing App State, but this is a fairly radical change with a lot of unknowns.

@flosse
Copy link
Contributor Author

flosse commented Feb 14, 2026

Good to know. Is there anything I can help?

Depends on how deep you want to dive :) There was a reason for the ViewArgument trait, but I'm also not sure whether the original reason ever came to action (probably because it was never promoted, didn't have approachable docs/examples etc.), nor whether the drawbacks are worth it. See: #xilem > A mirage of a future Xilem or the actual PR implementing that: #1444. In short: to allow splitting app state to components that are not composed in one type (e.g. being able to change a global background color and have local checkbox state for a hypothetical "change background checkbox component" or something like that.).

Also related: #xilem > Adapting non-trivial State

I still think it's worth it to explore: #xilem > Removing App State, but this is a fairly radical change with a lot of unknowns.

Interesting. I'll take a look here and there.
I have great respect for the architecture and your skills and will probably play through a few use cases as a “user.” Feel free to contact me anyway if you think there are any “little things” that need attention.

@PoignardAzur
Copy link
Contributor

Did your code compile before you added the on_click call?

yes!

I couldn't reduce it to a working version.

I just tried it with the current master (416c156) with the same behavior.

Can you push a compiling commit then? (With the on_click part commented out, I guess.)

@PoignardAzur
Copy link
Contributor

Welp, by now I've spent more than five hours looking at the code and I can't figure out how to fix the general problem except "remove the ViewArgument trait".

On the shorter term, you probably want to use the trick mentioned in the Zulip thread Philipp linked; in our case that means specifying html::button::<Edit<AppState>, _, _>(...) :

            html::div((
                "Some content ...",
                html::button::<Edit<AppState>, _, _>("click").on_click(|s: &mut AppState, _| {
                    s.clicks += 1;
                }),
            )),

Doing that makes the code compile on my end.

@flosse
Copy link
Contributor Author

flosse commented Feb 17, 2026

Welp, by now I've spent more than five hours looking at the code and I can't figure out how to fix the general problem

😮

except "remove the ViewArgument trait".

Okay, and that would have a lot of consequences, right?

On the shorter term, you probably want to use the trick mentioned in the Zulip thread Philipp linked;

Well, it's not the most beautiful code, but it could be much worse 😉
Then I'll finish the PR with the current workaround, right?

Thank you for investing your time!

@PoignardAzur
Copy link
Contributor

Okay, and that would have a lot of consequences, right?

Well, as Philipp said, we weren't using it that much anyway.

@flosse
Copy link
Contributor Author

flosse commented Feb 17, 2026

Okay, and that would have a lot of consequences, right?

Well, as Philipp said, we weren't using it that much anyway.

Okay, I'll try that and see what the code base would look like if there were no more ViewArguments.

@Philipp-M
Copy link
Member

It's basically about reverting #1444, it shouldn't be very difficult I think, just a little tedious (especially checking all new views in Xilem etc.). Does @DJMcNab has any input here (since it was his PR)?

@flosse
Copy link
Contributor Author

flosse commented Feb 17, 2026

It's basically about reverting #1444, it shouldn't be very difficult I think, just a little tedious (especially checking all new views in Xilem etc.). Does @DJMcNab has any input here (since it was his PR)?

👍 I'll try to create a PR (draft).

@flosse flosse mentioned this pull request Feb 17, 2026
github-merge-queue bot pushed a commit that referenced this pull request Feb 18, 2026
Motivated by
#1638 (comment)
this PR basically reverts #1444.
@RagibHasin
Copy link
Contributor

As I said here, I have been using ViewArgument to pass only relevant parts of app state to children views.

While working on the aforementioned project I have also been bitten by next solver not being available (I think?).

But a little judicious boxing (a total of 4 times in ~350 LOC) of the view tree and callbacks solved the problem for me.

Anyway, at the time this ViewArgument "experiment" landed, I was skeptical of its benefits and annoyed with its cumbersome Arg/Edit/Read wrapping usage. But now I do think that the design has its merit.

Alas, it is gone while I have been away, having fun using it. 😢

@flosse
Copy link
Contributor Author

flosse commented Feb 19, 2026

But now I do think that the design has its merit.

What exactly do you mean?

@RagibHasin
Copy link
Contributor

@RagibHasin
Copy link
Contributor

I just remembered that we've removed Adapt view earlier. I see no option other than index-unwrap in the child.

@flosse
Copy link
Contributor Author

flosse commented Feb 20, 2026

Sorry, I still don't understand the problem. What do you mean by

I see no option other than index-unwrap in the child.

Are you talking about this line?

let (idx, reader_state) = state.reader.as_mut().unwrap();

Your reader field is a Option:

pub reader: Option<(usize, ScrollingReader)>

So you either unwrap it (I wouldn't do that) or you map it.
But this has nothing to do with Xilem or ViewArgument.

I assume you mean something else, but please specify exactly what you mean!

@RagibHasin
Copy link
Contributor

With ViewArgument it would only need to be unwrapped/mapped once in map_state. Without it all event handlers now might need to.
I used to pass a mutable reference to an item of a Vec describing progress. Now It might not be possible to do cleanly. I've not ported the code back to pre/post-ViewArgument era.
I'd let you know.

And you might read the whole file I linked earlier. If you have any suggestions how can I better structure the code, I'd be very grateful. Thanks!

@RagibHasin
Copy link
Contributor

Okay, I've gotten around to update Xilem for my project and here is the diff.

Notice that:

  1. It now has become necessary to have a copy of a global state (font_size) in reader's local state.
  2. Also, setting of preference now needs a piggyback on action mapping, which is a code pattern I don't like much.

An alternative would have been to have AppState as the state type for all views, which leaks access to unnecessary parts of AppState to views, creating potential for misuse.

And the aforementioned first problem is also error-prone, as it is possible to forget to update the local state in the event handler.


But all that said, I think I was one of the first to be bitten by the ViewArgument experiment when it was introduced and there is some conversation between me and Daniel concerning possible type-inference breakage that you have been facing. But I still maintain that ViewArgument design was superior if type-inference can be fixed, which it seems would be when the next trait solver lands. We should revisit it then.

Thanks for your patience!

@RagibHasin
Copy link
Contributor

And the aforementioned first problem is also error-prone, as it is possible to forget to update the local state in the event handler.

I just now figured out that a local copy of the font size in the view function would do the trick. No need to duplicate data in AppState. Thus my main gripe with it is mostly solved. 👍🏽

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants