How "safe" are Angular 2 custom HTML tags? (selectors: Custom tags vs. Custom attributes)
Asked Answered
D

1

8

This is a question regarding Angular 2 selectors, Custom tags vs. Custom attributes, SEO, and browser rendering.

When I first started to look over Angular 2, the very first thing I did when following their quickstart, right of the bat, was to change my selector to '[my-component]' (attribute selector) instead of 'my-component' (tag selector), so I could have <div my-component></div> in my HTML instead of <my-component></my-component>, which isn't valid HTML. So I would write HTML according to standards. Well, at least pretty close to standards (because my-component isn't a valid HTML attribute, but I could live with only that HTML validation error)

Then, at some point in a video on YouTube, someone from the angular team mentioned that we should use the tag selector, performance wise at least.

Alright I said, screw HTML validation... or shouldn't I?
So:

  1. Say I ignore the W3C screaming about my HTML being completely invalid because of the <custom-tags>. I actually have another bigger and more real concern: how does this impact SEO?
    I mean don't just think client-side app, because in the real world (and for my angular 2 project as well) I also have server-side rendering, for 2 very important reasons: SEO and Fast initial rendering of the site to the user for that initial view, before the app bootstraps. You can not have a very high traffic SPA otherwise.
    Sure, google will crawl my site, regardless of the tags I use, but will it rank it the same in both scenarios: one with <custom-make-believe-tags> and the other with only standard HTML tags?

  2. Let's talk browsers and CSS:

As I started to build my first SPA site in Angular 2, I was immediately faced with another concern:
Say (in a non SPA site) I have the following HTML markup:

<header>
    <a class="logo">
        ...
    </a>

    <div class="widgets">
        <form class="frm-quicksearch"> ... </form>
        <div class="dropdown">
            <!-- a user dropdown menu here -->
        </div>
    </div>
</header>

<div class="video-listing">
    <div class="video-item"> ... </div>
    <div class="video-item"> ... </div>
    ...
</div>

Angular 2 wise I would have the following component tree:

<header-component>
    <logo-component></logo-component>
    <widgets-component>
        <quicksearch-component></quicksearch-component>
        <dropdown-component></dropdown-component>
    </widgets-component>
</header-component>

<video-listing-component>
    <video-item-component></video-item-component>
    ...
</video-listing-component>

Now, I have 2 options. Let's just take the <video-listing-component> for example, to keep this simple... I either
A) place the entire standard HTML tags which I already have (<div class="video-item"></div>) within the <video-item-component> tag, and once rendered will result in this:

<video-listing-component>
    <div class="video-listing>
        <video-item-component>
            <div class="video-item>...</div>
        </video-item-component>
        ...
        ...
    </div>
</video-listing-component>

OR:

B) Only put the content of <div class="video-item"> directly into my <video-item-component> component and adding the required class (class="video-item") for styling on the component tag, resulting in something like this:

<video-listing-component class="video-listing">
    <video-item-component class="video-item"></video-item-component>
    <video-item-component class="video-item"></video-item-component>
    ...
</video-listing-component>

Either way (A or B), the browser renders everything just fine.
BUT if you take a closer look (after everything is rendered in the DOM, of course), by default the custom tags don't occupy any space in the DOM. They're 0px by 0px. Only their content occupies space. I don't get it how come the browser still renders everything as you would want to see it, I mean in the first case (A):

While having float: left; width: 25%; on the div class="video-item", but each of these divs being within a <video-item-component> tag, which doesn't have any styling... Isn't it just a fortunate side-effect that the browser renders everything as you'd expect? With all the <div class="video-item"> floating next to each other, even though each of them are within another tag, the <video-item-component> which does NOT have float: left? I've tested on IE10+, Firefox, Chrome, all fine. Is it just fortunate or is there a solid explanation for this and we can safely rely for this kind of markup to be rendered as we'd expect by all (or at least most) browsers?

Second case (B):

If we use classes and styling directly on the custom tags (<video-item-component>)... again, everything shows up fine. But as far as I know, we shouldn't style custom components, right? Isn't this also just a fortunate expected outcome? Or is this fine also? I don't know, maybe I'm still living in 2009... am I?
Which of these 2 approaches (A or B) would be the recommended one? Or are both just fine?

I have no idea!!

Since my divs have float: left, that's why the (custom or not) tag they're wrapped in doesn't expand it's height. Seems I've forgotten how CSS works since I started to look over Angular 2.

But one thing still remains:

If I set a percentage width on a block element (call it E), I would assume it takes x% of it's immediate parent. If I set float: left, I would expect floating within the immediate parent. In my A case, since the immediate parent is a custom tag with no display type and no width, I would expect for things to break somehow, but still... my E elements behave like their parent isn't the custom tag they're each wrapped in, but the next one in the DOM (which is <div class="video-listing> in my case). And they occupy x% of that and they float within that. I don't expect this to be normal, I would think this is just a fortunate effect, and I'm afraid that one day, after some browser update... I'll wake up to find all my Angular 2 sites looking completely broken.

So... are both A and B an equally proper approach? Or am I doing it wrong in case A?

EDIT2:
Let's simplify things a bit. As I got part of my question answered, let's take another example of generated HTML (simplified a bit, with inlined CSS):

<footer>
    <angular-component-left>
        <div style="float: left; width: 50%;">
            DIV CONTENT
        </div>
    </angular-component-left>
    <angular-component-right>
        <div style="float: left; width: 50%;">
            DIV CONTENT
        </div>
    </angular-component-right>
</footer>

In the original, not yet implemented HTML (without <angular-component-...>, those divs should float left and each occupy 50% of the <footer>. Surprisingly, once they're wrapped in the <angular-component-...> custom tags, they do the same: occupy 50% of the footer. But this just seems like good fortune to me, dumb luck... Unintended effect.
So, is it or isn't it "dumb luck"?

Should I leave it like that, or rewrite so instead of the above code, I would have something like this:

<footer>
    <angular-component-left style="display: block; float: left; width: 50%;">
        DIV CONTENT
    </angular-component-left>
    <angular-component-right style="display: block; float: left; width: 50%;">
        DIV CONTENT
    </angular-component-right>
</footer>

Note that the inline styling is introduced here for simplicity, I would actually have a class instead which would be in an external CSS file included in the <head> of my document, not through style or styleUrls from my angular components.

Dictatorship answered 15/5, 2016 at 15:48 Comment(5)
I don't really understand what essential difference between A and B is supposed to demonstrate.Advocation
I'm simply asking which of A or B would be the proper way to do it. And if what happens in case A is as intended by the browser, or is it just fortunate. And one day I'd wake up and see that this unintended effect has been fixed across all browsers and my site looks broken. Also, I mostly do html/css. I can't wrap my head around custom-tags, not to mention styling them. In my opinion, they're simply unnatural. One of the first things most clients would do is paste any html I produce into a validator and say: look, I have warnings or errors. We need to fix those. And I DO have to fix those.Dictatorship
I'm not thinking from a developer's point of view here, but from the point of view of someone who implements design into html/css. I'm talking about the rendered result, not what happens in angular or behind the scenes.Dictatorship
I don't get what the diffetence is between A and B. Custom elements are normal HTML, it's just expanded only at runtime to the full HTML. It's easier this way to create reusable fragments and allows to get scoped styles, which is achieved by Angular rewriting the selectors of the CSS to only match unique attributes added to the elemens of a component (default) or by leveraging shadow DOM style scoping (with Native encapsulation mode).Advocation
You can think of <angular-component-left> as a <div> with a custom name. If <angular-component-left> is an Angular component, then the template specified in the component will be added to <angular-component-left> as innerHTML.Advocation
R
2

The issue is your HTML validator. The - in the element name is required for elements to be treated as custom elements and it is valid HTML5. Angular doesn't require - in element names but it's good practice.

Check for example https://www.w3.org/TR/custom-elements/#registering-custom-elements (search for x-foo) or https://w3c.github.io/webcomponents/spec/custom/#custom-elements-custom-tag-example. I'm sure this dash rule is specified somewhere but wasn't able to find the spec. It is for example required in Polymer that depends on elements being proper custom elements while this doesn't matter much in Angular. The only difference as far as I know is that when you query the element, you get a HTMLUnknownElement when the - is missing in the name and a HTMLElement when it contains a -.

See also this question I asked a few years ago Why does Angular not need a dash in component name

BUT if you take a closer look, by default the custom tags don't occupy any space in the dom. They're 0px by 0px. Only their content occupies space. I just don't get it how come the browser still renders everything as you would want to see it

I'm not sure I understand this question. When Angular processes the template it adds the content dynamically. When you see the content in the browser than it's also available in the DOM and has actual dimensions.

Search engine crawlers are able to process pages that are generated by JavaScript. If this isn't enough, server-side rendered pages can provide static HTML to crawlers that contain the whole view.

Relict answered 15/5, 2016 at 15:51 Comment(8)
>They're 0px by 0px I mean the custom tag is 0px by 0px in the browser's viewport, it doesn't visibly expand to it's content size, like a standard html tag. The only way to make it have a size is to explicitly give it a display type (block/inline-block) and width and height, I know. BUT, in case A, how come it simply works? Does the browser explicitly and completely ignore custom tags or is it just a fortunate side effect? Why are my divs still floating next to each other, when they're in fact each in another separate element that does NOT have float: left. Dumb luck or can we rely on it?Dictatorship
If display is not set to block then they behave like <span> elements. inline-block is the default display value AFAIR. There is nothing special. or magical going on with Angular components or custom elements. They behave like any other element with the same style settings (like the mentioned display). If you enable ViewEncapsulation.Native the components view is wrapped in a shadow DOM in browsers that already support it, but that's also nothing special as native elements like <input>, <video>, ... also have their view hidden in a shadow DOM.Advocation
It's probably what is explained here #9024994Advocation
D'oh! :) Thanks for that. I've edited my question and added a paragraph at the end.Dictatorship
I don't have such deep CSS knowledge. I can tell for sure though that Angular isn't doing anything special. It's just HTML elements with custom names added to the DOM by JavaScript. Some special things like bindings [attr.prop]="xxx" are resolved by Angular before it is added to the DOM. Such attributes are never added to the DOM as is.Advocation
And about SEO... Sure, google will crawl my site regardless of the tags I use. What I was thinking and probably what I should have explicitly asked (and I've updated the question for this) is: might custom tags affect ranking? Would the same site rank better if I only have standard html tags as opposed to having custom-make-believe-tags? Anyway, this would be more of a question for an SEO professional. Thank you for your time and for the help you've offered so far with my concerns.Dictatorship
@GünterZöchbauer So angular 2 creates HTML 5 custom elements ? Not every browser supports it natively yet, so I suppose they are using a polyfill for that ?Whimper
No, Angular2 doesn't create custom elements. The browsers that support custom elements recognize a - in the name and treat such elements a bit different. It's nit necessary to add - to the name and in practice it doesn't matter much if you do or not.Advocation

© 2022 - 2024 — McMap. All rights reserved.