Hi all,
I wanted to share some thoughts on custom elements (CEs) and how they
relate to UI patterns that separate model from view -- various themes
and variations on MVC (model, view, controller):
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Basically, CEs don't encourage separation of model and view (data/state
and presentation). One of the main things they offer over plan HTML is
letting you couple JS logic with a particular piece of HTML/CSS UI. One
of their main use cases was to bundle all of that up into self-contained
units that could be dropped wherever but not de-composed. (I.e. put a
google maps widget on your website.) In short, they enable and tend to
encourage keeping state in DOM nodes/local component state, which
couples the model and view together.
Separating model and view is a pretty well established UI approach with
various benefits. MVC dates from the 1970s, and more recently in the
web dev world we had a broad shift away from jQuery to React/Redux etc.
While CEs make a lot of sense as an upgrade/migration path away from
XBL, I think it's worth considering as we go forward, whether we should
move towards greater separation between model and view in our UI code.
I think there's a lot of unnecessary complexity and brittleness in our
UI code that could be improved by this kind of separation of concerns.
Here are a couple of articles on this topic:
UI as an afterthought
Makes the general case really well.
https://medium.com/@mweststrate/ui-as-an-afterthought-26e5d2bb24d6
Choosing a web component Model
A short post I found that makes the comparison between web components
and MVC, etc.
https://medium.com/@daveford/choosing-a-web-component-model-f83bb9a8edae
Consider an example. Just for sake of argument, say we wanted to offer
two UIs for entering recipients for a message, a plain text one and a
pill-based one, and we wanted to be able to toggle between them on the
fly. Or maybe an addon wants to offer an alternative UI.
If we have the model separate from the view, then it is just a matter of
switching the view. If we have our model coupled with one particular
view, then it is not so simple.
Consider addons that want to modify the UI (like "Conversations" or
"CardBook"). It would be much more feasible to see how that could work
if we had more separation between model and view. It's easier to
imagine where WebExtensions APIs might hook in, in a world with greater
model/view separation.
Or consider making TB more scriptable via command line, etc.
These are just some preliminary thoughts I've had about this as I've
been working with CEs, and now as we move past de-XBL to moving the UI
forward. Curious to hear what others think.
-Paul
--
Paul Morris
Thunderbird.net
I kind of completely agree with you.
Coming from lots of years of Angular, Laravel, and VueJS, I love the MVC
approach and it makes monolith applications incredibly easy to maintain
and extend.
Since I'm having this sort of thought process while coding the new
address pills, I was trying to find a decent solution in order to make
the pills easily reusable and adaptable to various locations in the UI.
Maybe creating a basic MozElement as a CE acting as a model that can be
extended freely to create dedicate CEs that act only as views.
Something similar, but not quite identical, is how the new Notification
system is handled in m-c:
https://searchfox.org/mozilla-central/rev/c8933daeb71df02566407eff88904ee981a7bcdd/toolkit/content/widgets/notificationbox.js
There's a MozElements.NotificationBox
class that handles all the data
and the various actions and behavior of a notification-box element, but
the actual notification-box UI is a Custom Element defined as
"notification".
So far, this is the closest attempt of separating the model from the
view I've stumbled upon.
I think it's worth exploring this approach.
On 2019-10-11 11:07, Paul Morris wrote:
Hi all,
I wanted to share some thoughts on custom elements (CEs) and how they
relate to UI patterns that separate model from view -- various themes
and variations on MVC (model, view, controller):
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Basically, CEs don't encourage separation of model and view
(data/state and presentation). One of the main things they offer over
plan HTML is letting you couple JS logic with a particular piece of
HTML/CSS UI. One of their main use cases was to bundle all of that up
into self-contained units that could be dropped wherever but not
de-composed. (I.e. put a google maps widget on your website.) In
short, they enable and tend to encourage keeping state in DOM
nodes/local component state, which couples the model and view together.
Separating model and view is a pretty well established UI approach
with various benefits. MVC dates from the 1970s, and more recently in
the web dev world we had a broad shift away from jQuery to React/Redux
etc.
While CEs make a lot of sense as an upgrade/migration path away from
XBL, I think it's worth considering as we go forward, whether we
should move towards greater separation between model and view in our
UI code. I think there's a lot of unnecessary complexity and
brittleness in our UI code that could be improved by this kind of
separation of concerns. Here are a couple of articles on this topic:
UI as an afterthought
Makes the general case really well.
https://medium.com/@mweststrate/ui-as-an-afterthought-26e5d2bb24d6
Choosing a web component Model
A short post I found that makes the comparison between web components
and MVC, etc.
https://medium.com/@daveford/choosing-a-web-component-model-f83bb9a8edae
Consider an example. Just for sake of argument, say we wanted to
offer two UIs for entering recipients for a message, a plain text one
and a pill-based one, and we wanted to be able to toggle between them
on the fly. Or maybe an addon wants to offer an alternative UI.
If we have the model separate from the view, then it is just a matter
of switching the view. If we have our model coupled with one
particular view, then it is not so simple.
Consider addons that want to modify the UI (like "Conversations" or
"CardBook"). It would be much more feasible to see how that could
work if we had more separation between model and view. It's easier to
imagine where WebExtensions APIs might hook in, in a world with
greater model/view separation.
Or consider making TB more scriptable via command line, etc.
These are just some preliminary thoughts I've had about this as I've
been working with CEs, and now as we move past de-XBL to moving the UI
forward. Curious to hear what others think.
-Paul
--
Alessandro Castellani
Lead UX Architect
Thunderbird
Hi Paul,
this is definitely an interesting topic. To me there are two areas to
this, one being separating the HTML from Javascript (view from
controller), and the other being separating the view/controller from the
model.
The latter point, to my mind, is pretty clear. Web Components should not
have any model code. They should be re-usable widgets that are
self-contained. The way they get their model data is setters, which will
re-render as appropriate. This means the controller that drives the
window those elements are in will need to update those custom elements
by getting from the model and setting on the custom element.
The former point is a complaint I've had with react as well, and
especially coming from XBL something I am unhappy about with custom
elements. Having to either create dom nodes with javascript or using
some form of templating system kills the great separation I am used to
with XBL. Similarly, styling information needs to be within the node
somehow, so it ends up being within the javascript. I think currently
there aren't a lot of ways go resolve this, as long as web components
are defined in js. You can have separate files and load them using
DOMParser and friends. You can use template strings as well.
What I've been doing for now is to make the style and content static
getters on the element. This at least allows some degree of separation
and avoids manual dom node creation. There are certainly some things
that could be generalized into a super class. See here for example:
https://github.com/kewisch/quickmove-extension/blob/webextension/popup/folderlist.js
. When these components are being re-used you could also do the parsing
into a document fragment once in a static method and then re-use that on
each instance.
For your example, the model would be separate from any custom element. A
controller for the window would be responsible for retrieving that data,
and feeding it to the custom element. Maybe both the pill based and
plain UIs would have the same setters, so switching would just be a
matter of the controller determining the preference and then swapping
out the elements. The add-ons argument is a whole other can of worms,
though of course a good architecture would indeed make it easier to
integrate.
I think this might be a good topic to explore further and maybe even
blog about. Thanks Paul for venturing into this, I'm glad we are
spending time on the architecture of Thunderbird and not only patching
holes.
Philipp
On 10/11/19 8:07 PM, Paul Morris wrote:
Hi all,
I wanted to share some thoughts on custom elements (CEs) and how they
relate to UI patterns that separate model from view -- various themes
and variations on MVC (model, view, controller):
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Basically, CEs don't encourage separation of model and view
(data/state and presentation). One of the main things they offer over
plan HTML is letting you couple JS logic with a particular piece of
HTML/CSS UI. One of their main use cases was to bundle all of that up
into self-contained units that could be dropped wherever but not
de-composed. (I.e. put a google maps widget on your website.) In
short, they enable and tend to encourage keeping state in DOM
nodes/local component state, which couples the model and view together.
Separating model and view is a pretty well established UI approach
with various benefits. MVC dates from the 1970s, and more recently in
the web dev world we had a broad shift away from jQuery to React/Redux
etc.
While CEs make a lot of sense as an upgrade/migration path away from
XBL, I think it's worth considering as we go forward, whether we
should move towards greater separation between model and view in our
UI code. I think there's a lot of unnecessary complexity and
brittleness in our UI code that could be improved by this kind of
separation of concerns. Here are a couple of articles on this topic:
UI as an afterthought
Makes the general case really well.
https://medium.com/@mweststrate/ui-as-an-afterthought-26e5d2bb24d6
Choosing a web component Model
A short post I found that makes the comparison between web components
and MVC, etc.
https://medium.com/@daveford/choosing-a-web-component-model-f83bb9a8edae
Consider an example. Just for sake of argument, say we wanted to
offer two UIs for entering recipients for a message, a plain text one
and a pill-based one, and we wanted to be able to toggle between them
on the fly. Or maybe an addon wants to offer an alternative UI.
If we have the model separate from the view, then it is just a matter
of switching the view. If we have our model coupled with one
particular view, then it is not so simple.
Consider addons that want to modify the UI (like "Conversations" or
"CardBook"). It would be much more feasible to see how that could
work if we had more separation between model and view. It's easier to
imagine where WebExtensions APIs might hook in, in a world with
greater model/view separation.
Or consider making TB more scriptable via command line, etc.
These are just some preliminary thoughts I've had about this as I've
been working with CEs, and now as we move past de-XBL to moving the UI
forward. Curious to hear what others think.
-Paul
Hi Philipp and Alessandro,
I like the approach Philipp laid out below, especially concerning
separation between models and views.
I don't have as strong a feel for the need for separation between
controller and view (e.g. JS and HTML). That probably shows how I've
been influenced by React, and the uni-directional data flow
approach[0][1]. In any case our options there seem more limited, and
Philipp's approach/example of making "the style and content static
getters on the element" makes sense to me.
So there would be one controller object for any given window. I'm less
clear on what the model part might look like. Would it be one model
object per component/custom element, one model per window, or something
else?
Custom elements would have event listeners on them for user input, but
(for separation between view and controller) they would respond to user
input events by say calling functions in the controller code, passing
along the relevant data, and letting the controller code handle them.
So that's another piece of how this could work.
-Paul
[0]
https://www.exclamationlabs.com/blog/the-case-for-unidirectional-data-flow/
[1]
https://vaibhavgupta.me/2018/01/07/bidirectional-vs-unidirectional-data-flow-architecture/
On 10/12/19 8:07 AM, Philipp Kewisch wrote:
Hi Paul,
this is definitely an interesting topic. To me there are two areas to
this, one being separating the HTML from Javascript (view from
controller), and the other being separating the view/controller from
the model.
The latter point, to my mind, is pretty clear. Web Components should
not have any model code. They should be re-usable widgets that are
self-contained. The way they get their model data is setters, which
will re-render as appropriate. This means the controller that drives
the window those elements are in will need to update those custom
elements by getting from the model and setting on the custom element.
The former point is a complaint I've had with react as well, and
especially coming from XBL something I am unhappy about with custom
elements. Having to either create dom nodes with javascript or using
some form of templating system kills the great separation I am used to
with XBL. Similarly, styling information needs to be within the node
somehow, so it ends up being within the javascript. I think currently
there aren't a lot of ways go resolve this, as long as web components
are defined in js. You can have separate files and load them using
DOMParser and friends. You can use template strings as well.
What I've been doing for now is to make the style and content static
getters on the element. This at least allows some degree of separation
and avoids manual dom node creation. There are certainly some things
that could be generalized into a super class. See here for example:
https://github.com/kewisch/quickmove-extension/blob/webextension/popup/folderlist.js
. When these components are being re-used you could also do the
parsing into a document fragment once in a static method and then
re-use that on each instance.
For your example, the model would be separate from any custom element.
A controller for the window would be responsible for retrieving that
data, and feeding it to the custom element. Maybe both the pill based
and plain UIs would have the same setters, so switching would just be
a matter of the controller determining the preference and then
swapping out the elements. The add-ons argument is a whole other can
of worms, though of course a good architecture would indeed make it
easier to integrate.
I think this might be a good topic to explore further and maybe even
blog about. Thanks Paul for venturing into this, I'm glad we are
spending time on the architecture of Thunderbird and not only patching
holes.
Philipp
On 10/11/19 8:07 PM, Paul Morris wrote:
Hi all,
I wanted to share some thoughts on custom elements (CEs) and how they
relate to UI patterns that separate model from view -- various themes
and variations on MVC (model, view, controller):
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Basically, CEs don't encourage separation of model and view
(data/state and presentation). One of the main things they offer
over plan HTML is letting you couple JS logic with a particular piece
of HTML/CSS UI. One of their main use cases was to bundle all of
that up into self-contained units that could be dropped wherever but
not de-composed. (I.e. put a google maps widget on your website.)
In short, they enable and tend to encourage keeping state in DOM
nodes/local component state, which couples the model and view together.
Separating model and view is a pretty well established UI approach
with various benefits. MVC dates from the 1970s, and more recently
in the web dev world we had a broad shift away from jQuery to
React/Redux etc.
While CEs make a lot of sense as an upgrade/migration path away from
XBL, I think it's worth considering as we go forward, whether we
should move towards greater separation between model and view in our
UI code. I think there's a lot of unnecessary complexity and
brittleness in our UI code that could be improved by this kind of
separation of concerns. Here are a couple of articles on this topic:
UI as an afterthought
Makes the general case really well.
https://medium.com/@mweststrate/ui-as-an-afterthought-26e5d2bb24d6
Choosing a web component Model
A short post I found that makes the comparison between web components
and MVC, etc.
https://medium.com/@daveford/choosing-a-web-component-model-f83bb9a8edae
Consider an example. Just for sake of argument, say we wanted to
offer two UIs for entering recipients for a message, a plain text one
and a pill-based one, and we wanted to be able to toggle between them
on the fly. Or maybe an addon wants to offer an alternative UI.
If we have the model separate from the view, then it is just a matter
of switching the view. If we have our model coupled with one
particular view, then it is not so simple.
Consider addons that want to modify the UI (like "Conversations" or
"CardBook"). It would be much more feasible to see how that could
work if we had more separation between model and view. It's easier to
imagine where WebExtensions APIs might hook in, in a world with
greater model/view separation.
Or consider making TB more scriptable via command line, etc.
These are just some preliminary thoughts I've had about this as I've
been working with CEs, and now as we move past de-XBL to moving the
UI forward. Curious to hear what others think.
-Paul
--
Paul Morris
Thunderbird.net