askill
tanstack-patterns

tanstack-patternsSafety 100Repository

TanStack ecosystem overview and shared patterns. Use when working with TanStack libraries or understanding headless UI architecture.

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

TanStack Ecosystem Patterns

Purpose

Provide an overview of the TanStack ecosystem and common patterns shared across TanStack libraries, including type-safe design principles, headless UI architecture, adapter patterns, and integration strategies for React, Vue, Solid, and other frameworks.

Ecosystem Overview

The TanStack ecosystem provides headless, type-safe, framework-agnostic libraries for common frontend needs:

  • TanStack Query - Async state management and data fetching
  • TanStack Router - Type-safe routing with built-in data loading
  • TanStack Table - Headless table/grid UI logic
  • TanStack Form - Type-safe form state management
  • TanStack Virtual - Virtualization for large lists and grids
  • TanStack Start - Full-stack framework built on TanStack Router

Core Design Principles

Headless Architecture

All TanStack libraries provide logic without UI, allowing full control over rendering:

// TanStack Table: headless logic, you provide the UI
const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
});

// You render however you want
return (
  <table>
    <thead>
      {table.getHeaderGroups().map((headerGroup) => (
        <tr key={headerGroup.id}>
          {headerGroup.headers.map((header) => (
            <th key={header.id}>
              {flexRender(header.column.columnDef.header, header.getContext())}
            </th>
          ))}
        </tr>
      ))}
    </thead>
  </table>
);

Type Safety First

All libraries leverage TypeScript generics for end-to-end type safety:

// Type-safe query keys and return types
const { data } = useQuery<User[], Error>({
  queryKey: ["users"],
  queryFn: fetchUsers,
});

// Type-safe route definitions
const routeTree = rootRoute.addChildren([
  indexRoute,
  usersRoute.addChildren([userRoute]),
]);

// Type-safe column definitions
const columns: ColumnDef<User>[] = [
  { accessorKey: "name", header: "Name" },
  { accessorKey: "email", header: "Email" },
];

Framework Adapters

Libraries ship core logic separately from framework bindings:

// Core (framework-agnostic)
import { QueryClient } from "@tanstack/query-core";

// React adapter
import { useQuery } from "@tanstack/react-query";

// Vue adapter
import { useQuery } from "@tanstack/vue-query";

// Solid adapter
import { createQuery } from "@tanstack/solid-query";

TanStack Virtual

Efficiently render large lists by only rendering visible items:

import { useVirtualizer } from "@tanstack/react-virtual";
import { useRef } from "react";

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
    overscan: 5,
  });

  return (
    <div ref={parentRef} style={{ height: "400px", overflow: "auto" }}>
      <div style={{ height: `${virtualizer.getTotalSize()}px`, position: "relative" }}>
        {virtualizer.getVirtualItems().map((virtualItem) => (
          <div
            key={virtualItem.key}
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: `${virtualItem.size}px`,
              transform: `translateY(${virtualItem.start}px)`,
            }}
          >
            {items[virtualItem.index].name}
          </div>
        ))}
      </div>
    </div>
  );
}

TanStack Form

Type-safe form management with framework adapters:

import { useForm } from "@tanstack/react-form";
import { zodValidator } from "@tanstack/zod-form-adapter";
import { z } from "zod";

function ContactForm() {
  const form = useForm({
    defaultValues: { name: "", email: "" },
    onSubmit: async ({ value }) => {
      await submitContact(value);
    },
    validatorAdapter: zodValidator(),
  });

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        form.handleSubmit();
      }}
    >
      <form.Field
        name="name"
        validators={{ onChange: z.string().min(1, "Required") }}
        children={(field) => (
          <div>
            <input
              value={field.state.value}
              onChange={(e) => field.handleChange(e.target.value)}
            />
            {field.state.meta.errors.map((err) => (
              <span key={err}>{err}</span>
            ))}
          </div>
        )}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Combining Libraries

Query + Router (Data Loading)

import { createFileRoute } from "@tanstack/react-router";
import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";

const userQueryOptions = (id: string) =>
  queryOptions({
    queryKey: ["users", id],
    queryFn: () => fetchUser(id),
  });

export const Route = createFileRoute("/users/$userId")({
  loader: ({ context: { queryClient }, params: { userId } }) =>
    queryClient.ensureQueryData(userQueryOptions(userId)),
  component: UserPage,
});

function UserPage() {
  const { userId } = Route.useParams();
  const { data: user } = useSuspenseQuery(userQueryOptions(userId));
  return <h1>{user.name}</h1>;
}

Query + Table (Server-Side Data)

function UsersTable() {
  const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });

  const { data } = useQuery({
    queryKey: ["users", pagination],
    queryFn: () => fetchUsers(pagination),
  });

  const table = useReactTable({
    data: data?.rows ?? [],
    columns,
    rowCount: data?.totalCount,
    state: { pagination },
    onPaginationChange: setPagination,
    manualPagination: true,
    getCoreRowModel: getCoreRowModel(),
  });

  return <DataTable table={table} />;
}

Best Practices

  • Leverage headless architecture for full control over UI and styling
  • Use TypeScript generics to get end-to-end type safety across all libraries
  • Combine TanStack Query with Router for data loading at the route level
  • Use TanStack Virtual for lists with more than 100 items
  • Use queryOptions() factory for reusable, type-safe query configurations
  • Prefer useSuspenseQuery with route-level loaders for seamless data flow
  • Use manualPagination, manualSorting, and manualFiltering for server-driven tables
  • Keep core logic framework-agnostic; use adapters for React, Vue, or Solid
  • Use overscan in virtualizers to pre-render items for smoother scrolling
  • Pin TanStack library versions together to avoid compatibility issues

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/11/2026

An excellent technical reference for the TanStack ecosystem, providing clear architectural patterns, type-safe code examples, and integration strategies.

100
95
100
95
90

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publisherqazuor

Tags

No tags yet.