How to Style ng-bootstrap - Alternative to /deep/ - css

I am using the accordion component from ng-bootstrap in one of my apps and the /deep/ (aka: ::ng-deep and >>>) selector to set its styles. However I saw this selector has been deprecated.
Is there an alternative to set the styles of the ng-bootstrap components?

Support for the emulated /deep/ CSS Selector (the Shadow-Piercing
descendant combinator aka >>>) has been deprecated to match browser
implementations and Chrome’s intent to remove. ::ng-deep has been
added to provide a temporary workaround for developers currently using
this feature.
From here: http://angularjs.blogspot.com/2017/07/angular-43-now-available.html

I've done some digging and it is possible to overwrite the ng-bootstrap styles if you turn off the view encapsulation for a component, like so:
#Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ExampleComponent {
constructor(public activeModal: NgbActiveModal) { }
}
For example, here I am customizing the styles for a modal dialog, because I assumed that my example component should be shown as a modal dialog and I want its width to be at maximum 70% of the view port in small screen sizes:
.modal-dialog {
#include media-breakpoint-down(xs) {
max-width: 70vw;
margin: 10px auto;
}
}
Please note that turning off the view encapsulation means that the styles for this particular component will be available throughout the application, therefore other components will have access to them and will eventually use them if you are not careful.

You have to make custom styling to override the default bootstrap variable in scss.
You can find all possible variables here ../node_modules/bootstrap/scss/_variables.scss
Bootstrap also provide a custom file for us add our styling ../node_modules/bootstrap/scss/_custom.scss
for eg: here i am overriding two variable that effect my accordion (i changed some random colors)
$link-color:$brand-warning;
$card-bg:$green;
and dont forget to remove !default in _custom.scss and you done with the custom styling.
Now need to build the css from scss
First install npm install -g grunt-cli globally
then navigate to \my-app\node_modules\bootstrap> npm install, this will install all dependencies.
Lastly run \my-app\node_modules\bootstrap> grunt, this will creates the css file.
This should work hopefully.
In my case "bootstrap.min.css" was not generated correctly, so now iam using "../node_modules/bootstrap/dist/css/bootstrap.css " in my .angular-cli.json file.

Related

PrimeNg p-inputnumber cannot be styled

I am getting stuck trying to implement the PrimeNg Inputnumber element: https://www.primefaces.org/primeng/showcase/#/inputnumber
As per its documentation, there are a couple of attributes that can be used to style the input element, most notably styleClass and inputStyleClass. Unfortunately, neither of them work but rather they get completely ignored.
component.html:
<p-inputNumber
inputStyleClass="form-control-inputnumber" [(ngModel)]="subwinFld.orderAdd.doubleVal">
</p-inputNumber>
Global styles.css
.form-control-inputnumber {
background:red;
width: 100%;
}
I have used and successfully styled other primeNg elements before, using the exact same strategy, for example the p-calendar element. However, here it completely ignores the attribute.
What am I doing wrong?
Try to add :host ::ng-deep
Style are scoped, and there are not inherited by nesting.
:host ::ng-deep .form-control-inputnumber {
background:red;
width: 100%;
}
styleClass is the property that put the class on the first level of a PrimeNG Component.
inputStyleClass is the property that will put the class on the input itself for this specific component.
I often have to play with the style encapsulation with styleClass, so I believe it is the same for inputStyleClass
Word about ::ng-deep deprecation
Yes, for sure it is deprecated. To be totally fair, there is an alternative. But the alternative counterpart is huge and in my opinion, the big picture is worst.
You can make it work by changing your ViewEncapsulation in your component with :
encapsulation: ViewEncapsulation.None
as follow
#Component({
selector: '',
template: '',
styles: [''],
encapsulation: ViewEncapsulation.None // Use to disable CSS Encapsulation for this component
})
Reference 1 about alternatives and reasons of deprecation
Reference 2 about alternatives of ::ng-deep
The choice is yours, but for my part I continue to use this methodology with third party library like primeNG, because there is no real alternative.
You either choose to make your style global or your style scoped.
Kill the encapsulation for the sake of a third party library usage, seems to me an overkill process.
By making your ViewEncapsulation to none, you give up on style encapsulation, so beware of it.
HTML:
<p-inputNumber styleClass="input-styling"></p-inputNumber>
CSS:
::ng-deep .input-styling input {
width: 20px !important;
}
The cause for the missing styling was a runtime error in the typescript of the component, that prevented the correct compilation of the DOM.
I assumed that did not matter, since they should not be related at all, but they are (somehow). Since others may have the same erroneous assumption, I am leaving this question here, rather than deleting it.
Simply add
styleClass="w-full" to p-inputNumber tag to adjust 100% width or according style to reach desired width in reference to https://www.primefaces.org/primeflex/width
No encapsulation: ViewEncapsulation.None is needed and no extra css classes/styling is required.

Override Angular Material CSS differently in different components

I have two components with tab groups in them. One is a main page and I have overwritten the css to make the labels larger, done using ViewEncapsulation.None. The other is a dialog, and I want to keep it small but still apply some other custom styles to it.
When I open the dialog after visiting the other tabs page, it copies all the styles, which I have figured is because ViewEncapsulation.None bleeds CSS but not exactly as expected.
Is there anyway to override Angular Material styles without changing ViewEncapsulation so that I can keep the two components separate?
Solution 1: you can put all elements of your component into a parent element with a css class and override the material style into it.(it's custom capsulation)
Note: ViewEncapsulation is none here.
component.html
<div class="my-component__container">
<!-- other elements(material) are here -->
</div>
component.scss
.my-component__container{
// override material styles here
.mat-form-field{...}
}
Solution 2: use /deep/(deprecated).(use ::ng-depp insteaded)
:host /deep/ .mat-form-field {
text-align: left !important;
}
Solution 3: don't change ViewEncapsulation , then:
:host {
.my-component__container{}
}
if you would like to customise your Angular material components and provide your own stylings, I have the following suggestions. You may use one of them.
1) Overwrite the classes on your main style.css (or style.scss, whichever you are using). If you are wondering, it is the one that is on the same directory level as your index.html, main.ts, package.json, etc. You might need to add the !important declaration.
For instance,
.mat-form-field-label {
color:blue!important;
}
2) Customising the various Angular Material directive (such as MatPlaceholder) by providing a custom class.
For instance, when we use the MatPlaceHolder, and on the component.html template,
<mat-placeholder class="placeholder">Search</mat-placeholder>
On your component.css, we can then supply the css properties to the placehodler class
.placeholder {
color: green
}
Note:
Alternatively you may use ::ng-deep, but I would strongly suggest using ::ng-deep as it will soon be deprecated.
::ng-deep .mat-dialog {
/* styles here */
/* try not to use ::ng-deep */
}
You can use ::ng-deep. Refer NgDeep

Angular 2 no unique component identifier generated for select arrow div

I'm trying to remove the arrow from an angular material select component.
To do that I have a custom CSS file where I say display: none.
Here is the code:
https://stackblitz.com/edit/angular2-remove-select-arrow
but as my CSS is custom for this component, I saw there's no unique identifier generated for the arrow div so CSS is not applied.
Can you please let me know what would be the best way to do achieve that?
Thanks for your help.
Mike
When you state the styles in a component's CSS file, custom attributes are added to it automatically, so that CSS is not applied outside of the current component. But that causes issues when you want to apply CSS to other components, in this case, mat-select.
There are two ways to solve this issue
Set encapsulation to none in component
#Component({
selector: 'select-form-example',
templateUrl: 'select-form-example.html',
styleUrls: ['select-form-example.css'],
encapsulation: ViewEncapsulation.None,
})
export class SelectFormExample {
}
Add the custom styles in style.css file instead of the component's CSS file
select-form-example.css
I have updated the stackblitz with 1st step
Use ::ng-deep in your case but note that this one is already deprecated.
Now your css rule becomes like this: ::ng-deep .staffing-cell .mat-select-arrow-wrapper
Deprecation info: https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep
Now for the "appropriate" way you need to leverage the material theming in which you can look up in their docs: https://material.angular.io/guide/theming

How and where to use ::ng-deep?

How and where can one use ::ng-deep in Angular 4?
Actually I want to overwrite some of the CSS properties of the child components from the parent components. Moreover is it supported on IE11?
Usually /deep/ “shadow-piercing” combinator can be used to force a style down to child components. This selector had an alias >>> and now has another one called ::ng-deep.
since /deep/ combinator has been deprecated, it is recommended to use ::ng-deep
For example:
<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>
and css
.overview {
::ng-deep {
p {
&:last-child {
margin-bottom: 0;
}
}
}
}
it will be applied to child components
I would emphasize the importance of limiting the ::ng-deep to only children of a component by requiring the parent to be an encapsulated css class.
For this to work it's important to use the ::ng-deep after the parent, not before otherwise it would apply to all the classes with the same name the moment the component is loaded.
Using the :host keyword before ::ng-deep will handle this automatically:
:host ::ng-deep .mat-checkbox-layout
Alternatively you can achieve the same behavior by adding a component scoped CSS class before the ::ng-deep keyword:
.my-component ::ng-deep .mat-checkbox-layout {
background-color: aqua;
}
Component template:
<h1 class="my-component">
<mat-checkbox ....></mat-checkbox>
</h1>
Resulting (Angular generated) css will then include the uniquely generated name and apply only to its own component instance:
.my-component[_ngcontent-c1] .mat-checkbox-layout {
background-color: aqua;
}
USAGE
::ng-deep, >>> and /deep/ disable view encapsulation for specific CSS rules, in other words, it gives you access to DOM elements, which are not in your component's HTML. For example, if you're using Angular Material (or any other third-party library like this), some generated elements are outside of your component's area (such as dialog) and you can't access those elements directly or using a regular CSS way. If you want to change the styles of those elements, you can use one of those three things, for example:
::ng-deep .mat-dialog {
/* styles here */
}
For now Angular team recommends making "deep" manipulations only with EMULATED view encapsulation.
DEPRECATION
"deep" manipulations are actually deprecated too, BUT it's still working for now, because Angular does pre-processing support (don't rush to refuse ::ng-deep today, take a look at deprecation practices first).
Anyway, before following this way, I recommend you to take a look at disabling view encapsulation approach (which is not ideal too, it allows your styles to leak into other components), but in some cases, it's a better way. If you decided to disable view encapsulation, it's strongly recommended to use specific classes to avoid CSS rules intersection, and finally, avoid a mess in your stylesheets. It's really easy to disable right in the component's .ts file:
#Component({
selector: '',
template: '',
styles: [''],
encapsulation: ViewEncapsulation.None // Use to disable CSS Encapsulation for this component
})
You can find more info about the view encapsulation in this article.
Make sure not to miss the explanation of :host-context which is directly above ::ng-deep in the angular guide : https://angular.io/guide/component-styles. I missed it up until now and wish I'd seen it sooner.
::ng-deep is often necessary when you didn't write the component and don't have access to its source, but :host-context can be a very useful option when you do.
For example I have a black <h1> header inside a component I designed, and I want the ability to change it to white when it's displayed on a dark themed background.
If I didn't have access to the source I may have to do this in the css for the parent:
.theme-dark widget-box ::ng-deep h1 { color: white; }
But instead with :host-context you can do this inside the component.
h1
{
color: black; // default color
:host-context(.theme-dark) &
{
color: white; // color for dark-theme
}
// OR set an attribute 'outside' with [attr.theme]="'dark'"
:host-context([theme='dark']) &
{
color: white; // color for dark-theme
}
}
This will look anywhere in the component chain for .theme-dark and apply the css to the h1 if found. This is a good alternative to relying too much on ::ng-deep which while often necessary is somewhat of an anti-pattern.
In this case the & is replaced by the h1 (that's how sass/scss works) so you can define your 'normal' and themed/alternative css right next to each other which is very handy.
Be careful to get the correct number of :. For ::ng-deep there are two and for :host-context only one.
Just an update:
You should use ::ng-deep instead of /deep/ which seems to be deprecated.
Per documentation:
The shadow-piercing descendant combinator is deprecated and support is
being removed from major browsers and tools. As such we plan to drop
support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until
then ::ng-deep should be preferred for a broader compatibility with
the tools.
You can find it here
I looked through all those answers and found nobody mentioned a child component can pass a style CSS in from its parent.
In component ts file, you can use this:
#Input() styles: any = {};
In component html file, you use this:
[ngStyle]="styles"
in parent, you use this :
<yourComponent [styles]="{backgroundColor: 'blue', 'font-size': '16px'}">
Please see more details here: Best way to pass styling to a component
In this way, we didn't break encapsulation, which is one of those most important Object orientation principles
Use ::ng-deep with caution. I used it throughout my app to set the material design toolbar color to different colors throughout my app only to find that when the app was in testing the toolbar colors step on each other. Come to find out it is because these styles becomes global, see this article Here is a working code solution that doesn't bleed into other components.
<mat-toolbar #subbar>
...
</mat-toolbar>
export class BypartSubBarComponent implements AfterViewInit {
#ViewChild('subbar', { static: false }) subbar: MatToolbar;
constructor(
private renderer: Renderer2) { }
ngAfterViewInit() {
this.renderer.setStyle(
this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
}
}

Angular-cli build generated CSS not working

I have an angular-cli app and using webpack.
When I try to run it the component specific css doesn't work
styles.css
/* You can add global styles to this file, and also import other style files*/
#import 'http://something/v4/dist/css/bootstrap.min.css';
Component
#Component({
selector: 'app-carousel',
templateUrl: './carousel.component.html',
styleUrls: ['./carousel.component.css']
})
export class CarouselComponent implements OnInit {
Component CSS
.carousel-indicators { display: none; }
angular-cli.config
"styles": [
"styles.css",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-bold.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-light.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-regular.scss"
],
The rendered html
<style type="text/css">#import url(http://something/v4/dist/css/bootstrap.min.css);</style>
<style type="text/css">/* You can add global styles to this file, and also import other style files */
</style><style></style><style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
but this is not applied to my html element 'carousel-indicators'
If I import the carousel.component.cssinto the styles.css then it works but it appears twice in the generated html
I'm looking for the right way of doing this
By default(as in your case) angular using ViewEncapsulation.Emulated that scopes your css. However there is 3 view encapsulation options in Angular:
Native view encapsulation uses the browser's native shadow DOM implementation (see Shadow DOM on the MDN site) to attach a shadow DOM to the component's host element, and then puts the component view inside that shadow DOM. The component's styles are included within the shadow DOM.
Emulated view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing (and renaming) the CSS code to effectively scope the CSS to the component's view. For details, see Appendix 1.
None means that Angular does no view encapsulation. Angular adds the CSS to the global styles. The scoping rules, isolations, and protections discussed earlier don't apply. This is essentially the same as pasting the component's styles into the HTML.
So when you applying any styles to your component in component.css(with default ViewEncapsulation.Emulated) the styles will be applied just for that particular component, it won't be leaked outside the component and always have a priority above the global styles unless global style has !important.
So as a result you have the style in the head of your html file like:
<style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
If you referencing your component.css in styles.css then it will became a global style rendered in html head like so:
<style type="text/css">/* You can add global styles to this file, and also import other style files */
.carousel-indicators {
display: none; }
</style>
As you declared you style in competent and then referenced your component.css in styles.css that competent styles just gets doubled in your html: one copy is a global style and other copy is scoped component styles.
I was tried to replicate you issue but my compentnt.css is always gets applied. I am using the latest stable angular cli 1.3.2. If you are using older cli try to update. Otherwise push your code on github or create a plunker so I can take a look.
UPDATE: You might have your custom css gets overridden by some of your global stylesheets you are referencing. You can use chrome dev tools to debug the styles also you can try to put !important to your custom css and see if it does help.
For everybody landing here :
The issue was with the ViewEncapsulation.Emulated I changed it to ViewEncapsulation.None as describe in this stackoverflow answer :
how to hide ngb-carousel indicators and prev-next control
Thanks for your help

Resources