168

Here in my mat-table have 6 column when any column has not more words then it looks like Image-1, but when any column has more words then UI looks like Image-2, so how to set UI like Image-1 when any column has more words in angular 6 ?

Image-1

enter image description here

Image-2

enter image description here

user.component.html

<div class="mat-elevation-z8">      
 <table mat-table [dataSource]="dataSource">
  <ng-container matColumnDef="userimage">
    <th mat-header-cell *matHeaderCellDef> # </th>
    <td mat-cell *matCellDef="let element"> 
      <img src="{{commonUrlObj.commonUrl}}/images/{{element.userimage}}" style="height: 40px;width: 40px;"/>
    </td>
  </ng-container>

  <ng-container matColumnDef="username">
    <th mat-header-cell *matHeaderCellDef> Full Name </th>
    <td mat-cell *matCellDef="let element"> {{element.username}} ( {{element.usertype}} )</td>
  </ng-container>

  <ng-container matColumnDef="emailid">
    <th mat-header-cell *matHeaderCellDef> EmailId </th>
    <td mat-cell *matCellDef="let element"> {{element.emailid}} </td>
   </ng-container>

  <ng-container matColumnDef="contactno">
    <th mat-header-cell *matHeaderCellDef> Contact No. </th>
    <td mat-cell *matCellDef="let element"> {{element.contactno}} </td>
  </ng-container>

  <ng-container matColumnDef="enabled">
    <th mat-header-cell *matHeaderCellDef> Enabled </th>
    <td mat-cell *matCellDef="let element" style="color: blue">
      <ng-container *ngIf="element.enabled == 'true'; else otherss">Enabled</ng-container>
        <ng-template #otherss>Disabled</ng-template>
    </td>
  </ng-container>

  <ng-container matColumnDef="action">
    <th mat-header-cell *matHeaderCellDef> Action </th>
      <td mat-cell *matCellDef="let element" fxLayoutGap="5px">
        <button mat-mini-fab color="primary" routerLink="/base/editUserDetails/{{element.userid}}"><mat-icon>edit</mat-icon></button>
        <button mat-mini-fab color="primary" routerLink="/base/viewUserDetails/{{element.userid}}"><mat-icon>pageview</mat-icon></button>
      </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20, 50 ,100]" showFirstLastButtons></mat-paginator>

Dharmesh
  • 5,383
  • 17
  • 46
  • 62

16 Answers16

173

using css we can adjust specific column width which i put in below code.

user.component.css

table{
 width: 100%;
}

.mat-column-username {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 28% !important;
  width: 28% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;

  word-break: break-word;

  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.mat-column-emailid {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 25% !important;
  width: 25% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;

  word-break: break-word;

  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.mat-column-contactno {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 17% !important;
  width: 17% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;

  word-break: break-word;

  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.mat-column-userimage {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 8% !important;
  width: 8% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;

  word-break: break-word;

  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.mat-column-userActivity {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 10% !important;
  width: 10% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;

  word-break: break-word;

  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}
Dharmesh
  • 5,383
  • 17
  • 46
  • 62
138

As i have implemented, and it is working fine. you just need to add column width using matColumnDef="description"

for example :

<mat-table #table [dataSource]="dataSource" matSortDisableClear>
    <ng-container matColumnDef="productId">
        <mat-header-cell *matHeaderCellDef>product ID</mat-header-cell>
        <mat-cell *matCellDef="let product">{{product.id}}</mat-cell>
    </ng-container>
    <ng-container matColumnDef="productName">
        <mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
        <mat-cell *matCellDef="let product">{{product.name}}</mat-cell>
    </ng-container>
    <ng-container matColumnDef="actions">
        <mat-header-cell *matHeaderCellDef>Actions</mat-header-cell>
        <mat-cell *matCellDef="let product">
            <button (click)="view(product)">
                <mat-icon>visibility</mat-icon>
            </button>
        </mat-cell>
    </ng-container>
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

here matColumnDef is productId, productName and action

now we apply width by matColumnDef

styling

.mat-column-productId {
    flex: 0 0 10%;
}
.mat-column-productName {
    flex: 0 0 50%;
}

and remaining width is equally allocated to other columns

Sandeep Patel
  • 2,069
  • 2
  • 14
  • 20
91

If you're using scss for your styles you can use a mixin to help generate the code. Your styles will quickly get out of hand if you put all the properties every time.

This is a very simple example - really nothing more than a proof of concept, you can extend this with multiple properties and rules as needed.

    @mixin mat-table-columns($columns)
    {
        .mat-column-
        {
            @each $colName, $props in $columns {
    
                $width: map-get($props, 'width');
                
                &#{$colName} 
                {
                    flex: $width;
                    min-width: $width;
    
                    @if map-has-key($props, 'color') 
                    {
                        color: map-get($props, 'color');
                    }
                }  
            }
        }
    }

Then in your component where your table is defined you just do this:

    @include mat-table-columns((
    
        orderid: (width: 6rem, color: gray),
        date: (width: 9rem),
        items: (width: 20rem)
    
    ));

This generates something like this:

    .mat-column-orderid[_ngcontent-c15] {
      flex: 6rem;
      min-width: 6rem;
      color: gray; }
    
    .mat-column-date[_ngcontent-c15] {
      flex: 9rem;
      min-width: 9rem; }

In this version width becomes flex: value; min-width: value.

For your specific example you could add wrap: true or something like that as a new parameter.

TmTron
  • 17,012
  • 10
  • 94
  • 142
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • About time someone upvoted me for this :-) I've found this way very helpful - and you can extend it all you please as needed to be more consistent across components. – Simon_Weaver Jul 18 '19 at 07:58
  • 2
    Note: You can of course use pixels if you prefer. I generally prefer ems when text data is involved, and I'm using rems here because when the header and cell font size is different they'll be skewed since by definition 'em' vary by font size. – Simon_Weaver Sep 05 '19 at 22:23
  • 2
    This look super spiffy, but I'm unclear on where to put the mixin... – Gus Aug 22 '20 at 20:25
  • 1
    how to import `$columns` in mat-table ?? – Sridhar Natuva Oct 14 '20 at 13:24
  • @SridharNatuva you don't import $columns, that's just a variable name in the defined mixin (look up sass mixins). When you use the mixin with @include that's where you put the value for $columns (in my example above `@include mat-table-columns((` the second parenthesis is beginning of the the value of $columns which is a sass data structure representing each named column) – Simon_Weaver Feb 01 '21 at 22:32
72

You can easily do this one. In each column you will get a class with the field name prefixed with mat-column, so the class will be like mat-column-yourFieldName. So for that you can set the style like following

.mat-column-yourFieldName {
    flex: none;
    width: 100px;
}

So we can give fixed width for column as per our requirement.

Hope this helps for someone.

Kiran Shetty
  • 844
  • 7
  • 10
  • 1
    It worked for me, thank you. what if I wanted to avoid to repeat `flex: none;` for each colum? let's say a class `.mat-column-* { flex: none; }` i tried but it did not work. – OJVM Sep 02 '21 at 16:31
  • @OJVM try using this syntax to target all columns in you scss. `td, th { &[class*=" mat-column-"] { flex: none; } }` – Vardhan Jan 31 '22 at 03:54
38

You can do it by using below CSS:

table {
  width: 100%;
  table-layout: fixed;
}

th, td {
  overflow: hidden;
  width: 200px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Here is a StackBlitz Example with Sample Data

Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84
  • 11
    It's about `mat-table` not `table[mat-table]`. This does not work for `mat-table` (flex). https://material.angular.io/components/table/overview – Domske Mar 12 '20 at 18:43
  • not sure they say this does not work with mat-table, I have a mat table, set this code and works perfectly. – Yogurtu Jan 06 '22 at 23:51
15

Here's an alternative way of tackling the problem:

Instead of trying to "fix it in post" why don't you truncate the description before the table needs to try and fit it into its columns? I did it like this:

<ng-container matColumnDef="description">
   <th mat-header-cell *matHeaderCellDef> {{ 'Parts.description' | translate }} </th>
            <td mat-cell *matCellDef="let element">
                {{(element.description.length > 80) ? ((element.description).slice(0, 80) + '...') : element.description}}
   </td>
</ng-container>

So I first check if the array is bigger than a certain length, if Yes then truncate and add '...' otherwise pass the value as is. This enables us to still benefit from the auto-spacing the table does :)

enter image description here

Tomislav Stankovic
  • 3,080
  • 17
  • 35
  • 42
Nelis Brink
  • 149
  • 1
  • 5
  • Best solution for me as I wanted to truncate data as well. In other solutions if u just provide the width of column the row height gets enlarged as data grows beyond the width – learner May 11 '20 at 22:08
12

we can add attribute width directly to th

eg:

<ng-container matColumnDef="position" >
    <th mat-header-cell *matHeaderCellDef width ="20%"> No. </th>
    <td mat-cell *matCellDef="let element"> {{element.position}} </td>
  </ng-container>
rakesh
  • 159
  • 1
  • 3
6

Just need to update the width of the th tag.

th {
  width: 100px;
}
Yasser Nascimento
  • 1,302
  • 7
  • 13
4

enter image description hereI had a table with four columns. Please see the screenshot. In the scss file I had include below code:

.full-width-table {
  width: 100%;
}
.mat-column-id {
  width: 15% !important;
}
.mat-column-question {
  width: 55% !important;
}
.mat-column-view {
  width: 15% !important;
}
.mat-column-reply {
  width: 15% !important;
}
3

You can use fixedLayout="true" attribute like <table #table mat-table [dataSource]="dataSource" fixedLayout="true">

fixedLayout : Whether to use a fixed table layout. Enabling this option will enforce consistent column widths and optimize rendering sticky styles for native tables. No-op for flex tables.

3

In case you want to give a fixed width to a particular column you can add fxFlex="60px" both to mat-cell and mat-header-cell.

Ish
  • 384
  • 4
  • 10
  • This is a great solution when you cannot use css because you don't know the names of the columns. – Faliorn Aug 23 '22 at 09:41
3

Below Css Class worked in Angular 13.2.3

.width-textArea {  
     width: 150px;  
     max-width: 150px;  
     word-wrap: break-word;
}

Class needed to be specified in both <th and <Td

 <ng-container matColumnDef="comments">
          <th class="width-textArea" mat-header-cell *matHeaderCellDef mat-sort-header class="TableHeaderRow">Comments</th>
          <td class="width-textArea" mat-cell *matCellDef="let element"> {{element.comments}} </td>
        </ng-container>
rajquest
  • 535
  • 1
  • 5
  • 10
1

Just add style="width:5% !important;" to th and td

  <ng-container matColumnDef="username">
    <th style="width:5% !important;" mat-header-cell *matHeaderCellDef> Full Name </th>
    <td style="width:5% !important;" mat-cell *matCellDef="let element"> {{element.username}} ( {{element.usertype}} )</td>
  </ng-container>
Kad
  • 542
  • 1
  • 5
  • 18
0

As mentioned, you can use the CSS selector mat-column-[matColumnDef]. However, if you want to apply CSS to all columns you can use a wildcard attribute selector:

[class*="mat-column-"] {
    //your styles here
}

This is helpful if you want to apply common styling. Just note that you must use a wildcard and not a caret "^" character (begins with) since there are multiple classes assigned to the class attribute. This also will apply to any element with a class containing "mat-column-".

Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors

OliviaLynn
  • 123
  • 7
0

Just do it like this in global css add

table {
  width: 100%;
}

and in your user.component.css file you add

.mat-column-<your-column-name> {
   word-break: break-word;
   width: <width-u-need>% !important;
}

works like a charm

Rossi Alex
  • 81
  • 1
  • 2
-1

Just add the class full-width-table at tag table.

e.g. <table mat-table class="full-width-table" [dataSource]="dataSource">

Breno Gomes
  • 105
  • 3