comments
As its name suggests, UI.Next was created to be the next-generation standard library for UI programming in WebSharper. As a consequence, as of WebSharper 4.0, UI.Next will be merged into WebSharper itself under a less "codenamey" moniker that we haven't decided yet. It will completely obsolete the current Html.Client and Html.Server.
The recently released version 3.4 prepares the terrain for this merger. It streamlines the embedded markup syntax, introduces server-side capability and adds client-side functionality.
Streamlined syntax
WebSharper UI.Next 3.4 overhauls the syntax for embedding HTML elements in F# for enhanced readability and familiarity.
The most visible change is the switch to lowercase elements and attributes, making UI.Next code more similar to what you would write in an HTML file. For elements, the function Div0 which creates a <div> tag with child elements becomes simply div, and Div which creates a <div> tag with attributes and child elements becomes divAttr. For attributes, the class attr contains static methods to create standard attributes and on creates event handlers. Here is a list of the new constructors available under WebSharper.UI.Next.Html:
New syntax | Old / Verbose syntax | |
|
| |
|
| |
|
| |
|
| Needs |
|
| |
|
| Needs |
|
| Needs |
|
| Needs |
See "Tier-specific functionality" below for the rationale behind needing open WebSharper.UI.Next.Client for some of these.
Here is a small code sample:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/// New syntax │ /// Old syntax
open WebSharper.UI.Next │ open WebSharper.UI.Next
open WebSharper.UI.Next.Html │ open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Client │
│
let myDocument = │ let myDocument =
let rvInput = Var.Create "" │ let rvInput = Var.Create ""
div [ │ Div0 [
h1 [text "A small example"] │ H10 [Doc.TextNode "A small example"]
label [text "Type something here: "] │ Label0 [Doc.TextNode "Type something here: "]
Doc.Input [] rvInput │ Doc.Input [] rvInput
pAttr [attr.``class`` "paragraph"] [ │ P [Attr.Create Attributes.Class "paragraph"] [
text "You typed: " │ Doc.TextNode "You typed: "
textView rvInput.View │ Doc.TextView rvInput.View
] │ ]
] │ ]Server-side markup
It is now possible to use the Doc type, and the above syntax, to create server-side markup, ie. markup that is generated on the server and output in the HTML document, as opposed to client-side markup, generated dynamically in JavaScript.
Returning a server-side Doc as content
There are two ways to use a Doc as server-side content:
Use
Content.Docto create a SiteletsContent<_>value:1 2 3 4 5 6 7 8
open WebSharper.Sitelets open WebSharper.UI.Next open WebSharper.UI.Next.Server [<Website>] let MyWebsite = Application.SinglePage <| fun context -> Content.Doc myDocumentConvert it to
Html.Serverelements usingDoc.AsElements:1 2 3 4 5 6 7 8 9 10
open WebSharper.Sitelets open WebSharper.UI.Next open WebSharper.UI.Next.Server [<Website>] let MyWebsite = Application.SinglePage <| fun context -> Content.Page( Body = Doc.AsElements myDocument )
Including client-side markup
In order to include a client-generated Doc inside a server-side Doc, you can use the function client. This function is analogous to ClientSide from Html.Server: it takes a quotation of a top-level, [<JavaScript>]-annotated function and includes it in server-side markup.
You can also add event handlers on server-side Docs using the methods in the on class. These methods take a quotation of a top-level, [<JavaScript>]-annotated function and return an Attr value that sets the handler as a static attribute on the element. This means that only one handler of a given type can be added to an element this way: you can't have two instances of eg. on.click <@ ... @> on the same server-side Doc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
open WebSharper
open WebSharper.UI.Next
open WebSharper.UI.Next.Html
[<JavaScript>]
module Client =
open WebSharper.JavaScript
open WebSharper.UI.Next.Client
let Widget() =
let rvInput = Var.Create ""
Doc.Concat [
Doc.Input [] rvInput
p [text "You typed: "; textView rvInput.View]
]
let Alert el ev =
JS.Alert "Clicked!"
module Server =
open WebSharper.Sitelets
open WebSharper.UI.Next.Server
[<Website>]
let MyWebsite =
Application.SinglePage <| fun context ->
Content.Doc(
div [
h1 [text "Enter text below"]
client <@ Client.Widget() @>
buttonAttr [on.click <@ Client.Alert @>] [text "Click me!"]
]
)Tier-specific functionality
Some Doc functionality is only available on the client, or only on the server. To use such functionality, you need to open WebSharper.UI.Next.Client or WebSharper.UI.Next.Server, respectively.
The following is only available on the client side, and will raise a runtime error if used from the server side:
- Reactive elements and attributes:
textView,Doc.EmbedView,attr.*Dyn,attr.*DynPred,attr.*Anim,Doc.Convert*, reactive form elements (Doc.Input, etc). Doc.Run,Doc.RunById,Doc.AsPageleton.*event handlers taking a function as argument. On the server you must use the version taking a quotation as argument.- Element methods and properties described below in "New client-side functionality".
The following is only available on the server side, and will raise a compile-time error if used from the client side:
Content.Doc,Doc.AsElements,Attr.AsAttributes.
New client-side functionality and the Elt type
One challenge in entirely replacing Html.Client with Doc is that existing applications using Html.Client should be convertible without requiring a complete change in paradigm. This means that we need to add as much of the imperative capabilities of Html.Client to Doc as possible. However, a Doc value is not guaranteed to be composed of a single root element, so accessing the element to perform actions such as SetAttribute or Append cannot be guaranteed to succeed. To fix this, we made the following change to the API.
The Doc type is now an abstract class, and there is a new type Elt that inherits from it and represents docs that are guaranteed to be composed of a single root element. The following functions return an Elt:
- Element constructors, such as
divanddivAttr. Doc.Element,Doc.SvgElement,Doc.Static.- Form input element constructors:
Doc.Input,Doc.Button, etc.
Values of type Elt, in addition to being Docs, also have the following properties and methods (non-exhaustive list):
Domreturns the underlyingDom.Element.Append(doc)andPrepend(doc)add childDocs to the beginning / end of the element. ReactiveDocs are properly handled.Clear()removes all children. Reactive children are properly disconnected from theViewgraph.Textgets or sets the text content. The setter properly disconnects reactive children from theViewgraph.Valuegets or sets the value.- Methods to get, set, remove, test the presence of attributes, classes, styles:
GetAttribute,SetProperty,HasClass, etc. On "eventName" functionadds an event callback.
We are still ironing out tricky parts required to implement OnAfterRender, which is quite ubiquitous in Html.Client code.
Templating language change
In order to allow using ${string} holes from the server side, the following change has been implemented:
${string}holes now have typestringinstead ofView<string>.$!{string}is the new syntax for holes of typeView<string>.
Conclusion
As you can see, a lot of enhancements are necessary to allow UI.Next markup to be usable as a replacement of Html.Client and Html.Server. We are confident that these changes will make it easy to convert existing applications to UI.Next for WebSharper 4.0.
Happy coding!







Hi, I am totally new to websharper and I found this blog post by chance while "googling" "Element vs Elt websharper".
From my understanding, UI.Next will supersede Html.Client and function like Div0 will become div. Does it mean that the documentation for UI.Next will not be valid anymore?
For the basic example in the doc, the code is the following:
let basicExample() = ... beginning ... Div [] [ Doc.Input [] rvContent Label [] [Doc.TextView vUpperContent] ]Should it be:
let basicExample'() = ... beginning ... div [ Doc.Input [] rvContent label [textView vUpperContent] ]As a newcomer it was a bit confusing until I found this blog post. If this is correct, do you have any plan to update the doc?
Thanks!