jaspr
jaspr copied to clipboard
Add utility methods / components for common html elements
Discussion related to #13
Status quo
The current way of defining html elements is by using DomComponent
and providing a tag
. This leaves the most freedom to developers, but can get verbose quickly when composing uis:
This:
return DomComponent(
tag: 'div',
children: [
DomComponent(
tag: 'h1',
child: Text('This is a title'),
),
DomComponent(
tag: 'p',
children: [
Text('Hello '),
DomComponent(
tag: 'b',
child: Text('World!'),
),
],
),
],
);
is unarguably a lot more verbose than standard html:
<div>
<h1>This is a title</h1>
<p>Hello <b>World!</b></p>
</div>
Proposal / Discussion
While DomComponent
should stay as the low-level base for all html elements, we need a more simple way to use common html elements like div
and others. This should be added on top of the core framework and be optional to use by the developer.
What should such an element look like?
There are two ways we could define such elements:
- As their own
StatelessComponent
- As methods returning a
DomComponent
Separate components (1) would define a class for each element, take any arguments in the constructor and return a DomComponent
in the build()
method. Since classes use PascalCase for their naming, we either
- (a) capitalize the tag name (
Div
,P
,H1
), or - (b) extend the tags to their more descriptive names (
Division
,Paragraph
,Heading1
).
Both are not really ideal, since (a) would have a bunch of single-letter class names and (b) would be again quite verbose for a lot of elements. Additionally, having separate components introduces a lot of extra depth into the component tree when building uis (2 components for each element, the elements component + the dom component), which will have some performance implications for larger apps.
Element methods (2) would provide a way to define shorthands for common elements without the overhead of additional components. A method can also have custom properties specific for the element and would just return a single DomComponent
with the static tag and provided attributes. Methods also have lower-case names and could directly mirror the original html tags (div()
, p()
, h1()
), keeping the code concise and appearing similar to original html.
Which elements are included?
Of course we want as many elements included as possible, however this might be a challenge as there are a lot of different elements in the html spec.
When writing this manually we would have to start with a few most common elements and expand the list over time. However this would also mean a lot of maintenance when the component api or properties of DomComponent
change (which might happen since jaspr is very early stage).
A better and more easy way would be to generate the methods and their bodies for each html element automatically. A good example would be domino_html which does exactly this for the domino package. It uses a script that crawls developer.mozilla.org/en-US/docs/Web/HTML/Element and developer.mozilla.org/en-US/docs/Web/HTML/Attributes to get all html elements and their attributes. Modifying this script to output jaspr-compatible code should be feasible. There are however some additional considerations to make:
- Some of the element have many uncommon attributes. These get very verbose and make the parameter list unclear and convoluted. A possibility would be to not include global attributes as defined by the attributes page.
- Some attributes have custom types other than
String
(mainlyboolean
,int
or enums). It would be cool to provide them as typed attributes (especially the enums), but I don't know right now how to get this information, since it is not specified in the attributes page.
I found that the content source for mdn is also here: https://github.com/mdn/content/tree/main/files/en-us/web/html/element Not really structured data, but at least markdown files for each element, so parsing this might be easier.
@schultek Did you see my code here: https://github.com/schultek/jaspr/pull/13 how I implemented it there?
I define new elements as class inherited from StatelessComponent
which have some more extra parameters depends on the specific element but in result you are still building only one DomComponent so you don't have a lot of extra depth into the component tree
.
I am for naming in more descriptive names. I don't like any very short names of classes or functions/methods so
P
, H1
, a
, b
are too short.
Minimal length 3 characters are good for me yet so Div
have really minimal length. Divider
is a little better.
I don't like also idea about methods returning DomComponent
.
I would like to keep this framework in more Flutter like style then domino_html
style so new elements should be classes inherited from StatelessComponent
I think.
Also I don't think that we should mirror original html tags. I would like create web framework for developers which want to create web pages in Dart but doesn't have any HTML/CSS knowledge. I would like create framework which will be similar or same simple like Flutter with very good community and great documentation/tutorials. Jaspr should not have HTML/CSS knowledge as a requirements for development with it.
So instead of: a
, h1
, div
, img
, br
, hr
, tr
, td
, etc..
I would like use: Link
, Header
, Container
, Image
, Table
, Row
, Cell
, etc..
and instead of styling elements: i
, b
, em
, strong
we should use CSS styles.
And we really cannot implement absolutely all html elements with all their attributes.
I want to keep it really simple how we can and implement only elements/tags which we really need.
Here is my list of the most frequently HTML elements and their CSS styles which we should implement and others (for ex. iframe) we can implement later if it will be really important.
I looked at the pr in detail, but just wanted to take a step back and discuss what's the best way to implement this.
I get your point and agree that we should make things simple + familiar for flutter devs. But I also want the framework to be appealing to web devs, and as a web dev I would want to have the actual bare-bone html elements. Thinking about it, targeting both with a single set of components might be difficult to impossible.
Let's take the Link
component for example. For flutter devs this might be good and easier to understand than maybe an Anchor
component (a
tag). However for web devs this is confusing because there is also the link
tag which then wouldn't have its own component.
So then we would have to have two sets of components
- bare-bone html elements for web devs (
a
,h1
,div
, etc...) - simple flutter-like components (
Link
,Header
,Container
,Row
, etc...)
So the question is if we have to / want to decide on one and leave the others out, or implement both for the developer to choose (e.g. under a separate import like package:jaspr/html.dart
vs package:jaspr/components.dart
)
Yes OK, I understand. For me as non web developer I don't like tags like a
, h1
, div
, etc.. for me are not readable and understandable a lot. Hence I didn't work with HTML/CSS a lot in past.. ;-)
But I understand your view and I agree with you.
So let's go create two separate libraries with imports package:jaspr/html.dart
and package:jaspr/components.dart
.
You can develop on bare-bone html elements which will be methods returning DomComponent
.
I will develop on Flutter-like elements which will be usable for non web developers.
And developers can choose which will better for them. :-)
Sounds like a plan. 👍
So when I will have a time, I will change package:jaspr/ui.dart
to package:jaspr/components.dart
in my PR.