Tables

For displaying tabular data, BTable supports pagination, filtering, sorting, custom rendering, various style options, events, and asynchronous data. For simple display of tabular data without all the fancy features, BootstrapVueNext provides two lightweight alternative components BTableLite and BTableSimple.

Basic Usage

AgeFirst nameLast name
40DickersonMacdonald
21LarsenShaw
89GenevaWilson
38JamiCarney
HTML
vue
<template>
  <div>
    <BTable striped hover :items="items" />
  </div>
</template>

<script setup lang="ts">
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {age: 38, first_name: 'Jami', last_name: 'Carney'},
]
</script>

Items (record data)

items is the table data in array format, where each record (row) data are keyed objects. Example format:

ts
const items = [
  {age: 32, first_name: 'Cyndi'},
  {age: 27, first_name: 'Havij'},
  {age: 42, first_name: 'Robert'},
]

<BTable> automatically samples the first row to extract field names (the keys in the record data). Field names are automatically "humanized" by converting kebab-case, snake_case, and camelCase to individual words and capitalizes each word. Example conversions:

  • first_name becomes First Name
  • last-name becomes Last Name
  • age becomes Age
  • YEAR remains YEAR
  • isActive becomes Is Active

These titles will be displayed in the table header, in the order they appear in the first record of data. See the Fields section below for customizing how field headings appear.

NOTE

Field order is not guaranteed. Fields will typically appear in the order they were defined in the first row, but this may not always be the case depending on the version of browser in use. See section Fields (column definitions) below to see how to guarantee the order of fields, and to override the headings generated.

Record data may also have additional special reserved name keys for colorizing rows and individual cells (variants), and for triggering additional row detail. The type TableItem defines the supported optional item record modifier properties (make sure your field keys do not conflict with these names):

PropertyTypeDescription
_cellVariantsPartial<Record<keyof T, ColorVariant>>Bootstrap contextual state applied to individual cells. Keyed by field (See the Color Variants for supported values). These variants map to classes table-${variant} or bg-${variant} (when the dark prop is set).
_rowVariantColorVariantBootstrap contextual state applied to the entire row (See the Color Variants for supported values). These variants map to classes table-${variant} or bg-${variant} (when the dark prop is set)
_showDetailsbooleanUsed to trigger the display of the row-details scoped slot. See section Row details support below for additional information

Example: Using variants for table cells

AgeFirst nameLast name
40DickersonMacdonald
21LarsenShaw
89GenevaWilson
40ThorMacDonald
29DickDunlap
HTML
vue
<template>
  <div>
    <BTable hover :items="items" />
  </div>
</template>

<script setup lang="ts">
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {
    age: 89,
    first_name: 'Geneva',
    last_name: 'Wilson',
    _rowVariant: 'danger',
  },
  {
    age: 40,
    first_name: 'Thor',
    last_name: 'MacDonald',
    _cellVariants: {age: 'info', first_name: 'warning'},
  },
  {age: 29, first_name: 'Dick', last_name: 'Dunlap'},
]
</script>

items can also be a reference to a provider function, which returns an Array of items data. Provider functions can also be asynchronous:

  • By returning null (or undefined) and calling a callback, when the data is ready, with the data array as the only argument to the callback,
  • By returning a Promise that resolves to an array.

See the "Using Items Provider functions" section below for more details.

Table item notes and warnings

  • Avoid manipulating record data in place, as changes to the underlying items data will cause either the row or entire table to be re-rendered. See Primary Key, below, for ways to minimize Vue's re-rendering of rows.
  • items array records should be a simple object and must avoid placing data that may have circular references in the values within a row. <BTable> serializes the row data into strings for sorting and filtering, and circular references will cause stack overflows to occur and your app to crash!

Fields (column definitions)

The fields prop is used to customize the table columns headings, and in which order the columns of data are displayed. The field object keys (i.e. age or first_name as shown below) are used to extract the value from each item (record) row, and to provide additional features such as enabling sorting on the column, etc.

Fields can be provided as a simple array or an array of objects. Internally the fields data will be normalized into the array of objects format. Events or slots that include the column field data will be in the normalized field object format (array of objects for fields, or an object for an individual field).

Fields as a simple array

Fields can be a simple array, for defining the order of the columns, and which columns to display:

First nameLast nameAge
DickersonMacdonald40
LarsenShaw21
GenevaWilson89
JamiCarney38
HTML
vue
<template>
  <div>
    <BTable striped hover :items="items" :fields="fields" />
  </div>
</template>

<script setup lang="ts">
// Note `isActive` is left out and will not appear in the rendered table
const fields = ['first_name', 'last_name', 'age']
const items = [
  {isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney'},
]
</script>

Fields as an array of objects

Fields can be a an array of objects, providing additional control over the fields (such as sorting, formatting, etc.). Only columns (keys) that appear in the fields array will be shown:

Last NameFirst NamePerson age
MacdonaldDickerson40
ShawLarsen21
WilsonGeneva89
CarneyJami38
HTML
vue
<template>
  <div>
    <BTable striped hover :items="items" :fields="fields" />
  </div>
</template>

<script setup lang="ts">
import type {TableFieldRaw} from 'bootstrap-vue-next'

interface Person {
  first_name: string
  last_name: string
  age: number
  isActive: boolean
}

// Note 'isActive' is left out and will not appear in the rendered table
const fields: TableFieldRaw<Person>[] = [
  {
    key: 'last_name',
    sortable: true,
  },
  {
    key: 'first_name',
    sortable: false,
  },
  {
    key: 'age',
    label: 'Person age',
    sortable: true,
    // Variant applies to the whole column, including the header and footer
    variant: 'danger',
  },
]

const items: Person[] = [
  {isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney'},
]
</script>

Field Definition Reference

The following field properties (defined as TableField) are recognized:

PropertyTypeDescription
keyLiteralUnion<keyof T>The key for selecting data from the record in the items array. Required when setting the fields via an array of objects. The key is also used for generating the custom data rendering and custom header and footer slot names.
labelstringAppears in the columns table header (and footer if foot-clone is set). Defaults to the field's key (in humanized format) if not provided. It's possible to use empty labels by assigning an empty string "" but be sure you also set headerTitle to provide non-sighted users a hint about the column contents.
headerTitlestringText to place on the fields header <th> attribute title. Defaults to no title attribute.
headerAbbrstringText to place on the fields header <th> attribute abbr. Set this to the unabbreviated version of the label (or title) if label (or title) is an abbreviation. Defaults to no abbr attribute.
classClassValueClass name (or array of class names) to add to <th> and <td> in the column.
formatterTableFieldFormatter<T>A formatter callback function can be used instead of (or in conjunction with) scoped field slots. The formatter will be called with the syntax formatter<T>(value: unknown, key: string, item: T). Refer to Custom Data Rendering for more details.
sortablebooleanEnable sorting on this column. Refer to the Sorting Section for more details.
sortDirectionstringSet the initial sort direction on this column when it becomes sorted. Refer to the Change initial sort direction Section for more details.Not yet implemented
sortByFormattedboolean | TableFieldFormatter<T>Sort the column by the result of the field's formatter callback function when set to true. Default is false. Boolean has no effect if the field does not have a formatter. Optionally accepts a formatter function reference to format the value for sorting purposes only. Refer to the Sorting Section for more details.
filterByFormattedboolean | TableFieldFormatter<T>Filter the column by the result of the field's formatter callback function when set to true. Default is false. Boolean has no effect if the field does not have a formatter. Optionally accepts a formatter function reference to format the value for filtering purposes only. Refer to the Filtering section for more details.
tdClassTableStrictClassValue | ((value: unknown, key: string, item: T) => TableStrictClassValue)Class name (or array of class names) to add to <tbody> data <td> cells in the column. If custom classes per cell are required, a callback function can be specified instead. See the typescript definition for accepted parameters and return types.
thClassClassValueClass name (or array of class names) to add to this field's <thead>/<tfoot> heading <th> cell.
thStyleStyleValueCSS styles you would like to apply to the table <thead>/<tfoot> field <th> cell.
variantColorVariant | nullApply contextual class to all the <th> and <td> in the column.
tdAttrAttrsValue | ((value: unknown, key: string, item: T) => AttrsValue)Object representing additional attributes to apply to the <tbody> field <td> cell. If custom attributes per cell are required, a callback function can be specified instead. See the typescript definition for accepted parameters and return types.
thAttrAttrsValue | ((value: unknown, key: string, item: T | null, type: TableRowThead) => AttrsValueObject representing additional attributes to apply to the field's <thead>/<tfoot> heading <th> cell. If the field's isRowHeader is set to true, the attributes will also apply to the <tbody> field <th> cell. If custom attributes per cell are required, a callback function can be specified instead. See the typescript definition for accepted parameters and return types.
isRowHeaderbooleanWhen set to true, the field's item data cell will be rendered with <th> rather than the default of <td>.
stickyColumnbooleanWhen set to true, and the table in responsive mode or has sticky headers, will cause the column to become fixed to the left when the table's horizontal scrollbar is scrolled. See Sticky columns for more details

Notes:

  • Field properties, if not present, default to null (falsey) unless otherwise stated above.
  • class, thClass, tdClass etc. will not work with classes that are defined in scoped CSS, unless you are using Vue's Deep selector.
  • For information on the syntax supported by thStyle, see Class and Style Bindings in the Vue.js guide.
  • Any additional properties added to the field definition objects will be left intact - so you can access them via the named scoped slots for custom data, header, and footer rendering.

For information and usage about scoped slots and formatters, refer to the Custom Data Rendering section below.

Feel free to mix and match simple array and object array together:

ts
const fields = [
  {key: 'first_name', label: 'First'},
  {key: 'last_name', label: 'Last'},
  'age',
  'sex',
]

Primary Key

<BTable> provides an additional prop primary-key, which you can use to identify the name of the field key that uniquely identifies the row.

The value specified by the primary column key must be either a string or number, and must be unique across all rows in the table.

The primary key column does not need to appear in the displayed fields.

Table row ID generation

When provided, the primary-key will generate a unique ID for each item row <tr> element. The ID will be in the format of {table-id}__row_{primary-key-value}, where {table-id} is the unique ID of the <BTable> and {primary-key-value} is the value of the item's field value for the field specified by primary-key.

Table render and transition optimization

The primary-key is also used by <BTable> to help Vue optimize the rendering of table rows. Internally, the value of the field key specified by the primary-key prop is used as the Vue :key value for each rendered item row <tr> element.

If you are seeing rendering issue (i.e. tooltips hiding or unexpected subcomponent re-usage when item data changes or data is sorted/filtered/edited) or table row transitions are not working, setting the primary-key prop (if you have a unique identifier per row) can alleviate these issues.

Specifying the primary-key column is handy if you are using 3rd party table transitions or drag and drop plugins, as they rely on having a consistent and unique per row :key value.

If primary-key is not provided, <BTable> will auto-generate keys based on the displayed row's index number (i.e. position in the displayed table rows). This may cause GUI issues such as sub components/elements that are rendering with previous results (i.e. being re-used by Vue's render patch optimization routines). Specifying a primary-key column can alleviate this issue (or you can place a unique :key on your element/components in your custom formatted field slots).

Refer to the Table body transition support section for additional details.

Table Style Options

Table styling

<BTable> provides several props to alter the style of the table:

propTypeDescription
stripedbooleanAdd zebra-striping to the table rows within the <tbody>
striped-columnsbooleanAdd zebra-striping to the table colums within the <tbody>
borderedbooleanFor borders on all sides of the table and cells.
borderlessbooleanremoves inner borders from table.
outlinedbooleanFor a thin border on all sides of the table. Has no effect if bordered is set.
smallbooleanTo make tables more compact by cutting cell padding in half.
hoverbooleanTo enable a hover highlighting state on table rows within a <tbody>
darkbooleanInvert the colors — with light text on dark backgrounds (equivalent to Bootstrap v5 class .table-dark)
fixedbooleanGenerate a table with equal fixed-width columns (table-layout: fixed;) Not yet implemented
responsiveboolean | BreakpointGenerate a responsive table to make it scroll horizontally. Set to true for an always responsive table, or set it to one of the breakpoints 'sm', 'md', 'lg', 'xl' or 'xxl' to make the table responsive (horizontally scroll) only on screens smaller than the breakpoint. See Responsive tables below for details.
sticky-headerboolean | NumberishGenerates a vertically scrollable table with sticky headers. Set to true to enable sticky headers (default table max-height of 300px), or set it to a string containing a height (with CSS units) to specify a maximum height other than 300px. See the Sticky header section below for details.
stackedboolean | BreakpointGenerate a responsive stacked table. Set to true for an always stacked table, or set it to one of the breakpoints 'sm', 'md', 'lg', 'xl' or 'xxl' to make the table visually stacked only on screens smaller than the breakpoint. See Stacked tables below for details.
caption-topboolean | NumberishIf the table has a caption, and this prop is set to true, the caption will be visually placed above the table. If false (the default), the caption will be visually placed below the table.
variantColorVariant | nullGive the table an overall theme color variant.
head-variantColorVariant | nullMake the table head a theme color different from the table
foot-row-variantColorVariant | nullMake the table foot a theme color different from the table. If not set, head-variant will be used. Has no effect if foot-clone is not set
head-row-variantColorVariant | nullMake the only the <tr> part of the <head> a specific theme color
foot-variantColorVariant | nullMake the only the <tr> part of the <foot> a specific theme color. If not set, head-row-variant will be used. Has no effect if foot-clone is not set
foot-clonebooleanTurns on the table footer, and defaults with the same contents a the table header
no-footer-sortingbooleanWhen foot-clone is true and the table is sortable, disables the sorting icons and click behaviour on the footer heading cells. Refer to the Sorting section below for more details. Not yet implemented
no-border-collapseBooleanDisables the default of collapsing of the table borders. Mainly for use with sticky headers and/or sticky columns. Will cause the appearance of double borders in some situations. Not yet implemented

NOTE

The table style options fixed, stacked, no-border-collapse, sticky headers, sticky columns and the table sorting feature, all require BootstrapVueNext's custom CSS.

Table Options
First nameLast nameAge
DickersonMacdonald40
LarsenShaw21
GenevaWilson89
HTML
vue
<template>
  <div>
    <BFormGroup v-slot="{ariaDescribedby}" label="Table Options" label-cols-lg="2">
      <BFormCheckbox v-model="striped" :aria-describedby="ariaDescribedby" inline
        >Striped</BFormCheckbox
      >
      <BFormCheckbox v-model="stripedColumns" :aria-describedby="ariaDescribedby" inline
        >Striped Columns</BFormCheckbox
      >
      <BFormCheckbox v-model="bordered" :aria-describedby="ariaDescribedby" inline
        >Bordered</BFormCheckbox
      >
      <BFormCheckbox v-model="borderless" :aria-describedby="ariaDescribedby" inline
        >Borderless</BFormCheckbox
      >
      <BFormCheckbox v-model="outlined" :aria-describedby="ariaDescribedby" inline
        >Outlined</BFormCheckbox
      >
      <BFormCheckbox v-model="small" :aria-describedby="ariaDescribedby" inline
        >Small</BFormCheckbox
      >
      <BFormCheckbox v-model="hover" :aria-describedby="ariaDescribedby" inline
        >Hover</BFormCheckbox
      >
      <BFormCheckbox v-model="dark" :aria-describedby="ariaDescribedby" inline>Dark</BFormCheckbox>
      <BFormCheckbox v-model="fixed" :aria-describedby="ariaDescribedby" inline
        >Fixed</BFormCheckbox
      >
      <BFormCheckbox v-model="footClone" :aria-describedby="ariaDescribedby" inline
        >Foot Clone</BFormCheckbox
      >
      <BFormCheckbox v-model="noCollapse" :aria-describedby="ariaDescribedby" inline
        >No border collapse</BFormCheckbox
      >
    </BFormGroup>

    <BFormGroup label="Variant" label-for="table-style-variant" label-cols-lg="2" class="my-2">
      <BFormSelect id="table-style-variant" v-model="variant" :options="variants">
        <template #first>
          <option :value="null">-- None --</option>
        </template>
      </BFormSelect>
    </BFormGroup>

    <BFormGroup label="Head Variant" label-for="head-style-variant" label-cols-lg="2" class="my-2">
      <BFormSelect id="head-style-variant" v-model="headVariant" :options="variants">
        <template #first>
          <option :value="null">-- None --</option>
        </template>
      </BFormSelect>
    </BFormGroup>

    <BFormGroup label="Foot Variant" label-for="foot-style-variant" label-cols-lg="2" class="my-2">
      <BFormSelect id="foot-style-variant" v-model="footVariant" :options="variants">
        <template #first>
          <option :value="null">-- None --</option>
        </template>
      </BFormSelect>
    </BFormGroup>

    <BTable
      :striped="striped"
      :striped-columns="stripedColumns"
      :bordered="bordered"
      :borderless="borderless"
      :outlined="outlined"
      :small="small"
      :hover="hover"
      :dark="dark"
      :fixed="fixed"
      :foot-clone="footClone"
      :no-border-collapse="noCollapse"
      :items="items"
      :fields="fields"
      :variant="variant"
      :head-variant="headVariant"
      :foot-variant="footVariant"
    />
  </div>
</template>

<script setup lang="ts">
import type {ColorVariant} from 'bootstrap-vue-next'
import {ref} from 'vue'

const fields = ['first_name', 'last_name', 'age']
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
]

const striped = ref(false)
const stripedColumns = ref(false)
const bordered = ref(false)
const borderless = ref(false)
const outlined = ref(false)
const small = ref(false)
const hover = ref(false)
const dark = ref(false)
const fixed = ref(false)
const footClone = ref(false)
const variant = ref<ColorVariant | null>(null)
const headVariant = ref<ColorVariant | null>(null)
const footVariant = ref<ColorVariant | null>(null)
const noCollapse = ref(false)

const variants = ['primary', 'secondary', 'info', 'danger', 'warning', 'success', 'light', 'dark']
</script>

Row styling and attributes

You can also style every row using the tbody-tr-class prop, and optionally supply additional attributes via the tbody-tr-attr prop:

PropertyTypeDescription
tbody-tr-class((item: Items | null, type: TableRowType) => TableStrictClassValue) | TableStrictClassValueClasses to be applied to every row on the table.
tbody-tr-attr((item: Items | null, type: TableRowType) => AttrsValue) | AttrsValueAttributes to be applied to every row on the table.

When passing a function reference to tbody-tr-class or tbody-tr-attr, the function's arguments will be as follows:

  • item - The item record data associated with the row. For rows that are not associated with an item record, this value will be null or undefined
  • type - The type of row being rendered (TableRowType). 'row' for an item row, 'row-details' for an item details row, 'row-top' for the fixed row top slot, 'row-bottom' for the fixed row bottom slot, or 'table-busy' for the table busy slot.
First nameLast nameAge
DickersonMacdonald40
LarsenShaw21
GenevaWilson89
HTML
vue
<template>
  <div>
    <BTable :items="items" :fields="fields" :tbody-tr-class="rowClass" />
  </div>
</template>

<script setup lang="ts">
import type {TableRowType, TableStrictClassValue} from 'bootstrap-vue-next'

interface Person {
  age: number
  first_name: string
  last_name: string
  status?: string
}

const fields = ['first_name', 'last_name', 'age']
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald', status: 'awesome'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
]

const rowClass = (item: Person, type: TableRowType): TableStrictClassValue =>
  type === 'row' && item.status === 'awesome' ? 'table-success' : ''
</script>

Responsive tables

Responsive tables allow tables to be scrolled horizontally with ease. Make any table responsive across all viewports by setting the prop responsive to true. Or, pick a maximum breakpoint with which to have a responsive table up to by setting the prop responsive to one of the breakpoint values: sm, md, lg, or xl.

Heading1Heading2Heading3Heading4Heading5Heading6Heading7Heading8Heading9Heading10Heading11Heading12
table celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable cell
table celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable cell
table celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable celltable cell
HTML
vue
<template>
  <div>
    <BTable responsive :items="items" />
  </div>
</template>

<script setup lang="ts">
const items = [
  {
    heading1: 'table cell',
    heading2: 'table cell',
    heading3: 'table cell',
    heading4: 'table cell',
    heading5: 'table cell',
    heading6: 'table cell',
    heading7: 'table cell',
    heading8: 'table cell',
    heading9: 'table cell',
    heading10: 'table cell',
    heading11: 'table cell',
    heading12: 'table cell',
  },
  {
    heading1: 'table cell',
    heading2: 'table cell',
    heading3: 'table cell',
    heading4: 'table cell',
    heading5: 'table cell',
    heading6: 'table cell',
    heading7: 'table cell',
    heading8: 'table cell',
    heading9: 'table cell',
    heading10: 'table cell',
    heading11: 'table cell',
    heading12: 'table cell',
  },
  {
    heading1: 'table cell',
    heading2: 'table cell',
    heading3: 'table cell',
    heading4: 'table cell',
    heading5: 'table cell',
    heading6: 'table cell',
    heading7: 'table cell',
    heading8: 'table cell',
    heading9: 'table cell',
    heading10: 'table cell',
    heading11: 'table cell',
    heading12: 'table cell',
  },
]
</script>

Responsive table notes:

  • Possible vertical clipping/truncation. Responsive tables make use of overflow-y: hidden, which clips off any content that goes beyond the bottom or top edges of the table. In particular, this may clip off dropdown menus and other third-party widgets.
  • Using props responsive and fixed together will not work as expected. Fixed table layout uses the first row (table header in this case) to compute the width required by each column (and the overall table width) to fit within the width of the parent container — without taking cells in the <tbody> into consideration — resulting in table that may not be responsive. To get around this limitation, you would need to specify widths for the columns (or certain columns) via one of the following methods:
    • Use <col> elements within the table-colgroup slot that have widths set (e.g. <col style="width: 20rem">), or
    • Wrap header cells in <div> elements, via the use of custom header rendering, which have a minimum width set on them, or
    • Use the thStyle property of the field definition object to set a width for the column(s), or
    • Use custom CSS to define classes to apply to the columns to set widths, via the thClass or class properties of the field definition object.

Stacked tables

An alternative to responsive tables, BootstrapVue includes the stacked table option (using custom SCSS/CSS), which allow tables to be rendered in a visually stacked format. Make any table stacked across all viewports by setting the prop stacked to true. Or, alternatively, set a breakpoint at which the table will return to normal table format by setting the prop stacked to one of the breakpoint values 'sm', 'md', 'lg', or 'xl'.

Column header labels will be rendered to the left of each field value using a CSS ::before pseudo element, with a width of 40%.

The stacked prop takes precedence over the sticky-header prop and the stickyColumn field definition property.

AgeFirst nameLast name
40DickersonMacdonald
21LarsenShaw
89GenevaWilson
HTML
vue
<template>
  <div>
    <BTable stacked :items="items" />
  </div>
</template>

<script setup lang="ts">
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
]
</script>

Note: When the table is visually stacked:

  • The table header (and table footer) will be hidden.
  • Custom rendered header slots will not be shown, rather, the fields' label will be used.
  • The table cannot be sorted by clicking the rendered field labels. You will need to provide an external control to select the field to sort by and the sort direction. See the Sorting section below for sorting control information, as well as the complete example at the bottom of this page for an example of controlling sorting via the use of form controls.
  • The slots top-row and bottom-row will be hidden when visually stacked.
  • The table caption, if provided, will always appear at the top of the table when visually stacked.
  • In an always stacked table, the table header and footer, and the fixed top and bottom row slots will not be rendered.

BootstrapVueNext's custom CSS is required in order to support stacked tables.

Table caption

Add an optional caption to your table via the prop caption or the named slot table-caption (the slot takes precedence over the prop). The default Bootstrap v4 styling places the caption at the bottom of the table:

First nameLast nameAge
DickersonMacdonald40
LarsenShaw21
GenevaWilson89
This is a table caption.
HTML
vue
<template>
  <div>
    <BTable :items="items" :fields="fields">
      <template #table-caption>This is a table caption.</template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
const fields = ['first_name', 'last_name', 'age']
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
]
</script>

You can have the caption placed at the top of the table by setting the caption-top prop to true:

First nameLast nameAge
DickersonMacdonald40
LarsenShaw21
GenevaWilson89
This is a table caption at the top.
HTML
vue
<template>
  <div>
    <BTable :items="items" :fields="fields" caption-top>
      <template #table-caption>This is a table caption at the top.</template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
const fields = ['first_name', 'last_name', 'age']
const items = [
  {age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {age: 89, first_name: 'Geneva', last_name: 'Wilson'},
]
</script>

You can also use custom CSS to control the caption positioning.

Table colgroup

Not yet implemented The table-colgroup slot is not yet implemented.

Table busy state

<BTable> provides a busy model that will flag the table as busy, which you can set to true just before you update your items, and then set it to false once you have your items. When in the busy state, the table will have the attribute aria-busy="true".

During the busy state, the table will be rendered in a "muted" look (opacity: 0.55), using the following custom CSS:

css
/* Busy table styling */
.table.b-table[aria-busy="true"] {
  opacity: 0.55;
}

table-busy slot

First nameLast nameAge
DickersonMacDonald40
LarsenShaw21
GenevaWilson89
JamiCarney38
HTML
vue
<template>
  <div>
    <BButton @click="toggleBusy">Toggle Busy State</BButton>

    <BTable :items="items" :busy="isBusy" class="mt-3" outlined>
      <!-- <template #table-busy>
        <div class="text-center text-danger my-2">
          <BSpinner class="align-middle" />
          <strong>Loading...</strong>
        </div>
      </template> -->
    </BTable>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue'
const isBusy = ref(false)
const items = [
  {first_name: 'Dickerson', last_name: 'MacDonald', age: 40},
  {first_name: 'Larsen', last_name: 'Shaw', age: 21},
  {first_name: 'Geneva', last_name: 'Wilson', age: 89},
  {first_name: 'Jami', last_name: 'Carney', age: 38},
]

const toggleBusy = () => {
  isBusy.value = !isBusy.value
}
</script>

Also see the Using Items Provider Functions below for additional information on the busy state.

Notes:

  • All click related and hover events, and sort-changed events will not be emitted when the table is in the busy state.
  • Busy styling and slot are not available in the <BTableLite> component.

Custom data rendering

Custom rendering for each data field in a row is possible using either scoped slots or a formatter callback function, or a combination of both.

Scoped field slots

Scoped field slots give you greater control over how the record data appears. You can use scoped slots to provided custom rendering for a particular field. If you want to add an extra field which does not exist in the records, just add it to the fields array, and then reference the field(s) in the scoped slot(s). Scoped field slots use the following naming syntax: `'cell(${field_key})'`.

You can use the default fall-back scoped slot 'cell()' to format any cells that do not have an explicit scoped slot provided.

IndexFull NameAgeSexFirst name and age
1DOE, John42MaleJohn is 42 years old
2DOE, Jane36FemaleJane is 36 years old
3KINCADE, Rubin73MaleRubin is 73 years old
4PARTRIDGE, Shirley62FemaleShirley is 62 years old
HTML
vue
<template>
  <div>
    <BTable small :fields="fields" :items="items" responsive="sm">
      <!-- A virtual column -->
      <template #cell(index)="data">
        {{ data.index + 1 }}
      </template>

      <!-- A custom formatted column -->
      <template #cell(name)="data">
        <b class="text-info">{{ data.item.name.last.toUpperCase() }}</b
        >, <b>{{ data.item.name.first }}</b>
      </template>

      <!-- A virtual composite column -->
      <template #cell(nameage)="data">
        {{ data.item.name.first }} is {{ data.item.age }} years old
      </template>

      <!-- Optional default data cell scoped slot -->
      <template #cell()="data">
        <i>{{ data.value }}</i>
      </template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
interface Person {
  name: {first: string; last: string}
  sex: string
  age: number
}

const fields = [
  // A virtual column that doesn't exist in items
  'index',
  // A column that needs custom formatting
  {key: 'name', label: 'Full Name'},
  // A regular column
  'age',
  // A regular column
  'sex',
  // A virtual column made up from two fields
  {key: 'nameage', label: 'First name and age'},
]
const items: Person[] = [
  {name: {first: 'John', last: 'Doe'}, sex: 'Male', age: 42},
  {name: {first: 'Jane', last: 'Doe'}, sex: 'Female', age: 36},
  {name: {first: 'Rubin', last: 'Kincade'}, sex: 'Male', age: 73},
  {name: {first: 'Shirley', last: 'Partridge'}, sex: 'Female', age: 62},
]
</script>

The slot's scope variable (data in the above sample) will have the following properties:

PropertyTypeDescription
indexnumberThe row number (indexed from zero) relative to the displayed rows
itemItemsThe entire raw record data (i.e. items[index]) for this row (before any formatter is applied)
valueunknownThe value for this key in the record (null or undefined if a virtual column), or the output of the field's formatter function
unformattedunknownThe raw value for this key in the item record (null or undefined if a virtual column), before being passed to the field's formatter function
field(typeof computedFields.value)[0]The field's normalized field definition object
detailsShowingbooleanWill be true if the row's row-details scoped slot is visible. See section Row details support below for additional information
toggleDetails() => voidCan be called to toggle the visibility of the rows row-details scoped slot. See section Row details support below for additional information
rowSelectedbooleanWill be true if the row has been selected. See section Row select support for additional information
selectRow(index?: number) => voidWhen called, selects the current row. See section Row select support for additional information
unselectRow(index?: number) => voidWhen called, unselects the current row. See section Row select support for additional information

Notes:

  • index will not always be the actual row's index number, as it is computed after filtering, sorting and pagination have been applied to the original table data. The index value will refer to the displayed row number. This number will align with the indexes from the optional v-model bound variable.
  • When using the v-slot syntax, note that slot names cannot contain spaces, and when using in-browser DOM templates the slot names will always be lower cased. To get around this, you can pass the slot name using Vue's dynamic slot names

Displaying raw HTML

By default BTable escapes HTML tags in items data and results of formatter functions, if you need to display raw HTML code in BTable, you should use v-html directive on an element in a in scoped field slot.

TextHtml
This is <i>escaped</i> contentThis is raw HTML content
HTML
vue
<template>
  <div>
    <b-table :items="items">
      <template #cell(html)="data">
        <!-- eslint-disable vue/no-v-html -->
        <span v-html="data.value" />
      </template>
    </b-table>
  </div>
</template>

<script setup lang="ts">
const items = [
  {
    text: 'This is <i>escaped</i> content',
    html: 'This is <i>raw <strong>HTML</strong></i> <span style="color:red">content</span>',
  },
]
</script>

WARNING

Be cautious of using the v-html method to display user supplied content, as it may make your application vulnerable to XSS attacks, if you do not first sanitize the user supplied string.

Formatter callback

Optionally, you can customize field output by using a formatter callback function. To enable this, the field's formatter property is used. The value of this property may be String or function reference. In case of a String value, the function must be defined at the parent component's methods. When providing formatter as a Function, it must be declared at global scope (window or as global mixin at Vue, or as an anonymous function), unless it has been bound to a this context.

The callback function accepts three arguments - value, key, and item, and should return the formatted value as a string (HTML strings are not supported)

Full NameAgeSexCalculated Birth Year
John Doe42M1983
Jane Doe36F1989
Rubin Kincade73M1952
Shirley Partridge62F1963
HTML
vue
<template>
  <div>
    <BTable :fields="fields" :items="items">
      <template #cell(name)="data">
        <!-- `data.value` is the value after formatted by the Formatter -->
        <a :href="`#${(data.value as any as string).replace(/[^a-z]+/i, '-').toLowerCase()}`">{{
          data.value
        }}</a>
      </template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
import type {TableFieldRaw} from 'bootstrap-vue-next'

interface Name {
  first: string
  last: string
}

interface Person {
  name: Name
  sex: string
  age: number
}

const fullName = (value: unknown) => {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const name = value as any as Name
  return `${name.first} ${name.last}`
}

const fields: TableFieldRaw<Person>[] = [
  {
    // A column that needs custom formatting,
    // calling formatter 'fullName' in this app
    key: 'name',
    label: 'Full Name',
    formatter: fullName,
  },
  // A regular column
  'age',
  {
    // A regular column with custom formatter
    key: 'sex',
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    formatter: (value) => (value as any as string).charAt(0).toUpperCase(),
  },
  {
    // A virtual column with custom formatter
    key: 'birthYear',
    label: 'Calculated Birth Year',
    formatter: (value_, key_, item: Person) => (new Date().getFullYear() - item.age).toString(),
  },
]

const items = [
  {name: {first: 'John', last: 'Doe'}, sex: 'Male', age: 42},
  {name: {first: 'Jane', last: 'Doe'}, sex: 'Female', age: 36},
  {name: {first: 'Rubin', last: 'Kincade'}, sex: 'male', age: 73},
  {name: {first: 'Shirley', last: 'Partridge'}, sex: 'female', age: 62},
]
</script>

It is also possible to provide custom rendering for the table's thead and tfoot elements. Note by default the table footer is not rendered unless foot-clone is set to true.

Scoped slots for the header and footer cells uses a special naming convention of 'head(<fieldkey>)' and 'foot(<fieldkey>)' respectively. if a 'foot(...)' slot for a field is not provided, but a 'head(...)' slot is provided, then the footer will use the 'head(...)' slot content.

You can use a default fall-back scoped slot 'head()' or 'foot()' to format any header or footer cells that do not have an explicit scoped slot provided.

FULL NAMEAgeSex
John Doe42Male
Jane Doe36Female
Rubin Kincade73Male
Shirley Partridge62Female
Full Name
Age
Sex
HTML
vue
<template>
  <div>
    <BTable :fields="fields" :items="items" foot-clone>
      <!-- A custom formatted data column cell -->
      <template #cell(name)="data">
        {{ (data.value as any as Name).first }} {{ (data.value as any as Name).last }}
      </template>

      <!-- A custom formatted header cell for field 'name' -->
      <template #head(name)="data">
        <span class="text-info">{{ data.label!.toUpperCase() }}</span>
      </template>

      <!-- A custom formatted footer cell for field 'name' -->
      <template #foot(name)="data">
        <span class="text-danger">{{ data.label }}</span>
      </template>

      <!-- Default fall-back custom formatted footer cell -->
      <template #foot()="data">
        <i>{{ data.label }}</i>
      </template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
type Name = {first: string; last: string}

const fields = [
  // A column that needs custom formatting
  {key: 'name', label: 'Full Name'},
  // A regular column
  'age',
  // A regular column
  'sex',
]
const items = [
  {name: {first: 'John', last: 'Doe'}, sex: 'Male', age: 42},
  {name: {first: 'Jane', last: 'Doe'}, sex: 'Female', age: 36},
  {name: {first: 'Rubin', last: 'Kincade'}, sex: 'Male', age: 73},
  {name: {first: 'Shirley', last: 'Partridge'}, sex: 'Female', age: 62},
]
</script>

The slots can be optionally scoped (data in the above example), and will have the following properties:

PropertyTypeDescription
columnLiteralUnion<keyof Items>The fields's key value
fieldTableField<Items>the field's object (from the fields prop)
labelstring | undefinedThe fields label value (also available as data.field.label)
isFootbooleanCurrently rending the foot if true
selectAllRows() => voidSelect all rows (applicable if the table is in selectable mode
clearSelected() => voidUnselect all rows (applicable if the table is in selectable mode

When placing inputs, buttons, selects or links within a head(...) or foot(...) slot, note that head-clicked event will not be emitted when the input, select, textarea is clicked (unless they are disabled). head-clicked will never be emitted when clicking on links or buttons inside the scoped slots (even when disabled)

Notes:

  • Slot names cannot contain spaces, and when using in-browser DOM templates the slot names will always
  • be lower cased. To get around this, you can pass the slot name using Vue's dynamic slot names

Adding additional rows to the header

If you wish to add additional rows to the header you may do so via the thead-top slot. This slot is inserted before the header cells row, and is not automatically encapsulated by <tr>..</tr> tags. It is recommended to use the BootstrapVue table helper components, rather than native browser table child elements.

Name and IDType 1Type 2Type 3
NameIDType 1Type 2AType 2BType 2CType 3
Stephen Hawking1falsetruefalsefalsefalse
Johnny Appleseed2falsetruetruefalsefalse
George Washington3falsefalsefalsefalsetrue
Albert Einstein4truefalsefalsetruefalse
Isaac Newton5truetruefalsetruefalse
HTML
vue
<template>
  <div>
    <BTable :items="items" :fields="fields" responsive="sm">
      <template #thead-top>
        <BTr>
          <BTh colspan="2"><span class="visually-hidden">Name and ID</span></BTh>
          <BTh variant="secondary">Type 1</BTh>
          <BTh variant="primary" colspan="3">Type 2</BTh>
          <BTh variant="danger">Type 3</BTh>
        </BTr>
      </template>
    </BTable>
  </div>
</template>

<script setup lang="ts">
const items = [
  {
    name: 'Stephen Hawking',
    id: 1,
    type1: false,
    type2a: true,
    type2b: false,
    type2c: false,
    type3: false,
  },
  {
    name: 'Johnny Appleseed',
    id: 2,
    type1: false,
    type2a: true,
    type2b: true,
    type2c: false,
    type3: false,
  },
  {
    name: 'George Washington',
    id: 3,
    type1: false,
    type2a: false,
    type2b: false,
    type2c: false,
    type3: true,
  },
  {
    name: 'Albert Einstein',
    id: 4,
    type1: true,
    type2a: false,
    type2b: false,
    type2c: true,
    type3: false,
  },
  {
    name: 'Isaac Newton',
    id: 5,
    type1: true,
    type2a: true,
    type2b: false,
    type2c: true,
    type3: false,
  },
]
const fields = [
  'name',
  {key: 'id', label: 'ID'},
  {key: 'type1', label: 'Type 1'},
  {key: 'type2a', label: 'Type 2A'},
  {key: 'type2b', label: 'Type 2B'},
  {key: 'type2c', label: 'Type 2C'},
  {key: 'type3', label: 'Type 3'},
]
</script>

Slot thead-top can be optionally scoped, receiving an object with the following properties:

PropertyTypeDescription
columnsnumberThe number of columns in the rendered table
fieldsTableField<Items>[]Array of field definition objects (normalized to the array of objects format)
selectAllRows() => voidSelect all rows (applicable if the table is in selectable mode
clearSelected() => voidUnselect all rows (applicable if the table is in selectable mode

If you need greater layout control of the content of the <tfoot>, you can use the optionally scoped slot custom-foot to provide your own rows and cells. Use BootstrapVue's table helper sub-components <BTr>, <BTh>, and <BTd> to generate your custom footer layout.

Slot custom-foot can be optionally scoped, receiving an object with the following properties:

PropertyTypeDescription
columnsnumberThe number of columns in the rendered table
fieldsTableField<Items>[]Array of field definition objects (normalized to the array of objects format)
itemsreadonly Items[]Array of the currently displayed items records - after filtering, sorting and pagination

Notes:

  • The custom-foot slot will not be rendered if the foot-clone prop has been set.
  • head-clicked events are not be emitted when clicking on custom-foot cells.
  • Sorting and sorting icons are not available for cells in the custom-foot slot.
  • The custom footer will not be shown when the table is in visually stacked mode.

Custom empty and empty-filtered rendering via slots

Aside from using empty-text, empty-filtered-text, it is also possible to provide custom rendering for tables that have no data to display using named slots.

In order for these slots to be shown, the show-empty attribute must be set and items must be either falsy or an array of length 0.

template
<BTable :fields="fields" :items="items" show-empty>
  <template #empty="scope">
    <h4>{{ scope.emptyText }}</h4>
  </template>
  <template #empty-filtered="scope">
    <h4>{{ scope.emptyFilteredText }}</h4>
  </template>
</BTable>

The slot can optionally be scoped. The slot's scope (scope in the above example) will have the following properties:

PropertyTypeDescription
emptyFilteredHtmlstringThe empty-filtered-html prop
emptyFilteredTextstringThe empty-filtered-text prop
fieldsTableField<Items>[]The fields prop
itemsItems[]The items prop. Exposed here to check null vs []

NOTE

If you prefiously used the emptyHtml or emtpyFilteredHtml scoped slots or the empty-html or empty-filtered-html props, please convert to using the empty-text or empty-filtered-text slots instead. See our migration guide for details.

Advanced Features

To Be Completed

Sticky headers

Sticky columns

Row details support

Row select support

Table body transition support

v-model binding

Sorting

As mentioned in the Fields section above, you can make columns sortable in <BTable>. Clicking on a sortable column header will sort the column in ascending direction (smallest first), while clicking on it again will switch the direction of sorting to descending (largest first). Clicking on it a third time will stop sorting on the column. For single column sorting (e.g. multisort===false) clicking on a differnt sortable column header will sort that column in ascending order and clear the sort order for the previously sorted column.

You can control which column is pre-sorted and the order of sorting (ascending or descending). To pre-specify the column to be sorted use the sortBy model. For single column sorting (e.g. multisort===false) sortBy should be an array containing a single BTableSortBy object.

ts
type BTableSortBy = {
  order: BTableSortByOrder // Sort order can by 'asc', 'desc' or undefined
  key: string // The field name to sort by
  comparer?: (a: string, b: string) => number
}
  • Ascending: Items are sorted lowest to highest (i.e. A to Z) and will be displayed with the lowest value in the first row with progressively higher values in the following rows.
  • Descending: Items are sorted highest to lowest (i.e. Z to A) and will be displayed with the highest value in the first row with progressively lower values in the following rows.

By default the comparer function does a numeric localeCompare. If one wishes to change this, use a custom comparer function with that BTableSortBy element.

To prevent the table from wiping out the comparer function, internally it will set the order key to undefined, instead of just removing the element from the sortBy array. i.e. :sort-by="[]" & :sort-by="[key: 'someKey', order: undefined]" behave identically. Naturally if this value is given to a server, orders of undefined should be handled.

Last NameFirst NameAgeIs Active
MacdonaldZelda45true
ShawLarsen21false
CarneyJami38true
WilsonGeneva89false
WilsonGary89false
MacdonaldDickerson40true
HTML
vue
<template>
  <BTable :sort-by="[{key: 'first_name', order: 'desc'}]" :items="items" :fields="fields" />
</template>

<script setup lang="ts">
import {type TableFieldRaw, type TableItem} from 'bootstrap-vue-next'

interface SortPerson {
  first_name: string
  last_name: string
  age: number
  isActive: boolean
}

const items: TableItem<SortPerson>[] = [
  {isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {isActive: true, age: 45, first_name: 'Zelda', last_name: 'Macdonald'},
  {isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {isActive: false, age: 89, first_name: 'Gary', last_name: 'Wilson'},
  {isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney'},
]

const fields: Exclude<TableFieldRaw<SortPerson>, string>[] = [
  {key: 'last_name', sortable: true},
  {key: 'first_name', sortable: true},
  {key: 'age', sortable: true},
  {key: 'isActive', sortable: false},
]
</script>

sorbBy is a named model so it can be bound to an object that will be updated with the current sort state when the user changes sorting by clicking the headers.

Last NameFirst NameAgeIs Active
MacdonaldZelda45true
ShawLarsen21false
CarneyJami38true
WilsonGeneva89false
WilsonGary89false
MacdonaldDickerson40true
sortBy = [{"key":"first_name","order":"desc"}]
HTML
vue
<template>
  <BTable v-model:sort-by="sortBy" :items="items" :fields="fields" />
  <div>sortBy = {{ JSON.stringify(sortBy) }}</div>
</template>

<script setup lang="ts">
import {type BTableSortBy, type TableFieldRaw, type TableItem} from 'bootstrap-vue-next'
import {ref} from 'vue'

interface SortPerson {
  first_name: string
  last_name: string
  age: number
  isActive: boolean
}

const items: TableItem<SortPerson>[] = [
  {isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {isActive: true, age: 45, first_name: 'Zelda', last_name: 'Macdonald'},
  {isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {isActive: false, age: 89, first_name: 'Gary', last_name: 'Wilson'},
  {isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney'},
]

const fields: TableFieldRaw<SortPerson>[] = [
  {key: 'last_name', sortable: true},
  {key: 'first_name', sortable: true},
  {key: 'age', sortable: true},
  {key: 'isActive', sortable: false},
]

const sortBy = ref<BTableSortBy[]>([{key: 'first_name', order: 'desc'}])
</script>

Tables can be sorted by multiple columns. Programmaticly, this can be done by adding more entries to the sortBy array. From the user inteface, multi-sort works as follows:

  • Clicking on a sortable header that isn't currently sorted adds it as ascending to the end of the sortBy list
  • Clicking on a sortable header that is currently sorted as ascending makes it descending, but leaves it in the same order in the sortBy list
  • Clicking on a sortable header that is currently sorted as descending will set the order to undefined. If must-sort is true OR if mustSort is an array that contains that columns key, it will skip to be ascending
Last NameFirst NameAgeIs Active
CarneyJami38true
MacdonaldDickerson40true
MacdonaldZelda45true
ShawLarsen21false
WilsonGary89false
WilsonGeneva89false
sortBy = [{"key":"last_name","order":"asc"},{"key":"first_name","order":"asc"}]
HTML
vue
<template>
  <BTable v-model:sort-by="multiSortBy" :items="sortItems" :fields="sortFields" :multisort="true" />
  <div>sortBy = {{ JSON.stringify(multiSortBy) }}</div>
</template>

<script setup lang="ts">
import {ref} from 'vue'
import {type BTableSortBy, type TableFieldRaw, type TableItem} from 'bootstrap-vue-next'

interface SortPerson {
  first_name: string
  last_name: string
  age: number
  isActive: boolean
}

const sortItems: TableItem<SortPerson>[] = [
  {isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald'},
  {isActive: true, age: 45, first_name: 'Zelda', last_name: 'Macdonald'},
  {isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw'},
  {isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson'},
  {isActive: false, age: 89, first_name: 'Gary', last_name: 'Wilson'},
  {isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney'},
]

const sortFields: TableFieldRaw<SortPerson>[] = [
  {key: 'last_name', sortable: true},
  {key: 'first_name', sortable: true},
  {key: 'age', sortable: true},
  {key: 'isActive', sortable: false},
]

const multiSortBy = ref<BTableSortBy[]>([
  {key: 'last_name', order: 'asc'},
  {key: 'first_name', order: 'asc'},
])
</script>

Change initial sort direction

Filtering

To Be Completed

Pagination

To Be Completed

Using items provider functions

To Be Completed

Light-weight tables

To Be Completed

Simple tables

The BTableSimple component gives the user complete control over the rendering of the table content, while providing basic Bootstrap v5 table styling. BTableSimple is a wrapper component around the <table> element. Inside the component, via the default slot, you can use any or all of the BootstrapVueNext table helper components: BThead, BTfoot, BTbody, BTr, BTh, BTd, and the HTML5 elements <caption>, <colgroup> and <col>. Contrary to the component's name, one can create simple or complex table layouts with BTableSimple.

BTableSimple provides basic styling options via props: striped, bordered, borderless, outlined, small, hover, dark, fixed, responsive and sticky-header. Note that stacked mode is available but requires some additional markup to generate the cell headings, as described in the Simple tables and stacked mode section below. Sticky columns are also supported, but also require a bit of additional markup to specify which columns are to be sticky. See below for more information on using sticky columns.

Since b-table-simple is just a wrapper component, of which you will need to render content inside, it does not provide any of the advanced features of BTable (i.e. row events, head events, sorting, pagination, filtering, foot-clone, items, fields, etc.).

Items sold in August, grouped by Country and City:
RegionClothesAccessories
CountryCityTrousersSkirtsDressesBraceletsRings
BelgiumAntwerp5622437223
Gent4618506115
Brussels5127386928
The NetherlandsAmsterdam8934698538
Utrecht8012433619
Total Rows: 5
HTML
template
<BTableSimple hover small caption-top responsive>
  <caption>
    Items sold in August, grouped by Country and City:
  </caption>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <colgroup>
    <col />
    <col />
    <col />
  </colgroup>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <BThead variant="dark">
    <BTr>
      <BTh colspan="2">Region</BTh>
      <BTh colspan="3">Clothes</BTh>
      <BTh colspan="2">Accessories</BTh>
    </BTr>
    <BTr>
      <BTh>Country</BTh>
      <BTh>City</BTh>
      <BTh>Trousers</BTh>
      <BTh>Skirts</BTh>
      <BTh>Dresses</BTh>
      <BTh>Bracelets</BTh>
      <BTh>Rings</BTh>
    </BTr>
  </BThead>
  <BTbody>
    <BTr>
      <BTh rowspan="3">Belgium</BTh>
      <BTh class="text-end">Antwerp</BTh>
      <BTd>56</BTd>
      <BTd>22</BTd>
      <BTd>43</BTd>
      <BTd variant="success">72</BTd>
      <BTd>23</BTd>
    </BTr>
    <BTr>
      <BTh class="text-end">Gent</BTh>
      <BTd>46</BTd>
      <BTd variant="warning">18</BTd>
      <BTd>50</BTd>
      <BTd>61</BTd>
      <BTd variant="danger">15</BTd>
    </BTr>
    <BTr>
      <BTh class="text-end">Brussels</BTh>
      <BTd>51</BTd>
      <BTd>27</BTd>
      <BTd>38</BTd>
      <BTd>69</BTd>
      <BTd>28</BTd>
    </BTr>
    <BTr>
      <BTh rowspan="2">The Netherlands</BTh>
      <BTh class="text-end">Amsterdam</BTh>
      <BTd variant="success">89</BTd>
      <BTd>34</BTd>
      <BTd>69</BTd>
      <BTd>85</BTd>
      <BTd>38</BTd>
    </BTr>
    <BTr>
      <BTh class="text-end">Utrecht</BTh>
      <BTd>80</BTd>
      <BTd variant="danger">12</BTd>
      <BTd>43</BTd>
      <BTd>36</BTd>
      <BTd variant="warning">19</BTd>
    </BTr>
  </BTbody>
  <BTfoot>
    <BTr>
      <BTd colspan="7" variant="secondary" class="text-end"> Total Rows: <b>5</b> </BTd>
    </BTr>
  </BTfoot>
</BTableSimple>

When in responsive or sticky-header mode, the <table> element is wrapped inside a <div> element. If you need to apply additional classes or attributes to the <table> element, use the table-classes and table-attrs, respectively.

Simple tables and stacked mode

A bit of additional markup is required on your BTableSimple body cells when the table is in stacked mode. Specifically, BootstrapVueNext uses a special data attribute to create the cell's heading, of which you can supply to BTd or BTh via the stacked-heading prop. Only plain strings are supported (not HTML markup), as we use the pseudo element ::before and css content property.

Here is the same table as above, set to be always stacked, which has the extra markup to handle stacked mode (specifically for generating the cell headings):

Items sold in August, grouped by Country and City:
RegionClothesAccessories
CountryCityTrousersSkirtsDressesBraceletsRings
Belgium (3 Cities)
Antwerp
56
22
43
72
23
Gent
46
18
50
61
15
Brussels
51
27
38
69
28
The Netherlands (2 Cities)
Amsterdam
89
34
69
85
38
Utrecht
80
12
43
36
19
Total Rows: 5
HTML
template
<BTableSimple hover small caption-top stacked>
  <caption>
    Items sold in August, grouped by Country and City:
  </caption>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <colgroup>
    <col />
    <col />
    <col />
  </colgroup>
  <colgroup>
    <col />
    <col />
  </colgroup>
  <BThead variant="dark">
    <BTr>
      <BTh colspan="2">Region</BTh>
      <BTh colspan="3">Clothes</BTh>
      <BTh colspan="2">Accessories</BTh>
    </BTr>
    <BTr>
      <BTh>Country</BTh>
      <BTh>City</BTh>
      <BTh>Trousers</BTh>
      <BTh>Skirts</BTh>
      <BTh>Dresses</BTh>
      <BTh>Bracelets</BTh>
      <BTh>Rings</BTh>
    </BTr>
  </BThead>
  <BTbody>
    <BTr>
      <BTh rowspan="3" class="text-center">Belgium (3 Cities)</BTh>
      <BTh stacked-heading="City" class="text-start">Antwerp</BTh>
      <BTd stacked-heading="Clothes: Trousers">56</BTd>
      <BTd stacked-heading="Clothes: Skirts">22</BTd>
      <BTd stacked-heading="Clothes: Dresses">43</BTd>
      <BTd stacked-heading="Accessories: Bracelets" variant="success">72</BTd>
      <BTd stacked-heading="Accessories: Rings">23</BTd>
    </BTr>
    <BTr>
      <BTh stacked-heading="City">Gent</BTh>
      <BTd stacked-heading="Clothes: Trousers">46</BTd>
      <BTd stacked-heading="Clothes: Skirts" variant="warning">18</BTd>
      <BTd stacked-heading="Clothes: Dresses">50</BTd>
      <BTd stacked-heading="Accessories: Bracelets">61</BTd>
      <BTd stacked-heading="Accessories: Rings" variant="danger">15</BTd>
    </BTr>
    <BTr>
      <BTh stacked-heading="City">Brussels</BTh>
      <BTd stacked-heading="Clothes: Trousers">51</BTd>
      <BTd stacked-heading="Clothes: Skirts">27</BTd>
      <BTd stacked-heading="Clothes: Dresses">38</BTd>
      <BTd stacked-heading="Accessories: Bracelets">69</BTd>
      <BTd stacked-heading="Accessories: Rings">28</BTd>
    </BTr>
    <BTr>
      <BTh rowspan="2" class="text-center">The Netherlands (2 Cities)</BTh>
      <BTh stacked-heading="City">Amsterdam</BTh>
      <BTd stacked-heading="Clothes: Trousers" variant="success">89</BTd>
      <BTd stacked-heading="Clothes: Skirts">34</BTd>
      <BTd stacked-heading="Clothes: Dresses">69</BTd>
      <BTd stacked-heading="Accessories: Bracelets">85</BTd>
      <BTd stacked-heading="Accessories: Rings">38</BTd>
    </BTr>
    <BTr>
      <BTh stacked-heading="City">Utrecht</BTh>
      <BTd stacked-heading="Clothes: Trousers">80</BTd>
      <BTd stacked-heading="Clothes: Skirts" variant="danger">12</BTd>
      <BTd stacked-heading="Clothes: Dresses">43</BTd>
      <BTd stacked-heading="Accessories: Bracelets">36</BTd>
      <BTd stacked-heading="Accessories: Rings" variant="warning">19</BTd>
    </BTr>
  </BTbody>
  <BTfoot>
    <BTr>
      <BTd colspan="7" variant="secondary" class="text-end"> Total Rows: <b>5</b> </BTd>
    </BTr>
  </BTfoot>
</BTableSimple>

Like BTable and BTableLite, table headers (<thead>) and footers (<tfoot>) are visually hidden when the table is visually stacked. If you need a header or footer, you can do so by creating an extra BTr inside of the BTbody component (or in a second BTbody component), and set a role of columnheader on the child BTh cells, and use Bootstrap v5 responsive display utility classes to hide the extra row (or BTbody) above a certain breakpoint when the table is no longer visually stacked (the breakpoint should match the stacked table breakpoint you have set), i.e. <BTr class="d-md-none"> would hide the row on medium and wider screens, while <BTbody class="d-md-none"> would hide the row group on medium and wider screens.

NOTE

Note: stacked mode with BTableSimple requires that you use the BootstrapVueNext table helper components. Use of the regular <tbody>, <tr>, <td> and <th> element tags will not work as expected, nor will they automatically apply any of the required accessibility attributes.

Simple tables and sticky columns

Sticky columns are supported with BTableSimple, but you will need to set the sticky-column prop on each table cell (in the thead, tbody, and tfoot row groups) in the column that is to be sticky. For example:

template
<BTableSimple responsive>
  <BThead>
    <BTr>
      <BTh sticky-column>Sticky Column Header</BTh>
      <BTh>Heading 1</BTh>
      <BTh>Heading 2</BTh>
      <BTh>Heading 3</BTh>
      <BTh>Heading 4</BTh>
    </BTr>
  </BThead>
  <BTbody>
    <BTr>
      <BTh sticky-column>Sticky Column Row Header</BTh>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
    </BTr>
    <BTr>
      <BTh sticky-column>Sticky Column Row Header</BTh>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
      <BTd>Cell</BTd>
    </BTr>
  </BTbody>
  <BTfoot>
    <BTr>
      <BTh sticky-column>Sticky Column Footer</BTh>
      <BTh>Heading 1</BTh>
      <BTh>Heading 2</BTh>
      <BTh>Heading 3</BTh>
      <BTh>Heading 4</BTh>
    </BTr>
  </BTfoot>
</BTableSimple>

As with BTable and BTableLite, sticky columns are not supported when the stacked prop is set on BTableSimple.

Table Helper Components

To Be Completed

Complete Example

Filter On
Leave all unchecked to filter on all data
Person full namePerson sortable namePerson ageIs ActiveActions
Dickerson MacdonaldMacdonald, Dickerson40Yes
Larsen ShawShaw, Larsen21No
Mini NavarroNavarro, Mini9No
Geneva WilsonWilson, Geneva89No
Jami CarneyCarney, Jami38Yes
HTML
vue
<template>
  <BContainer class="py-5">
    <!-- User Interface controls -->
    <BRow>
      <BCol lg="6" class="my-1">
        <BFormGroup
          v-slot="{ariaDescribedby}"
          label="Sort"
          label-for="sort-by-select"
          label-cols-sm="3"
          label-align-sm="right"
          label-size="sm"
          class="mb-0"
        >
          <BButton size="sm" @click="onAddSort">Add Sort...</BButton>
          <BInputGroup v-for="sort in sortBy" :key="sort.key" size="sm">
            <BFormSelect
              id="sort-by-select"
              v-model="sort.key"
              :options="sortOptions"
              :aria-describedby="ariaDescribedby"
              class="w-75"
            >
              <template #first>
                <option value="">-- none --</option>
              </template>
            </BFormSelect>
            <BFormSelect
              v-model="sort.order"
              :disabled="!sortBy"
              :aria-describedby="ariaDescribedby"
              size="sm"
              class="w-25"
            >
              <option value="asc">Asc</option>
              <option value="desc">Desc</option>
            </BFormSelect>
          </BInputGroup>
        </BFormGroup>
      </BCol>
      <BCol lg="6" class="my-1">
        <BFormGroup
          label="Filter"
          label-for="filter-input"
          label-cols-sm="3"
          label-align-sm="right"
          label-size="sm"
          class="mb-0"
        >
          <BInputGroup size="sm">
            <BFormInput
              id="filter-input"
              v-model="filter"
              type="search"
              placeholder="Type to Search"
            />
            <BInputGroupText>
              <BButton :disabled="!filter" @click="filter = ''">Clear</BButton>
            </BInputGroupText>
          </BInputGroup>
        </BFormGroup>
      </BCol>
      <BCol lg="6" class="my-1">
        <BFormGroup
          v-slot="{ariaDescribedby}"
          v-model="sortDirection"
          label="Filter On"
          description="Leave all unchecked to filter on all data"
          label-cols-sm="3"
          label-align-sm="right"
          label-size="sm"
          class="mb-0"
        >
          <div class="d-flex gap-2">
            <BFormCheckbox v-model="filterOn" value="name" :aria-describedby="ariaDescribedby"
              >Name</BFormCheckbox
            >
            <BFormCheckbox v-model="filterOn" value="age" :aria-describedby="ariaDescribedby"
              >Age</BFormCheckbox
            >
            <BFormCheckbox v-model="filterOn" value="isActive" :aria-describedby="ariaDescribedby"
              >Active</BFormCheckbox
            >
          </div>
        </BFormGroup>
      </BCol>
      <BCol sm="5" md="6" class="my-1">
        <BFormGroup
          label="Per page"
          label-for="per-page-select"
          label-cols-sm="6"
          label-cols-md="4"
          label-cols-lg="3"
          label-align-sm="right"
          label-size="sm"
          class="mb-0"
        >
          <BFormSelect id="per-page-select" v-model="perPage" :options="pageOptions" size="sm" />
        </BFormGroup>
      </BCol>
      <BCol sm="7" md="6" class="my-1">
        <BPagination
          v-model="currentPage"
          :total-rows="totalRows"
          :per-page="perPage"
          :align="'fill'"
          size="sm"
          class="my-0"
        />
      </BCol>
    </BRow>
    <!-- Main table element for typed table-->
    <BTable
      v-model:sort-by="sortBy"
      :sort-internal="true"
      :items="items"
      :fields="fields"
      :current-page="currentPage"
      :per-page="perPage"
      :filter="filter"
      :responsive="false"
      :filterable="filterOn"
      :small="true"
      :multisort="true"
      @filtered="onFiltered"
    >
      <template #cell(name)="row">
        {{ (row.value as PersonName).first }}
        {{ (row.value as PersonName).last }}
      </template>
      <template #cell(actions)="row">
        <BButton size="sm" class="me-1" @click="info(row.item, row.index)"> Info modal </BButton>
        <BButton size="sm" @click="row.toggleDetails">
          {{ row.detailsShowing ? 'Hide' : 'Show' }} Details
        </BButton>
      </template>
      <template #row-details="row">
        <BCard>
          <ul>
            <li v-for="(value, key) in row.item" :key="key">{{ key }}: {{ value }}</li>
            <BButton size="sm" @click="row.toggleDetails"> Toggle Details </BButton>
          </ul>
        </BCard>
      </template>
    </BTable>
    <!-- Info modal -->
    <BModal
      :id="infoModal.id"
      v-model="infoModal.open"
      :title="infoModal.title"
      :ok-only="true"
      @hide="resetInfoModal"
    >
      <pre>{{ infoModal.content }}</pre>
    </BModal>
  </BContainer>
</template>

<script setup lang="ts">
import {
  type BTableSortBy,
  type ColorVariant,
  type LiteralUnion,
  type TableFieldRaw,
  type TableItem,
} from 'bootstrap-vue-next'
import {computed, reactive, ref} from 'vue'

interface PersonName {
  first: string
  last: string
}

interface Person {
  name: PersonName
  age: number
  isActive: boolean
}

const items: TableItem<Person>[] = [
  {isActive: true, age: 40, name: {first: 'Dickerson', last: 'Macdonald'}},
  {isActive: false, age: 21, name: {first: 'Larsen', last: 'Shaw'}},
  {
    isActive: false,
    age: 9,
    name: {first: 'Mini', last: 'Navarro'},
    _rowVariant: 'success' as ColorVariant,
  },
  {isActive: false, age: 89, name: {first: 'Geneva', last: 'Wilson'}},
  {isActive: true, age: 38, name: {first: 'Jami', last: 'Carney'}},
  {isActive: false, age: 27, name: {first: 'Essie', last: 'Dunlap'}},
  {isActive: true, age: 40, name: {first: 'Thor', last: 'Macdonald'}},
  {
    isActive: true,
    age: 87,
    name: {first: 'Larsen', last: 'Shaw'},
    _cellVariants: {age: 'danger', isActive: 'warning'},
  },
  {isActive: false, age: 26, name: {first: 'Mitzi', last: 'Navarro'}},
  {isActive: false, age: 22, name: {first: 'Genevieve', last: 'Wilson'}},
  {isActive: true, age: 38, name: {first: 'John', last: 'Carney'}},
  {isActive: false, age: 29, name: {first: 'Dick', last: 'Dunlap'}},
]

const fields: Exclude<TableFieldRaw<Person>, string>[] = [
  {
    key: 'name',
    label: 'Person full name',
    sortable: true,
    sortDirection: 'desc',
  },
  {
    key: 'sortableName',
    label: 'Person sortable name',
    sortable: true,
    sortDirection: 'desc',
    formatter: (_value: unknown, _key?: LiteralUnion<keyof Person>, item?: Person) =>
      item ? `${item.name.last}, ${item.name.first}` : 'Something went wrong',
    sortByFormatted: true,
    filterByFormatted: true,
  },
  {key: 'age', label: 'Person age', sortable: true, class: 'text-center'},
  {
    key: 'isActive',
    label: 'Is Active',
    formatter: (value: unknown) => (value ? 'Yes' : 'No'),
    sortable: true,
    sortByFormatted: true,
    filterByFormatted: true,
  },
  {key: 'actions', label: 'Actions'},
]

const pageOptions = [
  {value: 5, text: '5'},
  {value: 10, text: '10'},
  {value: 15, text: '15'},
  {value: 100, text: 'Show a lot'},
]

const totalRows = ref(items.length)
const currentPage = ref(1)
const perPage = ref(5)
const sortBy = ref<BTableSortBy[]>([])
const sortDirection = ref('asc')
const filter = ref('')
const filterOn = ref([])
const infoModal = reactive({
  open: false,
  id: 'info-modal',
  title: '',
  content: '',
})

// Create an options list from our fields
const sortOptions = computed(() =>
  fields.filter((f) => f.sortable).map((f) => ({text: f.label, value: f.key}))
)

function info(item: TableItem<Person>, index: number) {
  infoModal.title = `Row index: ${index}`
  infoModal.content = JSON.stringify(item, null, 2)
  infoModal.open = true
}

function resetInfoModal() {
  infoModal.title = ''
  infoModal.content = ''
}

function onFiltered(filteredItems: TableItem<Person>[]) {
  // Trigger pagination to update the number of buttons/pages due to filtering
  totalRows.value = filteredItems.length
  currentPage.value = 1
}

function onAddSort() {
  sortBy.value.push({key: '', order: 'asc'})
}
</script>

Component Reference

PropTypeDefaultDescription
busybooleanfalse
busy-loading-textstring'Loading...'
current-pageNumberish1
empty-filtered-textstring'There are no records matching your request' Text to display when no items are present in the `items` array after filtering
empty-textstring'There are no records to show' Text to display when no items are present in the `items` array
filterstringundefined
filter-function(item: Readonly<Items>, filter: string | undefined) => booleanundefined Function called during filtering of items, gets passed the current item being filtered
filterablestring[]undefined
multisortbooleanfalse
must-sortboolean | string[]false
no-local-sortingbooleanfalse
no-providerNoProviderTypes[]undefined
no-provider-filteringbooleanfalse
no-provider-pagingbooleanfalse
no-provider-sortingbooleanfalse
no-select-on-clickbooleanfalse Do not select row when clicked
no-sortable-iconbooleanfalse
per-pageNumberishnull
providerBTableProviderundefined
select-headboolean | stringtrue
select-mode'multi' | 'single' | 'range''multi'
selectablebooleanfalse
selected-itemsTableItem[]undefined
selection-variantColorVariant | null'primary'
show-emptybooleanfalse Show the empty text when no items are present in the `items` array
sort-byBTableSortBy[]undefined Model representing the current sort state
sticky-selectbooleanfalse
Extensions:
EventArgsDescription
headClicked
key: TableField<Record<string, unknown>>.key: LiteralUnion<string, string>
field: TableField
event: MouseEvent
is-footer: boolean
rowClicked
item: TableItem
index: number
event: MouseEvent
rowDblClicked
item: TableItem
index: number
event: MouseEvent
rowHovered
item: TableItem
index: number
event: MouseEvent
rowSelected
row-selected: TableItem
rowUnhovered
item: TableItem
index: number
event: MouseEvent
rowUnselected
row-unselected: TableItem
selection
selection: TableItem[]
sorted
value: BTableSortBy
Updated when the user clicks a sortable column heading and represents the column click and the sort state (`asc`, `desc`, or undefined)
update:sortBy
value: string - BTableSortBy[] | undefined
Emitted when the `sortBy` model is changed and represents the current sort state
NameScopeDescription
custom-foot
default
emptyContent to display when no items are present in the `items` array
empty-filteredContent to display when no items are present in the `items` array after filtering
row-details
select-head
selectCell
table-busy
table-caption
table-caption
thead-sub
thead-top
<BTableLite>
PropTypeDefaultDescription
alignVerticalAlignundefined
captionstringundefined
details-td-classClassValueundefined
field-column-class(field: TableField) => Record<string, any>[] | string | Record<PropertyKey, any> | any[]undefined
fieldsTableFieldRaw[]'() => []'
foot-clonebooleanfalse
foot-row-variantColorVariant | nullundefined
foot-variantColorVariant | nullundefined
head-row-variantColorVariant | nullundefined
head-variantColorVariant | nullundefined
itemsTableItem[]'() => []'
label-stackedbooleanfalse
model-valueanyundefined
primary-keystringundefined
tbody-classClassValueundefined
tbody-tr-attrsClassValueundefined
tbody-tr-class((item: TableItem | null, type: string) => string | any[] | null | undefined) | string | Record<PropertyKey, any> | any[]undefined
tfoot-classClassValueundefined
tfoot-tr-classClassValueundefined
thead-classClassValueundefined
thead-tr-classClassValueundefined
Extensions:
<BTableSimple>
PropTypeDefaultDescription
border-variantColorVariant | nullnull Applies one of the Bootstrap theme color variants to the table border
borderedbooleanfalse Adds borders to all the cells and headers
borderlessbooleanfalse Removes all borders from cells
caption-topbooleanfalse When set, the table caption will appear above the table
darkbooleanfalse Places the table in dark mode
fixedbooleanfalse Makes all columns equal width (fixed layout table). Will speed up rendering for large tables. Column widths can be set via CSS or colgroup
hoverbooleanfalse Enables hover styling on rows
idstringundefined Used to set the `id` attribute on the rendered content, and used as the base to generate any additional element IDs as needed
no-border-collapsebooleanfalse Disable's the collapsing of table borders. Useful when table has sticky headers or columns
outlinedbooleanfalse Adds an outline border to the table element
responsiveboolean | Breakpointfalse Makes the table responsive in width, adding a horizontal scrollbar. Set to true for always responsive or set to one of the breakpoints to switch from responsive to normal: 'sm', 'md', 'lg', 'xl'
smallbooleanfalse Renders the table with smaller cell padding
stackedboolean | Breakpointfalse Place the table in stacked mode. Set to true for always stacked, or set to one of the breakpoints to switch from stacked to normal: 'sm', 'md', 'lg', 'xl'
sticky-headerboolean | Numberishfalse Makes the table header sticky. Set to true for a maximum height 300px tall table, or set to any valid CSS height (including units). Inputting a number type is converted to px height
stripedbooleanfalse Applies striping to the tbody rows
striped-columnsbooleanfalse Applies striping to the table columns
table-attrsAttrsValueundefined Attributes to apply to the table element
table-classClassValueundefined Classes to apply to the table element
variantColorVariant | nullnull Applies one of the Bootstrap theme color variants to the component. When implemented `bg-variant` and `text-variant` will take precedence
NameScopeDescription
defaultContent to place in the table
PropTypeDefaultDescription
variantColorVariantnull
NameScopeDescription
default
PropTypeDefaultDescription
colspanstring | numberundefined
rowspanstring | numberundefined
stacked-headingstringundefined
sticky-columnbooleanfalse
variantColorVariant | nullnull
NameScopeDescription
default
PropTypeDefaultDescription
variantColorVariant | nullnull
NameScopeDescription
default
PropTypeDefaultDescription
colspanstring | numberundefined
rowspanstring | numberundefined
stacked-headingstringundefined
sticky-columnbooleanfalse
variantColorVariant | nullnull
NameScopeDescription
default
PropTypeDefaultDescription
variantColorVariantnull
NameScopeDescription
default
PropTypeDefaultDescription
variantColorVariantnull
NameScopeDescription
default