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
Age | First name | Last name |
---|---|---|
40 | Dickerson | Macdonald |
21 | Larsen | Shaw |
89 | Geneva | Wilson |
38 | Jami | Carney |
<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:
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
becomesFirst Name
last-name
becomesLast Name
age
becomesAge
YEAR
remainsYEAR
isActive
becomesIs 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):
Property | Type | Description |
---|---|---|
_cellVariants | Partial<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). |
_rowVariant | ColorVariant | Bootstrap 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) |
_showDetails | boolean | Used 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
Age | First name | Last name |
---|---|---|
40 | Dickerson | Macdonald |
21 | Larsen | Shaw |
89 | Geneva | Wilson |
40 | Thor | MacDonald |
29 | Dick | Dunlap |
<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
(orundefined
) 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 name | Last name | Age |
---|---|---|
Dickerson | Macdonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
Jami | Carney | 38 |
<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 Name | First Name | Person age |
---|---|---|
Macdonald | Dickerson | 40 |
Shaw | Larsen | 21 |
Wilson | Geneva | 89 |
Carney | Jami | 38 |
<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:
Property | Type | Description |
---|---|---|
key | LiteralUnion<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. |
label | string | Appears 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. |
headerTitle | string | Text to place on the fields header <th> attribute title . Defaults to no title attribute. |
headerAbbr | string | Text 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. |
class | ClassValue | Class name (or array of class names) to add to <th> and <td> in the column. |
formatter | TableFieldFormatter<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. |
sortable | boolean | Enable sorting on this column. Refer to the Sorting Section for more details. |
sortDirection | string | Set 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 |
sortByFormatted | boolean | 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. |
filterByFormatted | boolean | 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. |
tdClass | TableStrictClassValue | ((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. |
thClass | ClassValue | Class name (or array of class names) to add to this field's <thead> /<tfoot> heading <th> cell. |
thStyle | StyleValue | CSS styles you would like to apply to the table <thead> /<tfoot> field <th> cell. |
variant | ColorVariant | null | Apply contextual class to all the <th> and <td> in the column. |
tdAttr | AttrsValue | ((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. |
thAttr | AttrsValue | ((value: unknown, key: string, item: T | null, type: TableRowThead) => AttrsValue | Object 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. |
isRowHeader | boolean | When set to true , the field's item data cell will be rendered with <th> rather than the default of <td> . |
stickyColumn | boolean | When 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:
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:
prop | Type | Description |
---|---|---|
striped | boolean | Add zebra-striping to the table rows within the <tbody> |
striped-columns | boolean | Add zebra-striping to the table colums within the <tbody> |
bordered | boolean | For borders on all sides of the table and cells. |
borderless | boolean | removes inner borders from table. |
outlined | boolean | For a thin border on all sides of the table. Has no effect if bordered is set. |
small | boolean | To make tables more compact by cutting cell padding in half. |
hover | boolean | To enable a hover highlighting state on table rows within a <tbody> |
dark | boolean | Invert the colors — with light text on dark backgrounds (equivalent to Bootstrap v5 class .table-dark ) |
fixed | boolean | Generate a table with equal fixed-width columns (table-layout: fixed; ) Not yet implemented |
responsive | boolean | Breakpoint | Generate 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-header | boolean | Numberish | Generates 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. |
stacked | boolean | Breakpoint | Generate 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-top | boolean | Numberish | If 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. |
variant | ColorVariant | null | Give the table an overall theme color variant. |
head-variant | ColorVariant | null | Make the table head a theme color different from the table |
foot-row-variant | ColorVariant | null | Make 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-variant | ColorVariant | null | Make the only the <tr> part of the <head> a specific theme color |
foot-variant | ColorVariant | null | Make 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-clone | boolean | Turns on the table footer, and defaults with the same contents a the table header |
no-footer-sorting | boolean | When 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-collapse | Boolean | Disables 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.
First name | Last name | Age |
---|---|---|
Dickerson | Macdonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
<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:
Property | Type | Description |
---|---|---|
tbody-tr-class | ((item: Items | null, type: TableRowType) => TableStrictClassValue) | TableStrictClassValue | Classes to be applied to every row on the table. |
tbody-tr-attr | ((item: Items | null, type: TableRowType) => AttrsValue) | AttrsValue | Attributes 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 benull
orundefined
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 name | Last name | Age |
---|---|---|
Dickerson | Macdonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
<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
.
Heading1 | Heading2 | Heading3 | Heading4 | Heading5 | Heading6 | Heading7 | Heading8 | Heading9 | Heading10 | Heading11 | Heading12 |
---|---|---|---|---|---|---|---|---|---|---|---|
table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell |
table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell |
table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell | table cell |
<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
andfixed
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 thetable-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
orclass
properties of the field definition object.
- Use
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.
Age | First name | Last name |
---|---|---|
40 | Dickerson | Macdonald |
21 | Larsen | Shaw |
89 | Geneva | Wilson |
<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
andbottom-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 name | Last name | Age |
---|---|---|
Dickerson | Macdonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
<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 name | Last name | Age |
---|---|---|
Dickerson | Macdonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
<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 Thetable-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:
/* Busy table styling */
.table.b-table[aria-busy="true"] {
opacity: 0.55;
}
table-busy slot
First name | Last name | Age |
---|---|---|
Dickerson | MacDonald | 40 |
Larsen | Shaw | 21 |
Geneva | Wilson | 89 |
Jami | Carney | 38 |
<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.
Index | Full Name | Age | Sex | First name and age |
---|---|---|---|---|
1 | DOE, John | 42 | Male | John is 42 years old |
2 | DOE, Jane | 36 | Female | Jane is 36 years old |
3 | KINCADE, Rubin | 73 | Male | Rubin is 73 years old |
4 | PARTRIDGE, Shirley | 62 | Female | Shirley is 62 years old |
<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:
Property | Type | Description |
---|---|---|
index | number | The row number (indexed from zero) relative to the displayed rows |
item | Items | The entire raw record data (i.e. items[index] ) for this row (before any formatter is applied) |
value | unknown | The value for this key in the record (null or undefined if a virtual column), or the output of the field's formatter function |
unformatted | unknown | The 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 |
detailsShowing | boolean | Will be true if the row's row-details scoped slot is visible. See section Row details support below for additional information |
toggleDetails | () => void | Can be called to toggle the visibility of the rows row-details scoped slot. See section Row details support below for additional information |
rowSelected | boolean | Will be true if the row has been selected. See section Row select support for additional information |
selectRow | (index?: number) => void | When called, selects the current row. See section Row select support for additional information |
unselectRow | (index?: number) => void | When 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. Theindex
value will refer to the displayed row number. This number will align with the indexes from the optionalv-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.
Text | Html |
---|---|
This is <i>escaped</i> content | This is raw HTML content |
<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 Name | Age | Sex | Calculated Birth Year |
---|---|---|---|
John Doe | 42 | M | 1983 |
Jane Doe | 36 | F | 1989 |
Rubin Kincade | 73 | M | 1952 |
Shirley Partridge | 62 | F | 1963 |
<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>
Header and Footer custom rendering via scoped slots
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 NAME | Age | Sex |
---|---|---|
John Doe | 42 | Male |
Jane Doe | 36 | Female |
Rubin Kincade | 73 | Male |
Shirley Partridge | 62 | Female |
Full Name | Age | Sex |
<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:
Property | Type | Description |
---|---|---|
column | LiteralUnion<keyof Items> | The fields's key value |
field | TableField<Items> | the field's object (from the fields prop) |
label | string | undefined | The fields label value (also available as data.field.label ) |
isFoot | boolean | Currently rending the foot if true |
selectAllRows | () => void | Select all rows (applicable if the table is in selectable mode |
clearSelected | () => void | Unselect 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 ID | Type 1 | Type 2 | Type 3 | |||
---|---|---|---|---|---|---|
Name | ID | Type 1 | Type 2A | Type 2B | Type 2C | Type 3 |
Stephen Hawking | 1 | false | true | false | false | false |
Johnny Appleseed | 2 | false | true | true | false | false |
George Washington | 3 | false | false | false | false | true |
Albert Einstein | 4 | true | false | false | true | false |
Isaac Newton | 5 | true | true | false | true | false |
<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:
Property | Type | Description |
---|---|---|
columns | number | The number of columns in the rendered table |
fields | TableField<Items>[] | Array of field definition objects (normalized to the array of objects format) |
selectAllRows | () => void | Select all rows (applicable if the table is in selectable mode |
clearSelected | () => void | Unselect all rows (applicable if the table is in selectable mode |
Creating a custom footer
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:
Property | Type | Description |
---|---|---|
columns | number | The number of columns in the rendered table |
fields | TableField<Items>[] | Array of field definition objects (normalized to the array of objects format) |
items | readonly Items[] | Array of the currently displayed items records - after filtering, sorting and pagination |
Notes:
- The
custom-foot
slot will not be rendered if thefoot-clone
prop has been set. head-clicked
events are not be emitted when clicking oncustom-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.
<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:
Property | Type | Description |
---|---|---|
emptyFilteredHtml | string | The empty-filtered-html prop |
emptyFilteredText | string | The empty-filtered-text prop |
fields | TableField<Items>[] | The fields prop |
items | Items[] | 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.
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
toZ
) 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
toA
) 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 Name | First Name | Age | Is Active |
---|---|---|---|
Macdonald | Zelda | 45 | true |
Shaw | Larsen | 21 | false |
Carney | Jami | 38 | true |
Wilson | Geneva | 89 | false |
Wilson | Gary | 89 | false |
Macdonald | Dickerson | 40 | true |
<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 Name | First Name | Age | Is Active |
---|---|---|---|
Macdonald | Zelda | 45 | true |
Shaw | Larsen | 21 | false |
Carney | Jami | 38 | true |
Wilson | Geneva | 89 | false |
Wilson | Gary | 89 | false |
Macdonald | Dickerson | 40 | true |
<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
istrue
OR ifmustSort
is an array that contains that columnskey
, it will skip to beascending
Last Name | First Name | Age | Is Active |
---|---|---|---|
Carney | Jami | 38 | true |
Macdonald | Dickerson | 40 | true |
Macdonald | Zelda | 45 | true |
Shaw | Larsen | 21 | false |
Wilson | Gary | 89 | false |
Wilson | Geneva | 89 | false |
<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.).
Region | Clothes | Accessories | ||||
---|---|---|---|---|---|---|
Country | City | Trousers | Skirts | Dresses | Bracelets | Rings |
Belgium | Antwerp | 56 | 22 | 43 | 72 | 23 |
Gent | 46 | 18 | 50 | 61 | 15 | |
Brussels | 51 | 27 | 38 | 69 | 28 | |
The Netherlands | Amsterdam | 89 | 34 | 69 | 85 | 38 |
Utrecht | 80 | 12 | 43 | 36 | 19 | |
Total Rows: 5 |
<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):
Region | Clothes | Accessories | ||||
---|---|---|---|---|---|---|
Country | City | Trousers | Skirts | Dresses | Bracelets | Rings |
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 |
<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:
<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
- «
- ‹
Person full name | Person sortable name | Person age | Is Active | Actions |
---|---|---|---|---|
Dickerson Macdonald | Macdonald, Dickerson | 40 | Yes | |
Larsen Shaw | Shaw, Larsen | 21 | No | |
Mini Navarro | Navarro, Mini | 9 | No | |
Geneva Wilson | Wilson, Geneva | 89 | No | |
Jami Carney | Carney, Jami | 38 | Yes |
<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
<BTable>
Prop | Type | Default | Description |
---|---|---|---|
busy | boolean | false | |
busy-loading-text | string | 'Loading...' | |
current-page | Numberish | 1 | |
empty-filtered-text | string | 'There are no records matching your request' | Text to display when no items are present in the `items` array after filtering |
empty-text | string | 'There are no records to show' | Text to display when no items are present in the `items` array |
filter | string | undefined | |
filter-function | (item: Readonly<Items>, filter: string | undefined) => boolean | undefined | Function called during filtering of items, gets passed the current item being filtered |
filterable | string[] | undefined | |
multisort | boolean | false | |
must-sort | boolean | string[] | false | |
no-local-sorting | boolean | false | |
no-provider | NoProviderTypes[] | undefined | |
no-provider-filtering | boolean | false | |
no-provider-paging | boolean | false | |
no-provider-sorting | boolean | false | |
no-select-on-click | boolean | false | Do not select row when clicked |
no-sortable-icon | boolean | false | |
per-page | Numberish | null | |
provider | BTableProvider | undefined | |
select-head | boolean | string | true | |
select-mode | 'multi' | 'single' | 'range' | 'multi' | |
selectable | boolean | false | |
selected-items | TableItem[] | undefined | |
selection-variant | ColorVariant | null | 'primary' | |
show-empty | boolean | false | Show the empty text when no items are present in the `items` array |
sort-by | BTableSortBy[] | undefined | Model representing the current sort state |
sticky-select | boolean | false |
Event | Args | Description |
---|---|---|
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 |
Name | Scope | Description |
---|---|---|
custom-foot | ||
default | ||
empty | Content to display when no items are present in the `items` array | |
empty-filtered | Content 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>
.table‑lite
Prop | Type | Default | Description |
---|---|---|---|
align | VerticalAlign | undefined | |
caption | string | undefined | |
details-td-class | ClassValue | undefined | |
field-column-class | (field: TableField) => Record<string, any>[] | string | Record<PropertyKey, any> | any[] | undefined | |
fields | TableFieldRaw[] | '() => []' | |
foot-clone | boolean | false | |
foot-row-variant | ColorVariant | null | undefined | |
foot-variant | ColorVariant | null | undefined | |
head-row-variant | ColorVariant | null | undefined | |
head-variant | ColorVariant | null | undefined | |
items | TableItem[] | '() => []' | |
label-stacked | boolean | false | |
model-value | any | undefined | |
primary-key | string | undefined | |
tbody-class | ClassValue | undefined | |
tbody-tr-attrs | ClassValue | undefined | |
tbody-tr-class | ((item: TableItem | null, type: string) => string | any[] | null | undefined) | string | Record<PropertyKey, any> | any[] | undefined | |
tfoot-class | ClassValue | undefined | |
tfoot-tr-class | ClassValue | undefined | |
thead-class | ClassValue | undefined | |
thead-tr-class | ClassValue | undefined |
<BTableSimple>
.table‑simple
Prop | Type | Default | Description |
---|---|---|---|
border-variant | ColorVariant | null | null | Applies one of the Bootstrap theme color variants to the table border |
bordered | boolean | false | Adds borders to all the cells and headers |
borderless | boolean | false | Removes all borders from cells |
caption-top | boolean | false | When set, the table caption will appear above the table |
dark | boolean | false | Places the table in dark mode |
fixed | boolean | false | Makes all columns equal width (fixed layout table). Will speed up rendering for large tables. Column widths can be set via CSS or colgroup |
hover | boolean | false | Enables hover styling on rows |
id | string | undefined | 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-collapse | boolean | false | Disable's the collapsing of table borders. Useful when table has sticky headers or columns |
outlined | boolean | false | Adds an outline border to the table element |
responsive | boolean | Breakpoint | false | 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' |
small | boolean | false | Renders the table with smaller cell padding |
stacked | boolean | Breakpoint | false | 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-header | boolean | Numberish | false | 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 |
striped | boolean | false | Applies striping to the tbody rows |
striped-columns | boolean | false | Applies striping to the table columns |
table-attrs | AttrsValue | undefined | Attributes to apply to the table element |
table-class | ClassValue | undefined | Classes to apply to the table element |
variant | ColorVariant | null | null | Applies one of the Bootstrap theme color variants to the component. When implemented `bg-variant` and `text-variant` will take precedence |
Name | Scope | Description |
---|---|---|
default | Content to place in the table |
<BTbody>
Prop | Type | Default | Description |
---|---|---|---|
variant | ColorVariant | null |
Name | Scope | Description |
---|---|---|
default |
<BTd>
Prop | Type | Default | Description |
---|---|---|---|
colspan | string | number | undefined | |
rowspan | string | number | undefined | |
stacked-heading | string | undefined | |
sticky-column | boolean | false | |
variant | ColorVariant | null | null |
Name | Scope | Description |
---|---|---|
default |
<BTfoot>
Prop | Type | Default | Description |
---|---|---|---|
variant | ColorVariant | null | null |
Name | Scope | Description |
---|---|---|
default |
<BTh>
Prop | Type | Default | Description |
---|---|---|---|
colspan | string | number | undefined | |
rowspan | string | number | undefined | |
stacked-heading | string | undefined | |
sticky-column | boolean | false | |
variant | ColorVariant | null | null |
Name | Scope | Description |
---|---|---|
default |
<BThead>
Prop | Type | Default | Description |
---|---|---|---|
variant | ColorVariant | null |
Name | Scope | Description |
---|---|---|
default |
<BTr>
Prop | Type | Default | Description |
---|---|---|---|
variant | ColorVariant | null |
Name | Scope | Description |
---|---|---|
default |