In several apps I work on, we use angular material to display data in a table. Sometimes, long text causes the height of the table cells to increase, resulting in an unaesthetic UI.
Using CSS, we can set the max width of the table cells, hide overflow and show ellipsis at the end of the overflowing text. When the user hovers over the long text, we can display the full content in a tooltip.
Below CSS snippet will instruct the browser to hide the overflow text and display with ellipsis.
table { // .... codes omitted for brevity td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 400px; padding: 0px 10px; } } }
In the above snippet, setting overflow to hidden and text-overflow to ellipsis allow the browser to replace the part of the text that cannot fit within the container with ellipsis. We set white-space to nowrap to collapse the whitespaces and avoid wrapping. Otherwise, the browser will break the text to another line as necessary, increasing the height of the table cells, which we don’t want.
In our app, we only want to display tooltip on table cells which contain overflowing text, not on all table cells. Below code snippets, which I took from this stackoverflow post, check when overflow occurs in an element.
// Determines if the passed element is overflowing its bounds, // either vertically or horizontally. // Will temporarily modify the "overflow" style to detect this // if necessary. // https://stackoverflow.com/questions/143815/determine-if-an-html-elements-content-overflows isOverflow(el: HTMLElement): boolean { var curOverflow = el.style.overflow; if (!curOverflow || curOverflow === "visible") el.style.overflow = "hidden"; var isOverflowing = el.clientWidth < el.scrollWidth || el.clientHeight < el.scrollHeight; el.style.overflow = curOverflow; return isOverflowing; }
In the html template, we can bind to the isOverflow method in the component to conditionally enable or disable the tooltip.
<div class="master-list-container"> <table matSort mat-table [dataSource]="data" class="mat-elevation-z8"> <ng-container *ngFor="let column of columns" [matColumnDef]="column"> <th mat-header-cell *matHeaderCellDef [mat-sort-header]="column"> {{getDisplayName(column)}} </th> <ng-container> <td mat-cell #tdElement [class.row-highlight]="element.id === currentElement?.id" [matTooltip]="element[column]" [matTooltipDisabled]="!isOverflow(tdElement)" matTooltipPosition="below" matTooltipClass="tooltip" *matCellDef="let element"> {{element[column]}} </td> </ng-container> <tr mat-header-row *matHeaderRowDef="columns"></tr> <tr mat-row *matRowDef="let row; columns: columns;"></tr> </table> <!-- codes omitted for brevity --> </div>
In the above snippet, notice how we bind the matTooltipDisabled property to the isOverflow function in the component. We also declare the template variable #tdElement to reference and pass the element as a parameter to the isOverflow function. We also customize the tooltip by specifying matTooltipClass.
.tooltip { font-size: 1em ; background-color: black; }
Note that I need to put the above css snippet in the global (styles.scss) style class. Either that, or I need to use ::ng-deep. Otherwise, the style does not have an effect. As you may know, ::ng-deep has become deprecated, so putting the code in the global stylesheet seems like a better way.
Below screenshot shows the result:
text-overflow – CSS: Cascading Style Sheets | MDN (mozilla.org)
white-space – CSS: Cascading Style Sheets | MDN (mozilla.org)
Determine if an HTML element’s content overflows
Cache angular components using RouteReuseStrategy
Using MSAL angular to authenticate a user against azure ADB2C via authorization code flow with Proof Key for Code Exchange.
Azure AD authentication in angular using MSAL angular v2 library
Common frameworks, libraries and design patterns I use
Rendering a PDF in angular that works with mobile browsers using ng2-pdf-viewer
Differences between a Promise and an Observable
Integrate Azure AD B2C reset password user flow in angular using oidc-client-js.
Integrate Azure AD B2C profile editing user flow in angular using oidc-client-js.