Skip to content

Components #17

Description

@schmylan

Xero (the language)

Directive

What would a component look like if the goal was to make it "... as simple as possible, but no simpler" and to adhere as closely to the HTML spec as possible?

Important

Isn't this just reinventing Web Components?

Web Components are great. They're a part of the HTML and DOM specs which means they'll probably outlive any of us humans currently alive. This is a wonderful thing and fully inline with the spirit of this article of combating framework fatigue. Xero has zero intention of replacing Web Components and plans on using them profusely.

The distinction is this: Web Components run in the browser. Xero runs before the browser. In the latter scenario there isn't always a DOM or scripting environment available but that's a good thing as it opens the door for things like portability and hoisting compexities up the stack in the name of simplifying its own spec.

Benefits

  • It should be compatible with both static site generation as well as dynamic hosting.
  • It should consist only of "markup language" with no imperative code so it can be fully language agnostic.
  • It can be made compatible with any flavor of templating one might prefer - whether {{ mustache }}, <?php ...;?>, <%= ERB %>, <> JSX </> or other.

What to call it?

Below, you'll find mentions of this approach being usable in any languange since it's "just markup language." Conceptually Xero goes beyond just components so I guess this approach needs its own name. Giving it yet-another-name (like JSX is to React) and requiring an understanding of where its responsibilitis begin and end would be counter-productive to the core goal of this article of reducing framework-fatigue. Therefore perhaps it's smartest to use the "Java way" which just names everything Java, whether it's Java-the-language, Java-the-runtime or Java-the-platform. So allow me to introduce Xero... the language!

HTML documents as components

I believe Angular gets credit for exploring this first but I am not sure. Here are a few embellishments.

Inclusion

  • Everything's a component! (Although, it'd be nonsensical to embed a component with <html> nodes inside another.)
  • Inclusion is handled by the file system.
  • Case sensitivity matters.
  • Only alpha-numerics and underscores are allowed. No spaces. Cannot begin with a number.
index.html
<html>
  <head></head>
  <body>
    <my-component />
  </body>
</html>

my-component.html
<p>Hello world</p>

Outputs
<html>
  <body>
    <p>Hello world</p>
  </body>
</html>

Namespacing

  • Any component can reference another component (regardless of its location in directory structure) using only its file name (excluding the extension).
  • Obviously this is scoped to the project root and does not extend to the entire file sytem.
  • In the even a directory includes two files of the same name but different extensions (i.e. .html and .htm) then the first alphabetically will be used and others will be ignored.
  • HTML has a spirit of being forgiving, therefore namespace collisions do not result in an error. Since two files can have the same name if located in different directories priority is determined as follows:
    1. Prefer the file that is in the same directory as the referencing component.
    2. Prefer the file that is in a descendant director over any files located in ancestor paths (i.e. great-grandchildren before cousins).
    3. If two files of the same name are both in various descendent directories:
    • Prefer the one with shorter directory depth
    • Prefer the one which path sorts alphanumerically first.
  • To explicitly reference components with naming collisions:
    • Use / notation and the names of directories. (Captialization matters.)
    • Use '//' shorthand notation to skip any number of directories and reduce verbosity
    • There is an implied // at the beginning of every component unless an explicit / is used.
File structure:
- my-project/
  - ui/
    - music/
      - components/
        - score.html
     - index.html
    - sports/
      - components
        - score.html
        - music/
          - score.html

index.html with full namespacing
<html>
  <body>
    </my-project/ui/music/components/score />
    </my-project/ui/sports/components/score />
    </my-project/ui/sports/components/music/score />
  </body>
</html>

index.html can be greatly simplified with shorthand notation `//`
<html>
  <body>
    <music//score />
    <sports//score />
    <sports//music/score />
  </body>
</html>

Attributes

Reusability is greatly increased with attributes. Components do not define their inputs upfront. Instead they just use them inline, escaped with a moustache-inspired {{}}.

index.html
<html>
  <head></head>
  <body>
    <my-component name="Rylan" />
  </body>
</html>

my-component.html
<p>Hello {{name}}</p>

Outputs
<html>
  <body>
    <p>Hello world</p>
  </body>
</html>

In an attempt to be as language-agnostic as possible, what goes inside the {{}} is outside the scope this spec and left as an implementation detail of the runtime.

index.html
<html>
  <head></head>
  <body>
    <my-component name="Rylan" />
  </body>
</html>

my-component.html
<p>Hello {{name}}!</p>

Outputs
<html>
  <body>
    <p>Hello Rylan!</p>
  </body>
</html>

By default, all attribute values are treated as strings which feels natural since they are contained inside double-quotes ". Some implementing lanuages would benefit greatly from some clues on data types, however. The primitives, string, integer, double, boolean, character can be supported in the following ways.

Support for objects more sophisticated than the primitive above is beyond the scope of this spec and is intentionally left open-ended for the implementing language to support by containing it within curly braces {{}} however it pleases. Please note that including your curly braces AND double-quotes as an attribute value (e.g. ` will be treated as a raw string value instead of an object.

Treated as a regular string:
<node attr="I am a string!" />

Treated as an integer:
<node attr=3 />

Treated with floating-point precision:
<node attr=3.0 />

Treated as booleans:
<node attr=true />
<node attr=false />

Treated as a characater:
<node attr='a' />

Treated as an object:
<node attr={{dateTime}} />

Treats attr as null (or undefined where available):
<node />

Composition (nested tags)

HTML tags are inherently nestable. Taking inspiration from Web Components' <slot> tag, Xero lets you build similarly with its escaped slots.

Usage my-button.html Output
<my-button>
  <h2>Click me</h2>
</my-button>
<button>
  {{slot}}
</button>
<button>
  <h2>Click me</h2>
</button>

If there's more than one slot, they can be referenced by name.

Usage my-button.html Output
<my-button>
  <img slot="icon" src="info.svg" />
  <h2 slot="message">Click me</h2>
</my-button>
<button>
  <slot name="icon"></slot>
  <slot name="messages"></slot>
</button>
<button>
  <img src="info.svg" />
  <h2>Click me</h2>
</button>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions