angular: Components should create a `display:block` style by default

Let’s say I create a new component in Angular2 and I attempt to style it:

// hello_world_cmp.ts
@Component({
   selector: 'hello-world',
   styleUrls: ['hello-world.css']
   template: 'hello world!'
})
class HelloWorldCmp { }

// hello_world.css
:host { background: red; }

The styling fails to be applied for the sole reason that browsers have no clue what the <hello-world></hello-world> HTML element is. This is expected, but it’s tricky to debug for those of whom are new to Angular and to web components. This is also the case with predefined Angular components (like <router-outlet></router-outlet>).

Solution

I think it’s best if Angular keeps track of each of the components created in an application and builds a CSS selector which is placed at the HEAD of the index.html file within a style tag.

<head>
<style>
router-outlet, hello-world { display:block; }
<style>
</head>

Since the CSS selectors are tag selectors this means that they have the lowest specificity and the fact that the styles are placed at the top of the index.html document this then allows for ui-libraries and user-defined styles to easily override the styles without having to use a heavier selector (e.g. is a .class selector is used to match all components then a user style like hello-world would lose to that in the specificity battle).

We should also have a flag to disable this.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 27
  • Comments: 20 (8 by maintainers)

Most upvoted comments

@tbosch we can’t use element.style.display because that’s an inline style and inline styles have the highest specificity. So something like this would always require !important.

/* from the component itself */
:host { display:block!important; }

/* or from a parent component */
hello-world { display:block!important; }

@tbosch and @kasperpeulen The reason why we use display:block here is because almost all components that contain inner element data are block by default in HTML (think <div>, <p>). Even HTML5 elements like <section>, <footer>, <aside> are all block level (here’s proof: http://plnkr.co/edit/aaIVUpEhqrVx6NltvFya?p=preview). That being said, there’s a higher chance that the user expects this as the default and then overrides to support something like flex or inline.

This isn’t so much about the component author vs the template author, it’s more about allowing the user to skip an annoying step for every component created.

I would prefer that angular components just received a css class when compiled. for example: <my-component></my-component> would become: <my-component class="ng-component"></my-component>

Thus, the author could do a global style to default components to whatever they want:

<style>
.ng-component{  display:block; }  // all my components will be block by default.
....
my-inline-component.ng-component{ display:inline-block;  } // this one will be in-line.. etc...
</style>

This is the 1st result (or one of the firsts) in Google when searching about Angular components display block.

Maybe this link (to the Angular 2 Doc: Component Styles) which describes about styling the Component with display: block; using :host could be useful: https://angular.io/docs/ts/latest/guide/component-styles.html#!#-host

Update: Angular 4 doc link: https://angular.io/guide/component-styles#host

You can use host: { 'style': 'display: block' }. I had to do this to get routing animations to work.

I wonder if this shouldn’t be also the default for custom elements (as in the WC spec),

They discussed this and I understand the reasoning why they didn’t change the display property.

obsolete (would be a breaking change)

FWIW if you’re arriving here from google, Angular components using display: flex have a really bad interaction where if you don’t set display: block it seems to just be inherited into the children components forever and they all flex. More importantly, even though they will mostly display “OK”, half a dozen javascript properties will show height: 0 since they are not block, which messes up a lot of libraries probing for element width/height (it’s arguable whether this is a bug in the libraries or whatever, I’ll leave it at that).

You have to ‘tie the knot’ with display: block in your :host style for your children or use a solution provided from here. You don’t usually notice this because the display: block; on div usually takes higher precedence and does this automatically …

Another solution is to use :host > * { display: block; } but this can be messy depending on your content.

If it is an ng-content container use :host /deep/ > * (at time of writing, this was very recently deprecated but there is no replacement yet afaik).

Why would display: block by default be better than display:inline?

I don’t understand, why would not just style the host css using css yourself. As creator/designer of the web component, you would know best if it should be display: block or display: inline?