UNPKG

bootstrap-vue

Version:

With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens

912 lines (767 loc) 145 kB
# Table > For displaying tabular data, `<b-table>` supports pagination, filtering, sorting, custom > rendering, various style options, events, and asynchronous data. For simple display of tabular > data without all the fancy features, BootstrapVue provides two lightweight alternative components > [`<b-table-lite>`](#light-weight-tables) and [`<b-table-simple>`](#simple-tables). **Example: Basic usage** ```html <template> <div> <b-table striped hover :items="items"></b-table> </div> </template> <script> export default { data() { return { 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> <!-- b-table.vue --> ``` ## Items (record data) `items` is the table data in array format, where each record (row) data are keyed objects. Example format: <!-- eslint-disable no-unused-vars --> ```js const items = [ { age: 32, first_name: 'Cyndi' }, { age: 27, first_name: 'Havij' }, { age: 42, first_name: 'Robert' } ] ``` `<b-table>` 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](#fields-column-definitions) 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)](#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 supported optional item record modifier properties (make sure your field keys do not conflict with these names): | Property | Type | Description | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `_cellVariants` | Object | Bootstrap contextual state applied to individual cells. Keyed by field (See the [Color Variants](/docs/reference/color-variants) for supported values). These variants map to classes `table-${variant}` or `bg-${variant}` (when the `dark` prop is set). | | `_rowVariant` | String | Bootstrap contextual state applied to the entire row (See the [Color Variants](/docs/reference/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](#row-details-support) below for additional information | **Example: Using variants for table cells** ```html <template> <div> <b-table hover :items="items"></b-table> </div> </template> <script> export default { data() { return { 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> <!-- b-table-variants.vue --> ``` `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"](#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](#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. `<b-table>` 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](#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: **Example: Using `array` fields definition** ```html <template> <div> <b-table striped hover :items="items" :fields="fields"></b-table> </div> </template> <script> export default { data() { return { // Note `isActive` is left out and will not appear in the rendered table fields: ['first_name', 'last_name', 'age'], 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> <!-- b-table-fields-array.vue --> ``` ### 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: **Example: Using array of objects fields definition** ```html <template> <div> <b-table striped hover :items="items" :fields="fields"></b-table> </div> </template> <script> export default { data() { return { // Note 'isActive' is left out and will not appear in the rendered table fields: [ { 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' } ], 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> <!-- b-table-fields-array-of-objects.vue --> ``` ### Field definition reference The following field properties are recognized: | Property | Type | Description | | ------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | String | 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](#custom-data-rendering) and [custom header and footer](#header-and-footer-custom-rendering-via-scoped-slots) 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` | String or Array | Class name (or array of class names) to add to `<th>` **and** `<td>` in the column. | | `formatter` | String or Function | A formatter callback function or name of a method in your component, can be used instead of (or in conjunction with) scoped field slots. The formatter will be called with the syntax `formatter(value, key, item)`. Refer to [Custom Data Rendering](#custom-data-rendering) for more details. | | `sortable` | Boolean | Enable sorting on this column. Refer to the [Sorting](#sorting) Section for more details. | | `sortKey` | String | <span class="badge badge-secondary">v2.17.0+</span> Set the value of `sortBy` for the column in the emitted context when `no-local-sorting` is `true`. | | `sortDirection` | String | Set the initial sort direction on this column when it becomes sorted. Refer to the [Change initial sort direction](#change-initial-sort-direction) Section for more details. | | `sortByFormatted` | Boolean or Function | 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](#sorting) Section for more details. | | `filterByFormatted` | Boolean or Function | 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](#filtering) section for more details. | | `tdClass` | String or Array or Function | 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. The function will be called as `tdClass(value, key, item)` and it must return an `Array` or `String`. | | `thClass` | String or Array | Class name (or array of class names) to add to this field's `<thead>`/`<tfoot>` heading `<th>` cell. | | `thStyle` | Object | JavaScript object representing CSS styles you would like to apply to the table `<thead>`/`<tfoot>` field `<th>`. | | `variant` | String | Apply contextual class to all the `<th>` **and** `<td>` in the column - `active`, `success`, `info`, `warning`, `danger`. These variants map to classes `thead-${variant}` (in the header), `table-${variant}` (in the body), or `bg-${variant}` (when the prop `dark` is set). | | `tdAttr` | Object or Function | JavaScript 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. The function will be called as `tdAttr(value, key, item)` and it must return an `Object`. | | `thAttr` | Object or Function | JavaScript 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. The function will be called as `thAttr(value, key, item, type)` and it must return an `Object`. | | `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](#responsive-tables) mode or has [sticky headers](#sticky-headers), will cause the column to become fixed to the left when the table's horizontal scrollbar is scrolled. See [Sticky columns](#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 VueLoader's [Deep selector](https://vue-loader.vuejs.org/guide/scoped-css.html#child-component-root-elements). - For information on the syntax supported by `thStyle`, see [Class and Style Bindings](https://vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles) 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](#custom-data-rendering) section below. Feel free to mix and match simple array and object array together: <!-- eslint-disable no-unused-vars --> ```js const fields = [ { key: 'first_name', label: 'First' }, { key: 'last_name', label: 'Last' }, 'age', 'sex' ] ``` ## Primary key `<b-table>` 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 `<b-table>` 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 `<b-table>` 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, `<b-table>` 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](#table-body-transition-support) section for additional details. ## Table style options ### Table styling `<b-table>` 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>` | | `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 v4 class `.table-dark`) | | `fixed` | Boolean | Generate a table with equal fixed-width columns (`table-layout: fixed;`) | | `responsive` | Boolean or String | 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'`, or `'xl'` to make the table responsive (horizontally scroll) only on screens smaller than the breakpoint. See [Responsive tables](#responsive-tables) below for details. | | `sticky-header` | Boolean or String | 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](#sticky-headers) section below for details. | | `stacked` | Boolean or String | Generate a responsive stacked table. Set to `true` for an always stacked table, or set it to one of the breakpoints `'sm'`, `'md'`, `'lg'`, or `'xl'` to make the table visually stacked only on screens smaller than the breakpoint. See [Stacked tables](#stacked-tables) below for details. | | `caption-top` | Boolean | 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. | | `table-variant` | String | Give the table an overall theme color variant. | | `head-variant` | String | Use `'light'` or `'dark'` to make table header appear light or dark gray, respectively | | `foot-variant` | String | Use `'light'` or `'dark'` to make table footer appear light or dark gray, respectively. If not set, `head-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](#sorting) section below for more details. | | `no-border-collapse` | Boolean | Disables the default of collapsing of the table borders. Mainly for use with [sticky headers](#sticky-headers) and/or [sticky columns](#sticky-columns). Will cause the appearance of double borders in some situations. | **Note:** The table style options `fixed`, `stacked`, `caption-top`, `no-border-collapse`, sticky headers, sticky columns and the table sorting feature, all require BootstrapVue's custom CSS. **Example: Basic table styles** ```html <template> <div> <b-form-group label="Table Options" label-cols-lg="2" v-slot="{ ariaDescribedby }"> <b-form-checkbox v-model="striped" :aria-describedby="ariaDescribedby" inline>Striped</b-form-checkbox> <b-form-checkbox v-model="bordered" :aria-describedby="ariaDescribedby" inline>Bordered</b-form-checkbox> <b-form-checkbox v-model="borderless" :aria-describedby="ariaDescribedby" inline>Borderless</b-form-checkbox> <b-form-checkbox v-model="outlined" :aria-describedby="ariaDescribedby" inline>Outlined</b-form-checkbox> <b-form-checkbox v-model="small" :aria-describedby="ariaDescribedby" inline>Small</b-form-checkbox> <b-form-checkbox v-model="hover" :aria-describedby="ariaDescribedby" inline>Hover</b-form-checkbox> <b-form-checkbox v-model="dark" :aria-describedby="ariaDescribedby" inline>Dark</b-form-checkbox> <b-form-checkbox v-model="fixed" :aria-describedby="ariaDescribedby" inline>Fixed</b-form-checkbox> <b-form-checkbox v-model="footClone" :aria-describedby="ariaDescribedby" inline>Foot Clone</b-form-checkbox> <b-form-checkbox v-model="noCollapse" :aria-describedby="ariaDescribedby" inline>No border collapse</b-form-checkbox> </b-form-group> <b-form-group label="Head Variant" label-cols-lg="2" v-slot="{ ariaDescribedby }"> <b-form-radio-group v-model="headVariant" :aria-describedby="ariaDescribedby" class="mt-lg-2" > <b-form-radio :value="null" inline>None</b-form-radio> <b-form-radio value="light" inline>Light</b-form-radio> <b-form-radio value="dark" inline>Dark</b-form-radio> </b-form-radio-group> </b-form-group> <b-form-group label="Table Variant" label-for="table-style-variant" label-cols-lg="2"> <b-form-select id="table-style-variant" v-model="tableVariant" :options="tableVariants" > <template #first> <option value="">-- None --</option> </template> </b-form-select> </b-form-group> <b-table :striped="striped" :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" :head-variant="headVariant" :table-variant="tableVariant" ></b-table> </div> </template> <script> export default { data() { return { fields: ['first_name', 'last_name', 'age'], 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' } ], tableVariants: [ 'primary', 'secondary', 'info', 'danger', 'warning', 'success', 'light', 'dark' ], striped: false, bordered: false, borderless: false, outlined: false, small: false, hover: false, dark: false, fixed: false, footClone: false, headVariant: null, tableVariant: '', noCollapse: false } } } </script> <!-- b-table-bordered.vue --> ``` ### 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` | String, Array or Function | Classes to be applied to every row on the table. If a function is given, it will be called as `tbodyTrClass( item, type )` and it may return an `Array`, `Object` or `String`. | | `tbody-tr-attr` | Object or Function | Attributes to be applied to every row on the table. If a function is given, it will be called as `tbodyTrAttr( item, type )` and it must return an `Object`. | 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. `'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. **Example: Basic row styles** ```html <template> <div> <b-table :items="items" :fields="fields" :tbody-tr-class="rowClass"></b-table> </div> </template> <script> export default { data() { return { fields: ['first_name', 'last_name', 'age'], 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' } ] } }, methods: { rowClass(item, type) { if (!item || type !== 'row') return if (item.status === 'awesome') return 'table-success' } } } </script> <!-- b-table-styled-row.vue --> ``` ### 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`. **Example: Always responsive table** ```html <template> <div> <b-table responsive :items="items"></b-table> </div> </template> <script> export default { data() { return { 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> <!-- b-table-responsive.vue --> ``` **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 &mdash; without taking cells in the `<tbody>` into consideration &mdash; 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](#table-colgroup) that have widths set (e.g. `<col style="width: 20rem">`), or - Wrap header cells in `<div>` elements, via the use of [custom header rendering](#header-and-footer-custom-rendering-via-scoped-slots), which have a minimum width set on them, or - Use the `thStyle` property of the [field definition object](#field-definition-reference) 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](#field-definition-reference). ### 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`](#sticky-headers) prop and the [`stickyColumn`](#sticky-columns) field definition property. **Example: Always stacked table** ```html <template> <div> <b-table stacked :items="items"></b-table> </div> </template> <script> export default { data() { return { 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> <!-- b-table-stacked.vue --> ``` **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](#sorting) section below for sorting control information, as well as the [complete example](#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. BootstrapVue'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: ```html <template> <div> <b-table :items="items" :fields="fields"> <template #table-caption>This is a table caption.</template> </b-table> </div> </template> <script> export default { data() { return { fields: ['first_name', 'last_name', 'age'], 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> <!-- b-table-caption.vue --> ``` You can have the caption placed at the top of the table by setting the `caption-top` prop to `true`: ```html <template> <div> <b-table :items="items" :fields="fields" caption-top> <template #table-caption>This is a table caption at the top.</template> </b-table> </div> </template> <script> export default { data() { return { fields: ['first_name', 'last_name', 'age'], 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> <!-- b-table-caption-top.vue --> ``` You can also use [custom CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/caption-side) to control the caption positioning. ### Table colgroup Use the named slot `table-colgroup` to specify `<colgroup>` and `<col>` elements for optional grouping and styling of table columns. Note the styles available via `<col>` elements are limited. Refer to [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup) for details and usage of `<colgroup>` Slot `table-colgroup` 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` | Array | Array of field definition objects (normalized to the [array of objects](#fields-as-an-array-of-objects) format) | When provided, the content of the `table-colgroup` slot will be placed _inside_ of a `<colgroup>` element. there is no need to provide your own outer `<colgroup>` element. When a series of table columns should be grouped for assistive technology reasons (for conveying logical column associations, use a `<col span="#">` element (with `#` replaced with the number of grouped columns) to group the series of columns. **Tip:** In some situations when trying to set column widths via `style` or `class` on the `<col>` element, you may find that placing the table in `fixed` header width (table fixed layout mode) mode, combined with `responsive` (horizontal scrolling) mode will help, although you will need to have explicit widths, or minimum widths, via a style or a class for each column's respective `<col>` element. For example: ```html <b-table fixed responsive :items="items" :fields="fields" ... > <template #table-colgroup="scope"> <col v-for="field in scope.fields" :key="field.key" :style="{ width: field.key === 'foo' ? '120px' : '180px' }" > </template> <!-- additional table slots here if needed --> </b-table> ``` ### Table busy state `<b-table>` provides a `busy` prop 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.6`), using the following custom CSS: ```css /* Busy table styling */ table.b-table[aria-busy='true'] { opacity: 0.6; } ``` You can override this styling using your own CSS. You may optionally provide a `table-busy` slot to show a custom loading message or spinner whenever the table's busy state is `true`. The slot will be placed in a `<tr>` element with class `b-table-busy-slot`, which has one single `<td>` with a `colspan` set to the number of fields. **Example of `table-busy` slot usage:** ```html <template> <div> <b-button @click="toggleBusy">Toggle Busy State</b-button> <b-table :items="items" :busy="isBusy" class="mt-3" outlined> <template #table-busy> <div class="text-center text-danger my-2"> <b-spinner class="align-middle"></b-spinner> <strong>Loading...</strong> </div> </template> </b-table> </div> </template> <script> export default { data() { return { isBusy: false, 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 } ] } }, methods: { toggleBusy() { this.isBusy = !this.isBusy } } } </script> <!-- b-table-busy-slot.vue --> ``` Also see the [Using Items Provider Functions](#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 `<b-table-lite>` component. ## Custom data rendering Custom rendering for each data field in a row is possible using either [scoped slots](https://vuejs.org/v2/guide/components.html#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`](#fields-column-definitions) 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. **Example: Custom data rendering with scoped slots** ```html <template> <div> <b-table 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.value.last.toUpperCase() }}</b>, <b>{{ data.value.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> </b-table> </div> </template> <script> export default { data() { return { 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' } ], 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> <!-- b-table-data-slots.vue --> ``` The slot's scope variable (`data` in the above sample) will have the following properties: | Property | Type | Description