Card
The Card component contains content and actions that inform about a single subject.
Default Card
The default card view with a rectangle shaped image, a title, a description and a button for some additional actions.
This block contain empty anchor element, this specific manipulation adds possibility to navigate with tab through whole card. With this structure we can click buttons inside or whole card itself. If root card element would be anchor element, we would not have possibility to click button inside.
<!-- eslint-disable vuejs-accessibility/anchor-has-content -->
<template>
<div class="flex flex-wrap gap-4 lg:gap-6 lg:flex-nowrap">
<div
v-for="({ image, title, description, button }, index) in cardDetails"
:key="`${title}-${index}`"
class="flex flex-col min-w-[325px] max-w-[375px] lg:w-[496px] relative border border-neutral-200 rounded-3xl hover:shadow-xl active:shadow-none transition-shadow group"
>
<a
class="absolute inset-0 z-1 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-3xl"
href="#"
/>
<img :src="image" :alt="title" class="object-cover h-auto rounded-t-3xl aspect-video" />
<div class="flex flex-col items-end p-4 grow">
<p class="font-medium typography-text-base">{{ title }}</p>
<p class="mt-1 mb-4 font-normal typography-text-sm text-neutral-700">{{ description }}</p>
<SfButton
size="sm"
variant="tertiary"
class="mt-auto group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabindex="-1"
>{{ button }}</SfButton
>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { SfButton } from '@storefront-ui/vue';
const cardDetails = [
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/card-3.png',
title: "Trail Running: Nature's Ultimate Challenge",
description:
"Explore the exhilarating world of trail running. Embrace nature's rugged terrains, elevate your fitness, and learn to conquer every path.",
button: 'Read more',
},
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/card-2.png',
title: 'Ride the Future: Exploring the Benefits of e-Bikes',
description:
'Eco-friendly, efficient, and fun modes of transportation that provide a range of benefits for riders and the environment.',
button: 'Read more',
},
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/card-1.png',
title: 'Unleash the Ultimate Listening Experience',
description:
'Audiophile headphones offer unmatched sound quality and clarity, making them the go-to choice for music enthusiasts.',
button: 'Read more',
},
];
</script>
Category Card
The category card view with a circle shaped image, and category title, clickable as the one element.
<template>
<div class="flex flex-wrap gap-4 lg:gap-6 lg:flex-no-wrap">
<div
v-for="{ title, image } in categories"
:key="title"
class="relative flex-col min-w-[140px] max-w-[240px] justify-center group"
>
<a
class="absolute w-full h-full z-[1] focus-visible:outline focus-visible:outline-offset focus-visible:rounded-3xl"
href="#"
:aria-label="title"
/>
<img
class="transition-[filter] drop-shadow-none group-hover:drop-shadow-xl group-active:drop-shadow-none"
:src="image"
:alt="title"
width="240"
height="240"
/>
<div class="flex justify-center p-4 gap-4">
<a
class="font-medium no-underline text-normal-900 typography-text-base group-hover:underline group-hover:text-primary-900 group-hover:font-normal group-active:underline group-active:text-primary-900 group-active:font-normal"
>
{{ title }}
</a>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const categories = [
{
title: `Women`,
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/women_category.png',
},
{
title: `Men`,
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/men_category.png',
},
{
title: `Kids`,
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/kid_category.png',
},
];
</script>
Card Feature
This type of card has only button to interact.
<template>
<div class="flex flex-wrap gap-4 lg:gap-6 lg:flex-nowrap">
<div
v-for="({ icon, title, description, buttonText, isDisabled }, index) in cardDetails"
:key="`${title}-${index}`"
class="flex flex-col w-full max-w-[325px] sm:w-[375px] lg:w-[496px] items-center"
>
<component :is="icon" size="2xl" :class="{ 'text-disabled-900': isDisabled }" />
<div class="p-4 flex flex-col items-center">
<p :class="['font-medium typography-text-base', { 'text-disabled-900': isDisabled }]">{{ title }}</p>
<p
:class="[
'mt-1 mb-4 font-normal typography-text-sm text-neutral-700 text-center',
{ 'text-disabled-700': isDisabled },
]"
>
{{ description }}
</p>
<SfButton size="sm" variant="secondary" :disabled="isDisabled" class="mt-auto">{{ buttonText }}</SfButton>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { SfButton, SfIconPackage, SfIconWarehouse, SfIconPublishedWithChanges } from '@storefront-ui/vue';
const cardDetails = [
{
icon: SfIconPackage,
title: 'Free shipping',
description: 'Learn about our commitments to ethics, our team, our communities and more.',
buttonText: 'Read more',
isDisabled: false,
},
{
icon: SfIconWarehouse,
title: 'Click & Collect',
description: 'Learn about our commitments to ethics, our team, our communities and more.',
buttonText: 'Read more',
isDisabled: false,
},
{
icon: SfIconPublishedWithChanges,
title: 'Free 30-Day returns',
description: 'Learn about our commitments to ethics, our team, our communities and more.',
buttonText: 'Read more',
isDisabled: true,
},
];
</script>