How do style a specific angular material component? - angular-material

I'm using angular material 2, but I think this also applies to angular material 1.
Let's say I want to use the angular material tabs, but I want to hide the tabs or add some specific styling to it.
So I have the following html/angular material code:
<md-tab-group>
<md-tab>
<template md-tab-label> <--- I want to style or hide all these. e.g. "height: 0"
Some tab
</template>
<template md-tab-content>
Some content. Perhaps other tab components.
</template>
</md-tab>
<md-tab>
<template md-tab-label> <--- I want to style or hide all these. e.g. "height: 0"
Some tab
</template>
<template md-tab-content>
Some content. Perhaps other tab components.
</template>
</md-tab>
</md-tab-group>
If I add a class to the "template md-tab-label"-tag it isn't added anywhere in the DOM structure.
I can't just style the "md-tab-label"-class because that would apply the style everywhere and to all tabs.
If I scope it from a parent element, it would apply to all nested tab components, that might be present in the tab content.
If I try limiting the depth and create a really really specific selector based on the final DOM representation, I would be applying a style on a structure that I have no control over and which could change at any update.
Is there a right way to do this or do I just have to create a selector by deconstructing the DOM structure?

You can override material styling from your scss/css. Like this:
/deep/ .mat-tab-group.mat-primary .mat-ink-bar{
background-color: red;
}
Due to view encapsulation, you need to use /deep/ selector that will allow you to get hold of the Material class added when the component is rendered.

I would recommend to avoid /deep/, >>>, and ::ng-deep, because it is going to be depreciated. (And it does not look so clean)
As a solution i would deactivate view encapsulation on a component level.
#Component({ ​
selector: 'app-card-list', ​
templateUrl: './card-list.component.html', ​
styleUrls: ['./card-list.component.scss'], ​
encapsulation: ViewEncapsulation.None​
})
After that i would create a surrounding div with scss for the angular material component.
.surrounding-div { ​
.mat-dialog { ​
display: flex; ​
flex-direction: row; ​
...​
} ​
}
This is my favourite approach to style Angular Material Components. Have fun!

If you want to do it using CSS then you need to add a panelClass, this will allow you to specify the options that you want to modify.
<md-tab panelClass="test-class">
...
</md-tab>
::ng-deep .test-class .md-tab-label {
height: 0 !important;
}
to avoid using ::ng-deep you can place the CSS rules in the styles.css file at the root

Related

Is there any way to use composition to alter the CSS of an web-component with a shadow dom?

my team lead has decided to use LitElement to create framework-agnostic web components, which makes sense, as we're creating a company-wide UI library that would be ideal to be used with Vue2, Vue3, React, Preact, and others.
However, I'm extremely worried about styling. Right now with our current (Vue 2) based UI library, if one of our teams needs to override the internal styling of an element for whatever reason (usually edge cases), one of the things they can do is use CSS Composition in order to do exactly that. Something like:
// in components/my-element.js
class MyElement extends LitElement {
render(){
return html`
<div class="stackui-my-element">
<p class="paragraph">A paragraph</p>
</div>
`;
}
}
customElements.define('my-element', MyElement);
// in app/businessthing.js
import React from 'react';
import {css} from 'styled-components'
const customCSS = css`
.this-thing {
& .stackui-my-element .paragraph {
border: 2px dotted pink;
}
}
`
export default (props) => <div class="this-thing"><my-element /></div>
As far as I can tell, the above code won't work ("My Paragraph" would not be surrounded with pink polka dots) because MyElement has its own shadow dom, and you can't reach in it from without to change the styles of the element.
Is there some sort of exception to the rule, or can you reach inside the shadow dom somehow? Other than losing CSS encapsulation, what are the other effects of disabling the shadow dom?
As you mention, when using Shadow DOM, style encapsulation would prevent users of the component from affecting the styling of the component's internals.
However, there are several ways to achieve what you want with different degrees of flexibility, all of them are part of how the Shadow DOM spec behaves and not Lit-specific, so, you could use this with Vanilla Web Components or components created with other libraries too.
Which of the following ways works better will depend on how strict you want to enforce styling rules for your component.
All the samples below will assume the internal DOM of the component looks like your sample
<div class="stackui-my-element">
<p class="paragraph">A paragraph</p>
</div>
Use custom CSS properties (CSS variables)
This approach is good when you want to limit the customization to only specific parts.
For example, to allow for the user to only be able to change the border for the paragraph, you could use a CSS variable with a fallback for the border in the style for your component's shadow DOM like this:
.paragraph {
border: var(--myel-paragraph-border, 1px solid black);
}
And then, users who wish to customize said border could just change the value for that CSS variable through inline styles or a class.
<style>
.fancy-border {
--myel-paragraph-border: 2px dotted pink;
}
</style>
<my-element class="fancy-border"></my-element>
The biggest limitation of this approach is that you would need to add a CSS variable for every property you wish to allow to be customized.
However, this can be an advantage for some use cases (like say, strict design systems) because it will not allow users to customize anything you don't wish to customize.
Use Shadow Parts
Shadow parts are one of the newer parts of the shadow DOM spec but browser support is pretty good by this point. They allow you to define arbitrary parts of your component you wish to be fully customizable from outside the shadow DOM.
To use them, you need to add the part attribute to the HTML node you wish to define as the part.
<div class="stackui-my-element">
<p part="paragraph" class="paragraph">A paragraph</p>
</div>
And when using the component, add the ::part() selector to the styles so that you can customize that specific part rather than the component host. It works pretty similar to how you would styles things such as a native input placeholder and so on.
<style>
.fancy::part(paragraph) {
/* you can do whatever you want here */
border: 2px dotted pink;
color: blue;
font-style: italic;
}
</style>
<my-element class="fancy"></my-element>
As you can see, shadow parts will allow you to override every style applied to the node, so, you must be careful when to use them as users might end up being able to customize things you don't want them too.
Final notes:
You could also achieve a similar thing using slots, but that might not be an easy change considering the contents of your question.
Here's an article in case you want more info on how styling Shadow DOM from outside the component works. (Disclaimer: I'm the author of that article.)

Angular material mat menu styling issue

I have two components that using mat menu. I just want to add some extra styling for one mat menu in one component. I have used this css inside the component css
::ng-deep.mat-menu-panel
{
position: fixed !important;
right : 2%;
}
Now the issue is the css is applying to the other component mat menu also.
How can i resolve this?
Add your panel styling to your global style sheet:
.fixed-menu-panel
{
position: fixed !important;
right : 2%;
}
Add the panel style to the mat-menu:
<mat-menu class="fixed-menu-panel">
StackBlitz: https://stackblitz.com/edit/angular-9bheaf?file=index.html
The challenge is that the menu is rendered in an overlay container attached to the parent document and not the button itself... with this in mind, you will need to think about how to grab a reference to that mat-menu-panel and append a class to it to make it unique on menu open.
For example, you could do something like the following to accomplish this.
Create a component method that will receive the templateRef as an argument. It will get the mat-menu-panel using Renderer2 and append a class to it of styled
styleMenu(el) {
const menuPanel = this.ren.parentNode(this.ren.parentNode(el.items.first['_elementRef'].nativeElement));
this.ren.addClass(menuPanel, 'styled')
}
Then in your view, use the (menuOpened) event emitter to call the styleMenu method when the menu opens, and pass the #styledMenu templateRef as an argument.
<button mat-button [matMenuTriggerFor]="styledMenu" (menuOpened)="styleMenu(styledMenu)">styled</button>
<mat-menu #styledMenu="matMenu">
Then your CSS will look like this
::ng-deep .mat-menu-panel.styled
{
position: fixed !important;
right : 2%;
}
This is one approach, you could also roll all of this into a directive and then just apply the directive selector where you need it.
Stackblitz
https://stackblitz.com/edit/angular-5nixtl?embed=1&file=app/menu-overview-example.ts

Angular Material: Change Background color of tabs when clicked/active

I want to remove the background-color effect applying when clicked on tab in angular material:
Here is the link of md-tabs
When I click on the tab, I can see a background-color is applying to the div element:
Here is the screenshot
I tried to over-ride the style with the following code, but not taking into effect:
.md-ripple-container:active{
background-color: none; !important
}
Help!!
Just use the .md-tab.md-active class in css. see the below example.
http://codepen.io/next1/pen/JXbVQN
You can override material styling from your scss/css. Like this:
/deep/ .mat-tab-group.mat-primary mat-tab-label-active{
background-color: red;
}
Due to view encapsulation, you need to use /deep/ selector that will allow you to get hold of the Material class added when the component is rendered.

Add text-transform: none and font-weight :bold styles to <md-buttons> in angular materials design without inline css

I am working on a project that is using angular materials design and I wanted to add certain styles to without using inline css but could not figure out the best way to do same.
Please note I tried adding a class with those styles but it was by default picking styles from .md-button class and was not picking the Css class I added
CSS class
.button__style {
text-transform :none;
font-weight :bold;
}
HTML
<md-button class='button__style'>Click me </md-button>
Also I know we can manipulate the default theme colors as below but wanted to find out if I am missing a way to add the two styles I require above i.e. text-transform : none and font-weight :bold;
angular.module('myApp', ['ngMaterial'])
.config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('pink')
.accentPalette('orange');
});
Your HTML
<div class='button__style'>
<md-button >Click me </md-button>
</div>
In your CSS :
.button__style {
button {
text-transform: none;
font-weight :bold;
//or any style you want to apply
}
}
Try this.
Code pen example for your problem

jQuery UI theming within datatables plugin

I'm using the jquery datatables plugin and added some custom jquery-ui buttons to the table footer.
To use the datatables plugin with jquery-ui theming the "bJQueryUI" option has to be turned on.
So far no problem, but now I added the jquery-ui themeroller to my page.
When I change the theme, all the jquery-ui components change their style accordingly, just like the datatable, except for the buttons within the datatable.
I found out that it actually is a css-priority issue: the new styles applied by the themeroller got lower priority than the original styles, so these buttons never change their look.
As the jquery-ui components and the datatables plugin both are quite popular I thought I would find someone with similar problems, but had no luck so far..
That's how the initialization of the datatable and the creation of the custom buttons are done:
<table id="DataTable">
// ...
</table>
<script type="text/javascript">
$(function ()
{
var oDataTable = $('#DataTable').dataTable({
"aaData": result.aaData,
"bPaginate": false,
"bJQueryUI": true,
"bInfo": true,
"sDom": '<"fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix"lfr>t<"fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"ipT<"toolbar">>',
"oTableTools":
{
"sRowSelect": "single"
}
});
// add buttons
$("div.toolbar").html('<button id="AddButton">New element</button>');
$("#AddButton").button().click(function () { /* ... */ });
// add more buttons...
}
</script>
Here's a screenshot of the actual html structure and applied css-styles:
http://i.stack.imgur.com/vbAuy.jpg
Any hint is greatly appreciated.
I found the solution myself:
If I add the "ui-widget-content" CSS-class to the toolbar-container div, the styles get applied correctly.
To remove the styles which that class applies (border and background), I added a more specific CSS style to remove these:
div.toolbar
{
float: right;
border: 0;
background: 0;
}
It's important here to use "div.toolbar" not ".toolbar", otherwise the ui-widget-content styles get applied.
Now the toolbar container doesnt get unwanted styles applied and the buttons inside correctly get the selected theme.
Maybe that's helpful for someone using the themeroller with custom jquery-ui buttons in datatables.
IF you want the theme to control the style of the button, then comment out the CSS that is overriding the theme roller style.
If they are themed buttons, then you will have to remove your CSS to allow the theme to take affect. Themes are made to be easily over-writable so you can add customization, only it sounds like you no longer want the customization.
Not sure if you had this problem but there are two separate css classes with datatables. Which one to use depends on if you have bJQueryUI:true or bJQueryUI:false

Resources