shadimage
ilinxa
blockarticle-metasource: ok · hit

Article Meta

Icon-and-value metadata strip for article headers — author, date, read time, view count, or any custom pairs.

npx shadcn add "https://ui.ilinxa.com/r/article-meta.json"
free

Where it goes

navbarblog-list

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
iconslucide-react

Files4 · source cached 10/12/2026, 2:41:11 PM

src/registry/components/data/article-meta/article-meta.tsx
import { memo } from "react";
import { cn } from "@/lib/utils";
import { MetaItem } from "./parts/meta-item";
import type { ArticleMetaProps } from "./types";

const ALIGN_CLASS = {
  start: "justify-start",
  center: "justify-center",
  end: "justify-end",
} as const;

function ArticleMetaInner(props: ArticleMetaProps) {
  const {
    items,
    linkComponent = "a",
    divider = false,
    align = "start",
    gapClass = "gap-6",
    className,
    itemClassName,
    iconClassName,
  } = props;

  return (
    <ul
      role="list"
      className={cn(
        "flex flex-wrap items-center text-muted-foreground list-none",
        gapClass,
        ALIGN_CLASS[align],
        divider && "pb-8 border-b border-border",
        className
      )}
    >
      {items.map((item) => (
        <MetaItem
          key={item.id}
          item={item}
          linkComponent={linkComponent}
          itemClassName={itemClassName}
          iconClassName={iconClassName}
        />
      ))}
    </ul>
  );
}

export const ArticleMeta = memo(ArticleMetaInner);
ArticleMeta.displayName = "ArticleMeta";
src/registry/components/data/article-meta/index.ts
export { ArticleMeta } from "./article-meta";
export type {
  ArticleMetaProps,
  ArticleMetaItem,
} from "./types";
src/registry/components/data/article-meta/types.ts
import type { ComponentType, ElementType, ReactNode } from "react";

export interface ArticleMetaItem {
  id: string;
  icon?: ComponentType<{ className?: string }>;
  value: ReactNode;
  href?: string;
  ariaLabel?: string;
}

export interface ArticleMetaProps {
  items: ReadonlyArray<ArticleMetaItem>;
  linkComponent?: ElementType;
  divider?: boolean;
  align?: "start" | "center" | "end";
  gapClass?: string;
  className?: string;
  itemClassName?: string;
  iconClassName?: string;
}
src/registry/components/data/article-meta/parts/meta-item.tsx
import type { ElementType } from "react";
import { cn } from "@/lib/utils";
import type { ArticleMetaItem } from "../types";

interface MetaItemProps {
  item: ArticleMetaItem;
  linkComponent: ElementType;
  itemClassName?: string;
  iconClassName?: string;
}

export function MetaItem({
  item,
  linkComponent: LinkEl,
  itemClassName,
  iconClassName,
}: MetaItemProps) {
  const Icon = item.icon;

  const inner = (
    <>
      {Icon ? (
        <Icon className={cn("w-4 h-4", iconClassName)} aria-hidden="true" />
      ) : null}
      <span>{item.value}</span>
    </>
  );

  return (
    <li className={cn("flex items-center gap-2", itemClassName)}>
      {item.href ? (
        <LinkEl
          href={item.href}
          aria-label={item.ariaLabel}
          className="inline-flex items-center gap-2 hover:text-foreground transition-colors rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
        >
          {inner}
        </LinkEl>
      ) : item.ariaLabel ? (
        <span aria-label={item.ariaLabel} className="inline-flex items-center gap-2">
          {inner}
        </span>
      ) : (
        <span className="inline-flex items-center gap-2">{inner}</span>
      )}
    </li>
  );
}

More from ilinxa

Browse all components in this library →