Avatar Groups
Flexible avatar group components for displaying multiple avatars together. Supports various layouts, sizes, and customization options. previews<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 5" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup borderColor="blue">
<Avatar src={sampleAvatar} alt="User 1" bordered />
<Avatar src={sampleAvatar2} alt="User 2" bordered />
<Avatar src={sampleAvatar3} alt="User 3" bordered />
<Avatar src={sampleAvatar4} alt="User 4" bordered />
<Avatar src={sampleAvatar5} alt="User 5" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-6 text-xs">
<div
class="relative flex items-center justify-center rounded-full size-6 text-xs overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-6 text-xs">
<div
class="relative flex items-center justify-center rounded-full size-6 text-xs overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-6 text-xs">
<div
class="relative flex items-center justify-center rounded-full size-6 text-xs overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-6 text-xs">
<div
class="relative flex items-center justify-center rounded-full size-6 text-xs overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-6 text-xs">
<div
class="relative flex items-center justify-center rounded-full size-6 text-xs overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto mt-4">
<div class="relative flex items-center justify-center rounded-full size-8 text-sm">
<div
class="relative flex items-center justify-center rounded-full size-8 text-sm overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-8 text-sm">
<div
class="relative flex items-center justify-center rounded-full size-8 text-sm overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-8 text-sm">
<div
class="relative flex items-center justify-center rounded-full size-8 text-sm overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-8 text-sm">
<div
class="relative flex items-center justify-center rounded-full size-8 text-sm overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-8 text-sm">
<div
class="relative flex items-center justify-center rounded-full size-8 text-sm overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto mt-4">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto mt-4">
<div class="relative flex items-center justify-center rounded-full size-14 text-lg">
<div
class="relative flex items-center justify-center rounded-full size-14 text-lg overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-14 text-lg">
<div
class="relative flex items-center justify-center rounded-full size-14 text-lg overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-14 text-lg">
<div
class="relative flex items-center justify-center rounded-full size-14 text-lg overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-14 text-lg">
<div
class="relative flex items-center justify-center rounded-full size-14 text-lg overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-14 text-lg">
<div
class="relative flex items-center justify-center rounded-full size-14 text-lg overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto mt-4">
<div class="relative flex items-center justify-center rounded-full size-16 text-xl">
<div
class="relative flex items-center justify-center rounded-full size-16 text-xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-16 text-xl">
<div
class="relative flex items-center justify-center rounded-full size-16 text-xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-16 text-xl">
<div
class="relative flex items-center justify-center rounded-full size-16 text-xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-16 text-xl">
<div
class="relative flex items-center justify-center rounded-full size-16 text-xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-16 text-xl">
<div
class="relative flex items-center justify-center rounded-full size-16 text-xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto mt-4">
<div class="relative flex items-center justify-center rounded-full size-20 text-2xl">
<div
class="relative flex items-center justify-center rounded-full size-20 text-2xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-20 text-2xl">
<div
class="relative flex items-center justify-center rounded-full size-20 text-2xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-20 text-2xl">
<div
class="relative flex items-center justify-center rounded-full size-20 text-2xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-20 text-2xl">
<div
class="relative flex items-center justify-center rounded-full size-20 text-2xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-20 text-2xl">
<div
class="relative flex items-center justify-center rounded-full size-20 text-2xl overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="Circular" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="xs" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="xs" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="xs" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="xs" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="xs" bordered />
</AvatarGroup>
<AvatarGroup class="mt-4">
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="sm" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="sm" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="sm" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="sm" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="sm" bordered />
</AvatarGroup>
<AvatarGroup class="mt-4">
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="md" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="md" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="md" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="md" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="md" bordered />
</AvatarGroup>
<AvatarGroup class="mt-4">
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="lg" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="lg" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="lg" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="lg" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="lg" bordered />
</AvatarGroup>
<AvatarGroup class="mt-4">
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="xl" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="xl" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="xl" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="xl" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="xl" bordered />
</AvatarGroup>
<AvatarGroup class="mt-4">
<Avatar src={sampleAvatar} alt="Circular" shape="circular" size="2xl" bordered />
<Avatar src={sampleAvatar2} alt="Circular" shape="circular" size="2xl" bordered />
<Avatar src={sampleAvatar3} alt="Circular" shape="circular" size="2xl" bordered />
<Avatar src={sampleAvatar4} alt="Circular" shape="circular" size="2xl" bordered />
<Avatar src={sampleAvatar5} alt="Circular" shape="circular" size="2xl" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div class="grid w-fit grid-cols-3 grid-rows-2 gap-2">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 5" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 6" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup layout="grid" columns={3} rows={2}>
<Avatar src={sampleAvatar} alt="User 1" />
<Avatar src={sampleAvatar2} alt="User 2" />
<Avatar src={sampleAvatar3} alt="User 3" />
<Avatar src={sampleAvatar4} alt="User 4" />
<Avatar src={sampleAvatar5} alt="User 5" />
<Avatar src={sampleAvatar} alt="User 6" />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
Grid with Different Columns and Rows
Avatar groups in grid layout with various column and row counts.
<div class="space-y-8">
<div class="grid w-fit grid-cols-2 grid-rows-2 gap-2">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
</div>
<div class="grid w-fit grid-cols-4 grid-rows-1 gap-2">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
</div>
<div class="grid w-fit grid-cols-3 grid-rows-3 gap-2">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 5" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 6" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 7" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 8" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 9" src="path/to/image.jpg">
</div>
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup layout="grid" columns={2} rows={2}>
<Avatar src={sampleAvatar} alt="User 1" />
<Avatar src={sampleAvatar2} alt="User 2" />
<Avatar src={sampleAvatar3} alt="User 3" />
<Avatar src={sampleAvatar4} alt="User 4" />
</AvatarGroup>
<AvatarGroup layout="grid" columns={4} rows={1}>
<Avatar src={sampleAvatar} alt="User 1" />
<Avatar src={sampleAvatar2} alt="User 2" />
<Avatar src={sampleAvatar3} alt="User 3" />
<Avatar src={sampleAvatar4} alt="User 4" />
</AvatarGroup>
<AvatarGroup layout="grid" columns={3} rows={3}>
<Avatar src={sampleAvatar} alt="User 1" />
<Avatar src={sampleAvatar2} alt="User 2" />
<Avatar src={sampleAvatar3} alt="User 3" />
<Avatar src={sampleAvatar4} alt="User 4" />
<Avatar src={sampleAvatar5} alt="User 5" />
<Avatar src={sampleAvatar} alt="User 6" />
<Avatar src={sampleAvatar} alt="User 7" />
<Avatar src={sampleAvatar} alt="User 8" />
<Avatar src={sampleAvatar} alt="User 9" />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div class="space-y-8">
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-1 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-3 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup spacing="tight">
<Avatar src={sampleAvatar} alt="User 1" bordered />
<Avatar src={sampleAvatar2} alt="User 2" bordered />
<Avatar src={sampleAvatar3} alt="User 3" bordered />
</AvatarGroup>
<AvatarGroup spacing="normal">
<Avatar src={sampleAvatar} alt="User 1" bordered />
<Avatar src={sampleAvatar2} alt="User 2" bordered />
<Avatar src={sampleAvatar3} alt="User 3" bordered />
</AvatarGroup>
<AvatarGroup spacing="loose">
<Avatar src={sampleAvatar} alt="User 1" bordered />
<Avatar src={sampleAvatar2} alt="User 2" bordered />
<Avatar src={sampleAvatar3} alt="User 3" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-purple-600 dark:border-purple-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-indigo-600 dark:border-indigo-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-green-600 dark:border-green-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup borderColor="red">
<Avatar src={sampleAvatar} alt="User 1" bordered borderColor="purple" />
<Avatar src={sampleAvatar2} alt="User 2" bordered borderColor="indigo" />
<Avatar src={sampleAvatar3} alt="User 3" bordered borderColor="green" />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">JD</span>
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<span class="inline-block size-5">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
data-slot="icon">
<path
fill-rule="evenodd"
d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z"
clip-rule="evenodd"></path>
</svg>
</span>
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
<span
class="absolute w-3 h-3 bottom-[2%] right-[2%] bg-green-500 rounded-full border-2 border-white dark:border-gray-800"></span>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-red-500 dark:bg-red-600 text-white dark:text-white hover:text-red-100 dark:hover:text-red-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">AB</span>
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="User 1" bordered />
<Avatar initials="JD" bordered />
<Avatar icon="UserIcon" bordered />
<Avatar src={sampleAvatar2} alt="User 4" status="online" bordered />
<Avatar initials="AB" color="red" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
<span
class="absolute w-3 h-3 bottom-[2%] right-[2%] bg-green-500 rounded-full border-2 border-white dark:border-gray-800"></span>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
<span
class="absolute w-3 h-3 bottom-[2%] right-[2%] bg-gray-500 rounded-full border-2 border-white dark:border-gray-800"></span>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
<span
class="absolute w-3 h-3 bottom-[2%] right-[2%] bg-red-500 rounded-full border-2 border-white dark:border-gray-800"></span>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
<span
class="absolute w-3 h-3 bottom-[2%] right-[2%] bg-yellow-500 rounded-full border-2 border-white dark:border-gray-800"></span>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="User 1" status="online" bordered />
<Avatar src={sampleAvatar2} alt="User 2" status="offline" bordered />
<Avatar src={sampleAvatar3} alt="User 3" status="busy" bordered />
<Avatar src={sampleAvatar4} alt="User 4" status="away" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-lg size-12 text-base">
<div
class="relative flex items-center justify-center rounded-lg size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-lg size-12 text-base">
<div
class="relative flex items-center justify-center rounded-lg size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-lg size-12 text-base">
<div
class="relative flex items-center justify-center rounded-lg size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-lg size-12 text-base">
<div
class="relative flex items-center justify-center rounded-lg size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="User 1" shape="rounded" bordered />
<Avatar src={sampleAvatar2} alt="User 2" shape="rounded" bordered />
<Avatar src={sampleAvatar3} alt="User 3" shape="rounded" bordered />
<Avatar src={sampleAvatar4} alt="User 4" shape="rounded" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-none size-12 text-base">
<div
class="relative flex items-center justify-center rounded-none size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-none size-12 text-base">
<div
class="relative flex items-center justify-center rounded-none size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-none size-12 text-base">
<div
class="relative flex items-center justify-center rounded-none size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div class="relative flex items-center justify-center rounded-none size-12 text-base">
<div
class="relative flex items-center justify-center rounded-none size-12 text-base overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-2 border-white dark:border-gray-800">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="User 1" shape="square" bordered />
<Avatar src={sampleAvatar2} alt="User 2" shape="square" bordered />
<Avatar src={sampleAvatar3} alt="User 3" shape="square" bordered />
<Avatar src={sampleAvatar4} alt="User 4" shape="square" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-red-500 dark:bg-red-600 text-white dark:text-white hover:text-red-100 dark:hover:text-red-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">JD</span>
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-blue-500 dark:bg-blue-600 text-white dark:text-white hover:text-blue-100 dark:hover:text-blue-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">AB</span>
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-green-500 dark:bg-green-600 text-white dark:text-white hover:text-green-100 dark:hover:text-green-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">CD</span>
</div>
</div>
<div class="relative flex items-center justify-center rounded-full size-12 text-base">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base overflow-hidden bg-yellow-500 dark:bg-yellow-600 text-white dark:text-white hover:text-yellow-100 dark:hover:text-yellow-200 border-2 border-white dark:border-gray-800">
<span class="font-medium">EF</span>
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
---
<AvatarGroup>
<Avatar initials="JD" color="red" bordered />
<Avatar initials="AB" color="blue" bordered />
<Avatar initials="CD" color="green" bordered />
<Avatar initials="EF" color="yellow" bordered />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
<div
class="flex -space-x-4 grid-cols-4 grid-rows-1 gap-2 [&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-sm dark:shadow-gray-700/50">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-sm dark:shadow-gray-700/50 overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 1" src="path/to/image.jpg">
</div>
</div>
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-md dark:shadow-gray-700/50">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-md dark:shadow-gray-700/50 overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 2" src="path/to/image.jpg">
</div>
</div>
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-lg dark:shadow-gray-600/50">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-lg dark:shadow-gray-600/50 overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 3" src="path/to/image.jpg">
</div>
</div>
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-xl dark:shadow-gray-500/50">
<div
class="relative flex items-center justify-center rounded-full size-12 text-base shadow-xl dark:shadow-gray-500/50 overflow-hidden bg-gray-500 dark:bg-gray-600 text-white dark:text-white hover:text-gray-100 dark:hover:text-gray-200 border-gray-600 dark:border-gray-500">
<img width="400" height="400" alt="User 4" src="path/to/image.jpg">
</div>
</div>
</div>
---
import { AvatarGroup } from '@/components/ui/avatargroup';
import { Avatar } from '@/components/ui/avatar';
import sampleAvatar from '@/images/sample-avatar.jpg';
---
<AvatarGroup>
<Avatar src={sampleAvatar} alt="User 1" shadow="sm" />
<Avatar src={sampleAvatar2} alt="User 2" shadow="md" />
<Avatar src={sampleAvatar3} alt="User 3" shadow="lg" />
<Avatar src={sampleAvatar4} alt="User 4" shadow="xl" />
</AvatarGroup> ---
// Imports
import { type HTMLAttributes } from "astro/types";
import { tv, type VariantProps } from "@utils/custom-tv";
import { colorPalette } from "@utils/colorUtils";
import { twMerge } from "tailwind-merge";
// Types and Interfaces
type AvatarGroupVariants = VariantProps<typeof avatarGroupStyles>;
interface Props extends HTMLAttributes<"div">, AvatarGroupVariants {
layout?: "stack" | "grid";
columns?: number;
rows?: number;
spacing?: "tight" | "normal" | "loose";
borderColor?: keyof typeof colorPalette;
class?: string;
preview?: boolean;
}
// Styles
const avatarGroupStyles = tv({
base: "flex",
variants: {
layout: {
stack: "-space-x-4",
grid: "grid w-fit",
},
columns: {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
},
rows: {
1: "grid-rows-1",
2: "grid-rows-2",
3: "grid-rows-3",
4: "grid-rows-4",
5: "grid-rows-5",
6: "grid-rows-6",
},
spacing: {
tight: "gap-1",
normal: "gap-2",
loose: "gap-3",
},
preview: {
true: "items-center gap-12 mx-auto w-fit p-4",
false: "",
},
},
defaultVariants: {
layout: "stack",
columns: 4,
rows: 1,
spacing: "normal",
preview: false,
},
compoundVariants: [
{
layout: "stack",
class: "[&>*]:z-0 [&>*:hover]:z-10 w-fit mx-auto",
},
],
});
// Component Logic
const {
layout = "stack",
columns = 4,
rows = 1,
spacing = "normal",
class: className = "",
preview = false,
} = Astro.props as Props;
const containerClasses = twMerge(
avatarGroupStyles({ layout, columns, rows, spacing, preview }),
className,
);
// PropTypes for documentation
export const propTypes = {
layout: {
type: ["stack", "grid"],
description: "Layout of the avatar group",
default: "stack",
},
columns: {
type: "number",
description: "Number of columns for grid layout",
default: 4,
},
rows: {
type: "number",
description: "Number of rows for grid layout",
default: 1,
},
spacing: {
type: ["tight", "normal", "loose"],
description: "Spacing between avatars",
default: "normal",
},
borderColor: {
type: Object.keys(colorPalette),
description: "Color of the avatar border",
default: "white",
},
class: {
type: "string",
description: "Additional CSS classes to apply to the avatar group",
},
preview: {
type: "boolean",
description: "Whether to apply preview styling",
default: false,
},
};
---
<div class={containerClasses}>
<slot />
</div>
Component Properties
| Property | Type | Default | Description |
|---|---|---|---|
| layout | stack | grid | "stack" | Layout of the avatar group |
| columns | number | 4 | Number of columns for grid layout |
| rows | number | 1 | Number of rows for grid layout |
| spacing | tight | normal | loose | "normal" | Spacing between avatars |
| borderColor | white | slate | gray | zinc | neutral | stone | red | orange | amber | yellow | lime | green | emerald | teal | cyan | sky | blue | indigo | violet | purple | fuchsia | pink | rose | "white" | Color of the avatar border |
| class | string | - | Additional CSS classes to apply to the avatar group |
| preview | boolean | false | Whether to apply preview styling |