After a bit of playing around I landed on a component system for s&box. So instead of making a big webpage and trying to maintain it, you create a lot of smaller components and make them work together. To do this we use
vue, and a slightly modified version of their
single file components.
So lets take a simple example.
Health HUD
Show health and armour on the HUD.
C# Component
The managed component is responsible for providing the data for the UI. One of the things I was keen to do was minimize the amount of javascript you have to write, because ideally all of that logic is in c#, and you're just displaying data in html.

So as you can see this is setting the properties Health and Armour from the local player's health and armour every tick.
We add this component when creating the main HUD (you can add new components at any point in time).
Vue file
The vue is a single file, but I'm going to break it down here.

The template section contains the html. The stuff in curly brackets are data. Notice how they have the same name as the properties in the c# file? That's because they're bound to them. Change the value on the managed side and it'll update those. The icons before each number are just
material icons.
The ":class=" part translates to "set the class "none" if Armour is lower or equal to 0".
Then we have the style block, which is self explanatory if you already know css. Maybe daunting if you don't.

This sets the vitals class to absolute positioned. This means it won't show inline, it'll be positioned globally on the page somewhere. We're setting the left and bottom to 16px, so it'll show 16px from the bottom left corner. We set the display mode to flex. This is just to let us vertical align stuff better.

This is setting the style of any "div" elements inside the "vitals" class. Basic styling stuff, font size, color, alignment, spacing.

Remember we added that condition to add the "none" class if armour was 0? This says that any divs under "vitals" with the "none" class should have 20% opacity.