Skip to content

Instantly share code, notes, and snippets.

@burkeholland
Created February 28, 2025 21:00
Show Gist options
  • Save burkeholland/bfa38d14b3ec4d5f1ec509656370d62e to your computer and use it in GitHub Desktop.
Save burkeholland/bfa38d14b3ec4d5f1ec509656370d62e to your computer and use it in GitHub Desktop.
Custom Instructions Example

Best Practices for AstroJS, React, Tailwind CSS, and Nanostores

Application Structure

Project Organization

src/
├── components/
│   ├── ui/              # Reusable UI components
│   └── features/        # Feature-specific components
├── layouts/             # Astro layout components
├── pages/               # Astro pages (file-based routing)
├── stores/              # Nanostores state management
├── utils/               # Utility functions and helpers
├── styles/              # Global styles and Tailwind customizations
└── assets/              # Static assets like images, fonts

Feature Organization (for larger applications)

src/
├── features/
│   ├── auth/
│   │   ├── components/  # React components specific to auth
│   │   ├── stores/      # Auth-related nanostores
│   │   └── utils/       # Auth-specific utilities
│   └── products/
│       ├── components/
│       └── stores/
├── shared/              # Shared components, stores, utilities
│   ├── components/
│   └── utils/
└── pages/               # Astro pages using components from features

Component Creation Guidelines

When to Create a New Component

  • Create a new component when:
    • UI element will be reused in multiple places
    • A section of UI exceeds 100 lines of code
    • A section has its own distinct responsibility or purpose
    • Logic for a section becomes complex (more than 3 state variables or hooks)
    • Component has a specific interaction pattern (dropdown, modal, etc.)

When NOT to Create a New Component

  • Avoid creating components that are:
    • Used only once and very simple (under 50 lines)
    • Too granular (e.g., a single styled button with no special behavior)
    • Breaking a component only for the sake of smaller files

Component Types

  • Astro Components (.astro): Use for:

    • Layout components
    • Static content
    • Components that don't need client-side interactivity
  • React Components (.jsx/.tsx): Use for:

    • Interactive UI elements
    • Components that need to maintain state
    • Sections requiring event handlers and user interactions

Nanostores Best Practices

Store Organization

  • Create a separate store file for each domain/feature
  • Export actions and getters, not the raw store
  • Group related stores in directories by feature

Keep Stores Simple

  • Focus each store on a single responsibility
  • Use atomic stores for primitive values when possible
  • Use map stores for related data structures
  • Create computed values with computed for derived state
  • Separate UI state from domain data

Store Actions Pattern

// userStore.js
import { atom, map } from 'nanostores';

// Create the store
export const userStore = map({
  user: null,
  isLoading: false,
  error: null
});

// Export actions, not the raw store
export function setUser(userData) {
  userStore.setKey('user', userData);
}

export function clearUser() {
  userStore.setKey('user', null);
}

export async function fetchUser(id) {
  userStore.setKey('isLoading', true);
  userStore.setKey('error', null);
  
  try {
    const response = await fetch(`/api/users/${id}`);
    const data = await response.json();
    userStore.setKey('user', data);
  } catch (error) {
    userStore.setKey('error', error.message);
  } finally {
    userStore.setKey('isLoading', false);
  }
}

Markup and Tailwind CSS Guidelines

Keep Markup Simple

  • Aim for a maximum nesting depth of 3-4 levels
  • Avoid excessive conditional rendering that creates multiple levels of nesting
  • Use sensible defaults for CSS with minimal override complexity
  • Leverage Astro's slot system for flexible component composition

Tailwind Best Practices

  • Use Tailwind's utility classes directly in HTML/JSX for most styling
  • Extract reusable patterns to components rather than creating custom classes
  • For complex components, consider grouping Tailwind classes with template literals
  • Utilize Tailwind's @apply directive sparingly and only for highly reused patterns
  • Create consistent spacing, color and typography systems through Tailwind configuration

Component Composition Example

// Bad: Overly nested and complex
<div className="p-4 border rounded-lg shadow-md">
  <div className="flex flex-col space-y-4">
    <div className="bg-gray-100 p-3 rounded">
      <div className="flex items-center justify-between">
        <h3 className="text-lg font-bold">{title}</h3>
        {isEditable && (
          <div className="flex space-x-2">
            <button className="px-2 py-1 bg-blue-500 text-white rounded">Edit</button>
            <button className="px-2 py-1 bg-red-500 text-white rounded">Delete</button>
          </div>
        )}
      </div>
    </div>
  </div>
</div>

// Good: Flatter, component-based approach
<Card>
  <CardHeader>
    <h3 className="text-lg font-bold">{title}</h3>
    {isEditable && <ActionButtons actions={['edit', 'delete']} />}
  </CardHeader>
</Card>

Astro and React Integration

Astro Components Best Practices

  • Use Astro for static or mostly-static pages and layouts
  • Pass data to React components as props
  • Take advantage of Astro's built-in data fetching for SEO-critical content
  • Add client directives only where needed:
    • client:load - Hydrate component immediately on page load
    • client:idle - Hydrate once the browser is idle
    • client:visible - Hydrate once the component is visible in viewport
    • client:only - Only renders on client-side, never SSR

React with Nanostores in Astro

  • Use @nanostores/react for React components to access stores
  • Import useStore hook to subscribe components to store changes
  • Keep React components focused on UI rendering
  • Move business logic and data fetching to store actions
// React component with nanostores
import { useStore } from '@nanostores/react';
import { todoStore, addTodo, toggleTodo } from '../stores/todoStore';

function TodoList() {
  const todos = useStore(todoStore);
  const [newTodo, setNewTodo] = useState('');
  
  const handleSubmit = (e) => {
    e.preventDefault();
    if (newTodo.trim()) {
      addTodo(newTodo);
      setNewTodo('');
    }
  };
  
  return (
    // Component JSX
  );
}

Code Elegance Guidelines

Simplicity Principles

  • Functions should generally be under 20 lines
  • Components should generally be under 150 lines
  • Aim for component props to be under 7 items
  • Use destructuring for cleaner component interfaces
  • Group related state items in meaningful objects
  • Follow the principle of least knowledge (components only know what they need)

Performance Considerations

  • Implement lazy loading for heavier React components with client:only when needed
  • Use Island Architecture to minimize JavaScript sent to the client
  • Leverage Astro's static generation for content that doesn't change frequently
  • Build component-specific stores to avoid unnecessary re-renders

Code Organization

  • Default export for the main component in a file
  • Named exports for utility functions
  • Group related hooks at the top of a component
  • Keep event handlers inside the component, but separate from the JSX
@Martin-Ferrero-Thompson

Really enjoyed the video and I think the introduction of AI into the design and coding of applications is awesome.

I can see that some folks are really worried about their work being taken over by AI Agents etc. I believe it is still very important at this time that the experience and knowledge that "real" developers have is still key to being able to direct the AI Coding tools to produce first class apps.

I really like the work you did around the PRD and Best Practices and see this document have produced is really, really good....

However, for those of us who dont necessarilly have the depth of experience and skills that you have I would be really interested to understand more about the process of using AI to help generate these kind of documents - Is this something you are able to do, or would be able to do?

Keep up the awesome videos Burke

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment