All skills
davila7 avatar

/frontend-dev-guidelines

@1deb97c

Frontend development guidelines for React/TypeScript applications. Modern patterns including Suspense, lazy loading, useSuspenseQuery, file organization with features directory, MUI v7 styling, TanStack Router, performance optimization, and TypeScript best practices. Use when creating components, pages, features, fetching data, styling, routing, or working with frontend code.

Use this Skill: https://skilld.dev/gh/davila7/claude-code-templates/frontend-dev-guidelines

This session only. Nothing lands on disk.

resourcesrouting-guide.md

≈1.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Routing Guide

TanStack Router implementation with folder-based routing and lazy loading patterns.


TanStack Router Overview

TanStack Router with file-based routing:

  • Folder structure defines routes
  • Lazy loading for code splitting
  • Type-safe routing
  • Breadcrumb loaders

Folder-Based Routing

Directory Structure

routes/
  __root.tsx                    # Root layout
  index.tsx                     # Home route (/)
  posts/
    index.tsx                   # /posts
    create/
      index.tsx                 # /posts/create
    $postId.tsx                 # /posts/:postId (dynamic)
  comments/
    index.tsx                   # /comments

Pattern:

  • index.tsx = Route at that path
  • $param.tsx = Dynamic parameter
  • Nested folders = Nested routes

Basic Route Pattern

Example from posts/index.tsx

/**
 * Posts route component
 * Displays the main blog posts list
 */

import { createFileRoute } from '@tanstack/react-router';
import { lazy } from 'react';

// Lazy load the page component
const PostsList = lazy(() =>
    import('@/features/posts/components/PostsList').then(
        (module) => ({ default: module.PostsList }),
    ),
);

export const Route = createFileRoute('/posts/')({
    component: PostsPage,
    // Define breadcrumb data
    loader: () => ({
        crumb: 'Posts',
    }),
});

function PostsPage() {
    return (
        <PostsList
            title='All Posts'
            showFilters={true}
        />
    );
}

export default PostsPage;

Key Points:

  • Lazy load heavy components
  • createFileRoute with route path
  • loader for breadcrumb data
  • Page component renders content
  • Export both Route and component

Lazy Loading Routes

Named Export Pattern

import { lazy } from 'react';

// For named exports, use .then() to map to default
const MyPage = lazy(() =>
    import('@/features/my-feature/components/MyPage').then(
        (module) => ({ default: module.MyPage })
    )
);

Default Export Pattern

import { lazy } from 'react';

// For default exports, simpler syntax
const MyPage = lazy(() => import('@/features/my-feature/components/MyPage'));

Why Lazy Load Routes?

  • Code splitting - smaller initial bundle
  • Faster initial page load
  • Load route code only when navigated to
  • Better performance

createFileRoute

Basic Configuration

export const Route = createFileRoute('/my-route/')({
    component: MyRoutePage,
});

function MyRoutePage() {
    return <div>My Route Content</div>;
}

With Breadcrumb Loader

export const Route = createFileRoute('/my-route/')({
    component: MyRoutePage,
    loader: () => ({
        crumb: 'My Route Title',
    }),
});

Breadcrumb appears in navigation/app bar automatically.

With Data Loader

export const Route = createFileRoute('/my-route/')({
    component: MyRoutePage,
    loader: async () => {
        // Can prefetch data here
        const data = await api.getData();
        return { crumb: 'My Route', data };
    },
});

With Search Params

export const Route = createFileRoute('/search/')({
    component: SearchPage,
    validateSearch: (search: Record<string, unknown>) => {
        return {
            query: (search.query as string) || '',
            page: Number(search.page) || 1,
        };
    },
});

function SearchPage() {
    const { query, page } = Route.useSearch();
    // Use query and page
}

Dynamic Routes

Parameter Routes

// routes/users/$userId.tsx

export const Route = createFileRoute('/users/$userId')({
    component: UserPage,
});

function UserPage() {
    const { userId } = Route.useParams();

    return <UserProfile userId={userId} />;
}

Multiple Parameters

// routes/posts/$postId/comments/$commentId.tsx

export const Route = createFileRoute('/posts/$postId/comments/$commentId')({
    component: CommentPage,
});

function CommentPage() {
    const { postId, commentId } = Route.useParams();

    return <CommentEditor postId={postId} commentId={commentId} />;
}

Navigation

Programmatic Navigation

import { useNavigate } from '@tanstack/react-router';

export const MyComponent: React.FC = () => {
    const navigate = useNavigate();

    const handleClick = () => {
        navigate({ to: '/posts' });
    };

    return <Button onClick={handleClick}>View Posts</Button>;
};

With Parameters

const handleNavigate = () => {
    navigate({
        to: '/users/$userId',
        params: { userId: '123' },
    });
};

With Search Params

const handleSearch = () => {
    navigate({
        to: '/search',
        search: { query: 'test', page: 1 },
    });
};

Route Layout Pattern

Root Layout (__root.tsx)

import { createRootRoute, Outlet } from '@tanstack/react-router';
import { Box } from '@mui/material';
import { CustomAppBar } from '~components/CustomAppBar';

export const Route = createRootRoute({
    component: RootLayout,
});

function RootLayout() {
    return (
        <Box>
            <CustomAppBar />
            <Box sx={{ p: 2 }}>
                <Outlet />  {/* Child routes render here */}
            </Box>
        </Box>
    );
}

Nested Layouts

// routes/dashboard/index.tsx
export const Route = createFileRoute('/dashboard/')({
    component: DashboardLayout,
});

function DashboardLayout() {
    return (
        <Box>
            <DashboardSidebar />
            <Box sx={{ flex: 1 }}>
                <Outlet />  {/* Nested routes */}
            </Box>
        </Box>
    );
}

Complete Route Example

/**
 * User profile route
 * Path: /users/:userId
 */

import { createFileRoute } from '@tanstack/react-router';
import { lazy } from 'react';
import { SuspenseLoader } from '~components/SuspenseLoader';

// Lazy load heavy component
const UserProfile = lazy(() =>
    import('@/features/users/components/UserProfile').then(
        (module) => ({ default: module.UserProfile })
    )
);

export const Route = createFileRoute('/users/$userId')({
    component: UserPage,
    loader: () => ({
        crumb: 'User Profile',
    }),
});

function UserPage() {
    const { userId } = Route.useParams();

    return (
        <SuspenseLoader>
            <UserProfile userId={userId} />
        </SuspenseLoader>
    );
}

export default UserPage;

Summary

Routing Checklist:

  • ✅ Folder-based: routes/my-route/index.tsx
  • ✅ Lazy load components: React.lazy(() => import())
  • ✅ Use createFileRoute with route path
  • ✅ Add breadcrumb in loader function
  • ✅ Wrap in SuspenseLoader for loading states
  • ✅ Use Route.useParams() for dynamic params
  • ✅ Use useNavigate() for programmatic navigation

See Also:

Source: SKILL.md on GitHub

1 alert16d4 checks · Risk HIGH
  • Gen Agent Trust Hub16d

    The skill recommends the use of non-standard and potentially malicious Node.js packages that appear to be typosquats of the popular react-hook-form library. Furthermore, the documentation contains a systematic and deceptive string replacement pattern where 'form' is replaced with 'blog' (e.g., 'transblogers', 'Perblogance'), which could be used to evade security filters or cause the generation of broken code.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    11/11 files flagged

Signed by skilld at 1deb97c. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 16 hours ago.

Activeupdated 8 months ago

README badge

README badge for davila7/claude-code-templates/frontend-dev-guidelines