Overview
Displays a grid of cards KCard
.
KCardGrid
provides base layouts for the most common grids in our ecosystem, as well as customization or complete override of the base layouts.
Together with KCard
, it ensures accessible navigation within card lists, such as announcing only their titles when using the tab key to avoid overwhelming screen reader outputs.
Grid's visual behavior is based on the
window breakpoint system
. KCardGrid
determines how many cards per row to display based on its layout and a current window breakpoint.
KCardGrid
doesn't manage inner card content. This is KCard
's responsibility.
Guidelines
KCardGrid
must be a direct parent ofKCard
( KCard: KCard and KCardGrid )-
Avoid setting card widths. Rely on
KCardGrid
layouts and customization options ( Base layouts , Layout customization ) - Avoid setting card heights. Instead, set heights on card sections, use text truncation, or limit content in other ways ( Card height, content tolerance and alignment )
- Ensure robust content tolerance and consistent content alignment ( Card height, content tolerance and alignment )
- Preview cards on all screen sizes ( Fine-tuning responsiveness )
- Configure loading skeleton cards to match the expected visual output of cards with loaded data as closely as possible on all screen sizes ( Loading state )
Also follow KCard guidelines .
Usage
Base layouts
Three base layouts are available: '1-1-1'
, '1-2-2'
, and '1-2-3'
. They determine the number of cards per row for each
window breakpoint level
.
'1-1-1' grid
Displays a grid with 1 card per row on every screen size.
Level 0 | Level 1 | Level 2 | Level 3 | Level 4 | Level 5 | Level 6 | Level 7 | |
---|---|---|---|---|---|---|---|---|
Cards per row | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
<KCardGrid layout="1-1-1">
<KCard
v-for="i in 2"
...
/>
</KCardGrid>
'1-2-2' grid
Displays a grid with 1 card per row on smaller screens, and 2 cards per row on medium and larger screens.
Level 0 | Level 1 | Level 2 | Level 3 | Level 4 | Level 5 | Level 6 | Level 7 | |
---|---|---|---|---|---|---|---|---|
Cards per row | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 2 |
<KCardGrid layout="1-2-2">
<KCard
v-for="i in 3"
...
/>
</KCardGrid>
'1-2-3' grid
Displays a grid with 1 card per row on smaller screens, 2 cards per row on medium screens, and 3 cards per row on larger screens.
Level 0 | Level 1 | Level 2 | Level 3 | Level 4 | Level 5 | Level 6 | Level 7 | |
---|---|---|---|---|---|---|---|---|
Cards per row | 1 | 1 | 2 | 2 | 3 | 3 | 3 | 3 |
<KCardGrid layout="1-2-3">
<KCard
v-for="i in 5"
...
/>
</KCardGrid>
Layout customization
Base layouts can be customized or even completely overriden via the layoutOverride
prop. layoutOverride
takes an array of objects { breakpoints, cardsPerRow, columnGap, rowGap }
, where:
breakpoints
is an array of0-7
values corresponding to the window breakpoint levels . All other attributes in the same object take effect on these breakpoints.cardsPerRow
overrides the number of cards per row for the specified breakpoints.columnGap
/rowGap
overrides grid column/row gaps for the specified breakpoints.
For example:
<KCardGrid
layout="1-2-3"
:layoutOverride="layoutOverride"
>
<KCard
v-for="i in 6"
...
/>
</KCardGrid>
export default {
...
data() {
return {
layoutOverride: [
{
breakpoints: [0, 1],
columnGap: '20px',
rowGap: '20px',
},
{
breakpoints: [4, 5, 6, 7],
cardsPerRow: 4,
},
],
};
},
};
Here, the base 1-2-3
layout is overriden partially. Column and row gaps are decreased to 20px
on breakpoints 0-1
, and the number of cards per row is increased to 4 on breakpoints 4-7
.
Card height, content tolerance and alignment
Cards displayed in KCardGrid
stretch vertically to fit their content, making a grid row height match its tallest card.
Setting height on cards is discouraged. Instead, manage height bottom-up, for example by setting height on card sections, using text truncation, or other ways to limit its inner content. Such approaches ensure content tolerance, prevent from unexpected overflows or excessive height, and keep vertical alignment of card sections consistent on a grid row. This is especially important when dealing with unknown lenghts or amounts of content displayed in cards. Consider:
<KCardGrid ...>
<KCard
...
preserveAboveTitle
>
<template #aboveTitle>
<div :style="{ height: '24px' }">
...
</div>
</template>
<template #title>
<div :style="{ height: '52px' }">
<KTextTruncator
:maxLines="2"
:text="..."
/>
</div>
</template>
<template #belowTitle>
<KTextTruncator
:maxLines="4"
:text="..."
/>
</template>
<template #footer>
<span v-for="pill in slicedPills">
...
</span>
</template>
</KCard>
</KCardGrid>
export default {
...
computed: {
slicedPills() {
return pills.slice(0, 2);
},
},
};
Here, KCard
has the following adjustments related to its visual output in the grid:
- Height is set on its
aboveTitle
slot content, and itspreserveAboveTitle
prop keeps the slot area even without content. This results in consistent alignment of all cards' titles on a grid row. - Similarly, height is set on its
title
slot, and the title is truncated. - Its
belowTitle
slot's content is truncated. - The number of pills in its
footer
slot is limited to a reasonable amount.
KCard
offers other preserve...
props corresponding to its slots.
Fine-tuning responsiveness
Grid configuration can be combined with KCard
's settings to further improve responsive experience. A common pattern is switching KCard
's horizontal orientation to vertical for smaller screens to organize content more effectively in limited space:
import useKResponsiveWindow from 'kolibri-design-system/lib/composables/useKResponsiveWindow';
export default {
setup() {
const { windowBreakpoint } = useKResponsiveWindow();
return { windowBreakpoint };
},
};
<KCardGrid layout="1-2-2">
<KCard
v-for="i in 2"
:orientation="windowBreakpoint < 4 ? 'vertical' : 'horizontal'"
...
/>
</KCardGrid>
This technique also works for adjusting KCard
slots content. In the following example, some metadata pills are hidden on smaller screens:
<KCardGrid layout="1-2-2">
<KCard
v-for="i in 2"
...
>
<template #footer>
<span ...>Read</span>
<span ...>Short Activity</span>
<template v-if="windowBreakpoint > 3">
<span ...>Biology</span>
<span ...>Ecology</span>
</template>
</template>
</KCard>
</KCardGrid>
Loading state
While data is loading, KCardGrid
shows loading skeleton cards. Use the loading
prop to toggle the loading state. Note that KCardGrid
internal optimizations may affect how closely the visual loading experience matches the loading
value:
- The loading skeletons won't be displayed for short loading times (< 1s)
- When the loading skeletons are displayed, they will be visible for at least 1s
Use the buttons in the example below to preview.
Number of loading skeletons
By default, the number of loading skeletons corresponds to the number of cards in a single grid row if it were full. This behavior can be overridden via the count
attribute (below), however do not override it unless indicated in the designs.
Loading skeletons configuration
Use the skeletonsConfig
prop to configure skeleton cards to match the expected visual output of loaded cards on all screen sizes. Preview the layout and height of cards with loaded data and adjust skeletonsConfig
accordingly.
skeletonsConfig
takes an array of objects { breakpoints, count, height, orientation, thumbnailDisplay, thumbnailAlign }
, where:
breakpoints
is an array of0-7
values corresponding to the window breakpoint levels . All other attributes in the same object take effect on these breakpoints.count
sets the number of skeleton cards for the specified breakpoints. See Number of loading skeletons .height
sets the height of skeleton cards for the specified breakpoints.orientation
sets the orientation of skeleton cards for the specified breakpoints. Corresponds toKCard's orientation
.thumbnailDisplay
sets the thumbnail display of skeleton cards for the specified breakpoints. Corresponds toKCard's thumbnailDisplay
.thumbnailAlign
sets the thumbnail alignment of skeleton cards for the specified breakpoints. Corresponds toKCard's thumbnailAlign
.
For easier development, enable the debug
prop to display the current breakpoint in the top left corner of the grid. Use the button in the example below to preview the debug mode.
<KCardGrid
layout="1-2-2"
:skeletonsConfig="skeletonsConfig"
:loading="loading"
>
<KCard
v-for="i in 3"
:orientation="windowBreakpoint < 4 ? 'vertical' : 'horizontal'"
thumbnailDisplay="large"
thumbnailAlign="left"
...
/>
</KCardGrid>
export default {
...
data() {
return {
skeletonsConfig: [
{
breakpoints: [0, 1, 2, 3, 4, 5, 6, 7],
height: '400px',
orientation: 'vertical',
thumbnailDisplay: 'large',
thumbnailAlign: 'left'
},
{
breakpoints: [4, 5, 6, 7],
height: '220px',
orientation: 'horizontal'
}
],
};
},
};
Here, the height of loading skeleton cards is 400px
with vertical orientation on breakpoints 0-3
, and 220px
with horizontal orientation on breakpoints 4-7
. This makes skeleton cards resemble loaded cards at all breakpoints, creating a smooth transition for users during data loading. Note the bottom-up approach where we begin with a base setup for all breakpoints and gradually override on higher breakpoints. This simplifies the configuration object.
To get a sense of what skeleton layouts can be achieved, reload this page and the KCard
page to preview the loading state in all examples.
Related
KCard
is a component for use withinKCardGrid
useKResponsiveWindow
can be used to detect the current window breakpoint for fine-tuning responsiveness
Props
Name | Description | Type | Default | Required |
---|---|---|---|---|
layout | Sets the base grid layout.
Options: '1-1-1' , '1-2-2' , and '1-2-3' . | string |
'1-2-2'
| — |
layoutOverride | Overrides the base grid layout for chosen breakpoints levels | array |
null
| — |
loading | Set to true as long as data for cards
are being loaded to display loading skeletons | boolean |
false
| — |
skeletonsConfig | Configures loading skeletons | array |
null
| — |
debug | Use for development only. Shows information in
the grid's corner that is useful for configuring
loading skeletons. | boolean |
false
| — |
Slots
Name | Description |
---|---|
default | Slot for KCard s |