Skip to content
On this page

Table ​

Variations ​

Anu provides two variations for table component:

  1. ATable - Use this lightweight table for simply rendering rows & columns. This also support rending custom column content via slot & allow adding extra columns.
  2. ADataTable - This table provide advanced features like sorting, searching & pagination. You can use this table to render the data from API. This component is build on top of ATable component.

Basic ​

You can create basic table that renders the rows & columns using ATable component.

Use rows prop to provide data to ATable. Defining columns for table is optional. When columns aren't specified via prop, columns will get calculate from first row.

nameusernamewebsite
Leanne GrahamBrethildegard.org
Ervin HowellAntonetteanastasia.net
Clementine BauchSamantharamiro.info
Patricia LebsackKariannekale.biz
Chelsey DietrichKamrendemarco.info
Demo data

In all table demos uses data for rows from below file.

ts
import type { ADataTableItemsFunctionParams, typeSortBy } from 'anu-vue'
import { useSearch, useSort } from 'anu-vue'

export const rows = [
  {
    name: 'Leanne Graham',
    username: 'Bret',
    website: 'hildegard.org',
  },
  {
    name: 'Ervin Howell',
    username: 'Antonette',
    website: 'anastasia.net',
  },
  {
    name: 'Clementine Bauch',
    username: 'Samantha',
    website: 'ramiro.info',
  },
  {
    name: 'Patricia Lebsack',
    username: 'Karianne',
    website: 'kale.biz',
  },
  {
    name: 'Chelsey Dietrich',
    username: 'Kamren',
    website: 'demarco.info',
  },
]

// 👉 For Server side table

export type User = {
  id: number
  name: string
  username: string
  email: string
  address: {
    street: string
    suite: string
    city: string
    zipcode: string
    geo: {
      lat: string
      lng: string
    }
  }
  phone: string
  website: string
  company: {
    name: string
    catchPhrase: string
    bs: string
  }
}

export const fakeDatabase: User[] = [
  {
    id: 1,
    name: 'Leanne Graham',
    username: 'Bret',
    email: 'Sincere@april.biz',
    address: {
      street: 'Kulas Light',
      suite: 'Apt. 556',
      city: 'Gwenborough',
      zipcode: '92998-3874',
      geo: {
        lat: '-37.3159',
        lng: '81.1496',
      },
    },
    phone: '1-770-736-8031 x56442',
    website: 'hildegard.org',
    company: {
      name: 'Romaguera-Crona',
      catchPhrase: 'Multi-layered client-server neural-net',
      bs: 'harness real-time e-markets',
    },
  },
  {
    id: 2,
    name: 'Ervin Howell',
    username: 'Antonette',
    email: 'Shanna@melissa.tv',
    address: {
      street: 'Victor Plains',
      suite: 'Suite 879',
      city: 'Wisokyburgh',
      zipcode: '90566-7771',
      geo: {
        lat: '-43.9509',
        lng: '-34.4618',
      },
    },
    phone: '010-692-6593 x09125',
    website: 'anastasia.net',
    company: {
      name: 'Deckow-Crist',
      catchPhrase: 'Proactive didactic contingency',
      bs: 'synergize scalable supply-chains',
    },
  },
  {
    id: 3,
    name: 'Clementine Bauch',
    username: 'Samantha',
    email: 'Nathan@yesenia.net',
    address: {
      street: 'Douglas Extension',
      suite: 'Suite 847',
      city: 'McKenziehaven',
      zipcode: '59590-4157',
      geo: {
        lat: '-68.6102',
        lng: '-47.0653',
      },
    },
    phone: '1-463-123-4447',
    website: 'ramiro.info',
    company: {
      name: 'Romaguera-Jacobson',
      catchPhrase: 'Face to face bifurcated interface',
      bs: 'e-enable strategic applications',
    },
  },
  {
    id: 4,
    name: 'Patricia Lebsack',
    username: 'Karianne',
    email: 'Julianne.OConner@kory.org',
    address: {
      street: 'Hoeger Mall',
      suite: 'Apt. 692',
      city: 'South Elvis',
      zipcode: '53919-4257',
      geo: {
        lat: '29.4572',
        lng: '-164.2990',
      },
    },
    phone: '493-170-9623 x156',
    website: 'kale.biz',
    company: {
      name: 'Robel-Corkery',
      catchPhrase: 'Multi-tiered zero tolerance productivity',
      bs: 'transition cutting-edge web services',
    },
  },
  {
    id: 5,
    name: 'Chelsey Dietrich',
    username: 'Kamren',
    email: 'Lucio_Hettinger@annie.ca',
    address: {
      street: 'Skiles Walks',
      suite: 'Suite 351',
      city: 'Roscoeview',
      zipcode: '33263',
      geo: {
        lat: '-31.8129',
        lng: '62.5342',
      },
    },
    phone: '(254)954-1289',
    website: 'demarco.info',
    company: {
      name: 'Keebler LLC',
      catchPhrase: 'User-centric fault-tolerant solution',
      bs: 'revolutionize end-to-end systems',
    },
  },
  {
    id: 6,
    name: 'Mrs. Dennis Schulist',
    username: 'Leopoldo_Corkery',
    email: 'Karley_Dach@jasper.info',
    address: {
      street: 'Norberto Crossing',
      suite: 'Apt. 950',
      city: 'South Christy',
      zipcode: '23505-1337',
      geo: {
        lat: '-71.4197',
        lng: '71.7478',
      },
    },
    phone: '1-477-935-8478 x6430',
    website: 'ola.org',
    company: {
      name: 'Considine-Lockman',
      catchPhrase: 'Synchronised bottom-line interface',
      bs: 'e-enable innovative applications',
    },
  },
  {
    id: 7,
    name: 'Kurtis Weissnat',
    username: 'Elwyn.Skiles',
    email: 'Telly.Hoeger@billy.biz',
    address: {
      street: 'Rex Trail',
      suite: 'Suite 280',
      city: 'Howemouth',
      zipcode: '58804-1099',
      geo: {
        lat: '24.8918',
        lng: '21.8984',
      },
    },
    phone: '210.067.6132',
    website: 'elvis.io',
    company: {
      name: 'Johns Group',
      catchPhrase: 'Configurable multimedia task-force',
      bs: 'generate enterprise e-tailers',
    },
  },
  {
    id: 8,
    name: 'Nicholas Runolfsdottir V',
    username: 'Maxime_Nienow',
    email: 'Sherwood@rosamond.me',
    address: {
      street: 'Ellsworth Summit',
      suite: 'Suite 729',
      city: 'Aliyaview',
      zipcode: '45169',
      geo: {
        lat: '-14.3990',
        lng: '-120.7677',
      },
    },
    phone: '586.493.6943 x140',
    website: 'jacynthe.com',
    company: {
      name: 'Abernathy Group',
      catchPhrase: 'Implemented secondary concept',
      bs: 'e-enable extensible e-tailers',
    },
  },
  {
    id: 9,
    name: 'Glenna Reichert',
    username: 'Delphine',
    email: 'Chaim_McDermott@dana.io',
    address: {
      street: 'Dayna Park',
      suite: 'Suite 449',
      city: 'Bartholomebury',
      zipcode: '76495-3109',
      geo: {
        lat: '24.6463',
        lng: '-168.8889',
      },
    },
    phone: '(775)976-6794 x41206',
    website: 'conrad.com',
    company: {
      name: 'Yost and Sons',
      catchPhrase: 'Switchable contextually-based project',
      bs: 'aggregate real-time technologies',
    },
  },
  {
    id: 10,
    name: 'Clementina DuBuque',
    username: 'Moriah.Stanton',
    email: 'Rey.Padberg@karina.biz',
    address: {
      street: 'Kattie Turnpike',
      suite: 'Suite 198',
      city: 'Lebsackbury',
      zipcode: '31428-2261',
      geo: {
        lat: '-38.2386',
        lng: '57.2232',
      },
    },
    phone: '024-648-3804',
    website: 'ambrose.net',
    company: {
      name: 'Hoeger LLC',
      catchPhrase: 'Centralized empowering task-force',
      bs: 'target end-to-end models',
    },
  },
]

export function fakeAPICall({ q, currentPage, rowsPerPage, sortedCols }: ADataTableItemsFunctionParams<User>) {
  return new Promise(resolve => {
    // Added some timeout to delay the request response
    setTimeout(() => {
      // Search logic
      const { results: filteredData } = useSearch<User>(q, fakeDatabase, [
        'id',
        'name',
        'username',
        'email',
        {
          name: 'address',
          filterBy: (val, q) => {
            const _q = q.toLocaleLowerCase()

            // ℹī¸ This type assertion is not required when we improve the types of useSearch composable
            return (val as unknown as User['address']).street.toLocaleLowerCase().includes(_q) || (val as unknown as User['address']).street.toLocaleLowerCase().includes(_q)
          },
        },
        'phone',
        'website',
        {
          name: 'company',
          filterBy: (val, q) => {
            const _q = q.toLocaleLowerCase()

            // ℹī¸ This type assertion is not required when we improve the types of useSearch composable
            return (val as unknown as User['company']).name.toLocaleLowerCase().includes(_q) || (val as unknown as User['company']).bs.toLocaleLowerCase().includes(_q)
          },
        },
      ])

      // Sorting logic
      const { results } = useSort<User>(
        filteredData.value,
        (() => {
          const colsSortBy: typeSortBy = []

          sortedCols.forEach(col => {
            if (col.sortBy !== undefined)
              colsSortBy.push({ name: col.name, isAsc: col.sortBy === 'asc' })
          })

          return colsSortBy
        })(),
      )

      const _currentPage = currentPage || 1

      const paginatedRows = results.value.slice((_currentPage - 1) * rowsPerPage, _currentPage * rowsPerPage)

      resolve({
        data: { rows: paginatedRows, total: results.value.length },
      })
    }, 150)
  })
}

Column Formatter ​

Use formatter property while defining column to format the column text.

nameusernamewebsite
Leanne Graham@Brethildegard.org
Ervin Howell@Antonetteanastasia.net
Clementine Bauch@Samantharamiro.info
Patricia Lebsack@Kariannekale.biz
Chelsey Dietrich@Kamrendemarco.info

Slots ​

ATable provides scoped slot for rendering customer header for your column instead of just text via header-<colName> slot.

It also generates scoped slot based on your column name for rendering custom column. If your column name is website then you can use col-website scoped slot to render custom content in your column.

nameusernamewebsite
Leanne GrahamBrethildegard.org
Ervin HowellAntonetteanastasia.net
Clementine BauchSamantharamiro.info
Patricia LebsackKariannekale.biz
Chelsey DietrichKamrendemarco.info

Extra Column ​

Define extra column in column definition to add column to table. Later, you can use column slot col-<name> to render your custom content.

Moreover, you can also omit the column definition to omit rendering the specific column.

nameusernameactions
Leanne GrahamBret
Ervin HowellAntonette
Clementine BauchSamantha
Patricia LebsackKarianne
Chelsey DietrichKamren

Filtering ​

Set search prop to true to enable table filtering.

Search will respect the column's isFilterable property to include or exclude the column from searching. If you don't specify column definition all columns will be filterable.

nameusernamewebsite
Leanne GrahamBrethildegard.org
Ervin HowellAntonetteanastasia.net
Clementine BauchSamantharamiro.info
Patricia LebsackKariannekale.biz
Chelsey DietrichKamrendemarco.info
1 - 5 of 5

Sorting ​

Sorting is enable by default and will respect the column's isSortable property. If you don't specify column definition all columns will be sortable.

To disable sorting on table use set isSortable prop to false on ATable.

Moreover, You can also sort multiple columns at once. You can enable it by setting multiSort prop to true on ATable.

nameusernamewebsite
Leanne GrahamBrethildegard.org
Ervin HowellAntonetteanastasia.net
Clementine BauchSamantharamiro.info
Patricia LebsackKariannekale.biz
Chelsey DietrichKamrendemarco.info
1 - 5 of 5

Server Side Table ​

If your table data is coming from API/backend you can pass async function to rows prop which should resolve the below type:

ts
interface rowsFunctionReturn {
  rows: unknown[]
  total: number
}
ts
const fetchRows = ({ q, currentPage, rowsPerPage, sortedCols }) => {
  // You can use => q, currentPage, rowsPerPage, sortedCols
    return fetch('https://jsonplaceholder.typicode.com/users')
      .then(response => response.json())
      .then(json => ({ rows: json, total: json.length }))
}
nameusernameemail
No records found!
0 - 0 of 0

API ​

Table

variant : LayerVariant

Layer variant

states : boolean

Interaction states like hover & active

loading : boolean | ALoaderProps

Set loading state

titleTag : string

Tag to use for title of the component

subtitleTag : string

Tag to use for subtitle of the component

textTag : string

Tag to use for text rendered via text prop

rows : Record<string, unknown>[]

Table rows

cols : ATablePropColumn<Record<string, unknown>>[]

By default table will infer the column definition from first row. You can also manually provide the column definition for more control.

noDataText : string

Text to render when no row is available

text : ConfigurableValue

Typography text content

color : ColorProp

Layer color

title : ConfigurableValue

Typography title

subtitle : ConfigurableValue

Typography subtitle

img : string

Render image at the top of the card (above header)

imgAlt : string

alt attribute for image rendered via img prop

Data Table

variant : LayerVariant

Layer variant

states : boolean

Interaction states like hover & active

search : string | boolean

Enable filtering/searching in table

loading : boolean | ALoaderProps

Set loading state

titleTag : string

Tag to use for title of the component

subtitleTag : string

Tag to use for subtitle of the component

textTag : string

Tag to use for text rendered via text prop

cols : ADataTablePropColumn<Record<string, unknown>>[]

By default table will infer the column definition from first row. You can also manually provide the column definition for more control.

noDataText : string

Text to render when no row is available

isSortable : boolean

Enable/Disable sorting table

multiSort : boolean

By default you can only sort single column. You can enable sorting multiple columns at the same time using this prop.

pageSize : number

Set rows to show per page

text : ConfigurableValue

Typography text content

color : ColorProp

Layer color

title : ConfigurableValue

Typography title

subtitle : ConfigurableValue

Typography subtitle

img : string

Render image at the top of the card (above header)

imgAlt : string

alt attribute for image rendered via img prop

rows : ADataTableItemsFunction<Record<string, unknown>> | Record<string, unknown>[]

Function that returns resolves array.

Released under the MIT License.