For

Declarative list rendering with built-in empty state handling for cleaner JSX.

The For component provides a declarative way to render lists and arrays in React, with automatic empty state handling and support for numeric ranges.

Installation

npm install @zayne-labs/ui-react

Preview

Loading...

Usage

Pass an array to each and utilize the render prop to define your items.

import { For } from "@zayne-labs/ui-react/common/for";

function UserList({ users }) {
  return (
    <For each={users} fallback={<p>No users joined yet.</p>}>
      {(user) => (
        <div key={user.id} className="p-2 border-b">
          {user.name}
        </div>
      )}
    </For>
  );
}

Pass a number to each to repeat content a specific number of times. Perfect for skeletons!

import { For } from "@zayne-labs/ui-react/common/for";

function TableSkeleton() {
  return (
    <For each={5}>
      {(i) => (
        <div key={i} className="h-8 w-full animate-pulse bg-gray-100 rounded" />
      )}
    </For>
  );
}

Use renderItem prop for cleaner syntax when you need to pass the render function as a prop.

import { ForWithWrapper } from "@zayne-labs/ui-react/common/for";

function ProductGrid({ products }) {
  return (
    <ForWithWrapper
      className="grid grid-cols-3 gap-4"
      each={products}
      renderItem={(product) => (
        <li key={product.id} className="p-4 border rounded">
          <h3>{product.name}</h3>
          <p>${product.price}</p>
        </li>
      )}
    />
  );
}

Component Source

import type {	DiscriminatedRenderItemProps,	PolymorphicPropsStrict,} from "@zayne-labs/toolkit-react/utils";import { isArray, isNumber, type Prettify } from "@zayne-labs/toolkit-type-helpers";type ArrayOrNumber = number | readonly unknown[];type GetArrayItemType<TArray extends ArrayOrNumber> =	TArray extends readonly unknown[] ? TArray[number]	: TArray extends number ? number	: unknown;type RenderPropFn<TArray extends ArrayOrNumber> = (	item: GetArrayItemType<TArray>,	index: number,	array: Array<GetArrayItemType<TArray>>) => React.ReactNode;export type ForRenderProps<TArray extends ArrayOrNumber> = DiscriminatedRenderItemProps<	RenderPropFn<TArray>>;/* eslint-disable perfectionist/sort-intersection-types -- Prefer the object to come first before the render props */export type ForProps<TArray extends ArrayOrNumber> = Prettify<	{		each: TArray;		fallback?: React.ReactNode;	} & ForRenderProps<TArray>>;/* eslint-enable perfectionist/sort-intersection-types -- Prefer the object to come first before the render props */const isArrayEmpty = <TArray extends ArrayOrNumber>(each: TArray) => {	// eslint-disable-next-line ts-eslint/no-unnecessary-condition -- Allow	return each == null || (isNumber(each) && each === 0) || (isArray(each) && each.length === 0);};export function For<const TArray extends ArrayOrNumber>(props: ForProps<TArray>) {	const { children, each, fallback = null, renderItem } = props;	if (isArrayEmpty(each)) {		return fallback;	}	const resolvedArray = isNumber(each) ? [...Array(each).keys()] : (each as unknown[]);	const selectedChildren = typeof children === "function" ? children : renderItem;	const elementList = resolvedArray.map((...params) => {		type Params = Parameters<RenderPropFn<TArray>>;		return selectedChildren(...(params as Params));	});	return elementList;}export type ForWithWrapperProps<	TArray extends ArrayOrNumber,	TElement extends React.ElementType = "ul",> = PolymorphicPropsStrict<TElement, ForProps<TArray>> & { displayFallBackWhenEmpty?: boolean };export function ForWithWrapper<	const TArray extends ArrayOrNumber,	TElement extends React.ElementType = "ul",>(props: ForWithWrapperProps<TArray, TElement>) {	const {		as: ListContainer = "ul",		children,		displayFallBackWhenEmpty = false,		each,		fallback = null,		renderItem,		...restOfProps	} = props;	if (displayFallBackWhenEmpty && isArrayEmpty(each)) {		return fallback;	}	return (		<ListContainer {...restOfProps}>			<For {...({ children, each, fallback, renderItem } as ForProps<TArray>)} />		</ListContainer>	);}

Component API

Examples

Semantic Table Rows

import { ForWithWrapper } from "@zayne-labs/ui-react/common/for";

function StatisticsTable({ data }) {
	return (
		<table>
			<ForWithWrapper as="tbody" each={data}>
				{(row) => (
					<tr key={row.id}>
						<td>{row.label}</td>
						<td>{row.value}</td>
					</tr>
				)}
			</ForWithWrapper>
		</table>
	);
}
Edit on GitHub

Last updated on

On this page