Skip to main content

Card Button

The CardButton component is a flexible card-style link designed to display a title, icon, optional badge, subtitle, and feature list.

It supports active and inactive states, hover animations, custom styling, and configurable link targets.

import { CardButton } from "tawuniya/components";

👉 View in Storybook

Props​

PropTypeDefaultDescription
titlestring-The title displayed inside the card.
iconReactNode | string | null-Icon displayed above the title.
activebooleanfalseIndicates whether the card is active. Applies the primary border and active indicator.
featuresFeatureItem[][]List of features displayed inside the card.
subTextReactNode-Optional secondary text displayed below the title when the card is inactive.
hrefstring | null-Optional link URL. If omitted, the card behaves as a button and can be controlled via onClick.
onClickMouseEventHandler<HTMLAnchorElement | HTMLButtonElement>-Click handler for router-based navigation or custom logic.
targetHTMLAttributeAnchorTarget | undefined_blankSpecifies where to open the linked page. Only used when href is provided.
badgeTextstring-Optional text displayed inside a badge at the top of the card.
type"default" | "flashed" | "mobile""default"Adjusts the visual behavior for the default, rotating-feature, or mobile card layouts.
imagestring-Optional illustrative image used for mobile layout cards.
classNamesCardButtonClassNames-Allows custom classes to be applied to different parts of the component.

FeatureItem​

type FeatureItem = {
key: string;
text: string;
};
PropertyTypeDescription
keystringUnique identifier for the feature.
textstringText displayed for the feature.

classNames​

The classNames prop allows customization of individual sections of the component.

interface CardButtonClassNames {
rootWrapper?: string;
mainWrapper?: string;
contentWrapper?: string;
featuresWrapper?: string;
iconWrapper?: string;
title?: string;

badge?: {
wrapper?: string;
badgeItem?: string;
};

feature?: {
wrapper?: string;
icon?: string;
text?: string;
};
}
PropertyTypeDescription
rootWrapperstringCustom classes for the root card wrapper.
mainWrapperstringCustom classes for the main card wrapper.
contentWrapperstringCustom classes for the content container.
featuresWrapperstringCustom classes for the features container.
iconWrapperstringCustom classes for the icon wrapper.
titlestringCustom classes for the card title.
badge.wrapperstringCustom classes for the badge wrapper.
badge.badgeItemstringCustom classes for the badge itself.
feature.wrapperstringCustom classes for each feature wrapper.
feature.iconstringCustom classes for the feature icon.
feature.textstringCustom classes for the feature text.

Usage​

Basic Example​

<CardButton
title="Comprehensive"
icon={<Icon name="car" />}
href="/comprehensive"
/>

Active Card​

Use the active prop to indicate the currently selected card.

<CardButton
title="Comprehensive"
icon={<Icon name="car" />}
href="/comprehensive"
active
/>

The active state:

  • Applies the border-primary class.
  • Changes the title and icon to the primary color.
  • Displays an active indicator in the top-right corner.
  • Expands the feature list if features are provided.

Flashed and Mobile Variants​

Use the type prop to switch to the alternating-feature or mobile presentation.

<CardButton
title="Motor"
icon={<Icon name="car" />}
href="/motor"
type="flashed"
features={[
{ key: "1", text: "Pay up-to-12 installments" },
{ key: "2", text: "Cash back with driver app" },
{ key: "3", text: "Insure online in seconds" },
]}
/>

<CardButton
title="Travel"
icon={<Icon name="shield" />}
href="/travel"
type="mobile"
image="/images/travel.png"
features={[
{ key: "1", text: "24/7 assistance" },
{ key: "2", text: "Global coverage" },
]}
/>

The mobile variant displays the provided image and keeps the headline compact while the flashed variant rotates through a single feature line with a subtle animation.

With Badge​

<CardButton
title="Premium"
icon={<Icon name="car" />}
href="/premium"
badgeText="Recommended"
/>

The badge is displayed above the card.

With Sub Text​

<CardButton
title="Basic"
icon={<Icon name="car" />}
href="/basic"
subText="Starting from SAR 500"
/>

The subText is displayed when the card is inactive.

When the user hovers over the card, the subtitle transitions out.

With Features​

<CardButton
title="Comprehensive"
icon={<Icon name="car" />}
href="/comprehensive"
features={[
{
key: "liability",
text: "Third Party Liability",
},
{
key: "roadside",
text: "Roadside Assistance",
},
{
key: "disaster",
text: "Natural Disaster Coverage",
},
]}
/>

Features are initially collapsed and become visible when the card is hovered.

Active Card With Features​

<CardButton
title="Comprehensive"
icon={<Icon name="car" />}
href="/comprehensive"
active
features={[
{
key: "liability",
text: "Third Party Liability",
},
{
key: "roadside",
text: "Roadside Assistance",
},
{
key: "disaster",
text: "Natural Disaster Coverage",
},
]}
/>

When the card is active, the features remain visible without requiring hover.

Click-only usage with router navigation​

When you already handle navigation with a router, href can be omitted and onClick can be used instead.

const navigate = useRouter();

<CardButton
title="Premium"
icon={<Icon name="car" />}
onClick={() => navigate("/premium")}
/>;

The default target is _blank.

<CardButton
title="Premium"
icon={<Icon name="car" />}
href="/premium"
target="_self"
/>

Supported values are the standard HTML anchor targets:

"_blank";
"_self";
"_parent";
"_top";

Custom Styling​

<CardButton
title="Premium"
icon={<Icon name="car" />}
href="/premium"
classNames={{
mainWrapper: "max-w-64",
contentWrapper: "gap-y-4",
iconWrapper: "bg-muted p-2 rounded-full",
title: "text-lg",
featuresWrapper: "mt-2",
badge: {
wrapper: "top-0",
badgeItem: "bg-green-600",
},
feature: {
wrapper: "gap-x-2",
icon: "size-4",
text: "text-sm",
},
}}
/>

When the card is used with target="_blank", the component adds rel="noopener noreferrer" automatically to reduce the risk of tabnabbing.

Complete Example​

<CardButton
title="Comprehensive"
icon={<Icon name="car" />}
href="/comprehensive"
target="_blank"
active
badgeText="Recommended"
subText="Starting from SAR 1,500"
features={[
{
key: "liability",
text: "Third Party Liability",
},
{
key: "roadside",
text: "Roadside Assistance",
},
{
key: "natural-disaster",
text: "Natural Disaster Coverage",
},
]}
/>

Variant notes​

  • default: standard card with hover-expanding feature list
  • flashed: compact rotating feature highlight for landing pages
  • mobile: card configured for mobile-style promos with image support

Features​

  • Active State: Supports active and inactive card states.
  • Badge: Displays an optional badge above the card.
  • Sub Text: Supports secondary content below the title.
  • Feature List: Displays a list of included features.
  • Hover Animation: Features and subtitle use smooth hover transitions.
  • Custom Icons: Accepts any ReactNode as the card icon.
  • Custom Styling: Supports granular styling through the classNames prop.
  • Link Support: Works as a standard HTML anchor with configurable href and target.
  • Responsive Width: Uses a maximum width while allowing custom width classes.

Notes​

  • href is optional. When omitted, the component renders as a button and can be used with onClick for router-driven navigation.
  • The default target is _blank and is only applied when href is present.
  • features defaults to an empty array.
  • subText is only rendered when the card is inactive.
  • Features are collapsed by default for inactive cards and expand on hover.
  • Features remain expanded when the card is active.
  • The key property in each feature should be unique.
  • Use the classNames prop when component-level customization is required without modifying the base component styles.