---
globs: *.ts,*.tsx
description: Development guidelines for React/TypeScript components in the Quartz framework
---
# Component Development Guidelines
## Quartz Component Architecture
Quartz uses Preact (React-compatible) for components. All UI components live in [quartz/components/](mdc:quartz/components/).
### Component Types
1. **Page Components** (`quartz/components/pages/`) - Full page layouts
2. **UI Components** (`quartz/components/`) - Reusable interface elements
3. **Script Components** (`quartz/components/scripts/`) - Client-side functionality
### Component Structure
Every Quartz component should follow this pattern:
```typescript
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
const ComponentName: QuartzComponent = ({
fileData,
cfg,
tree,
displayClass
}: QuartzComponentProps) => {
// Component logic here
return
{/* JSX content */}
}
// Optional: Add CSS if needed
ComponentName.css = "component-name.scss"
// Export as constructor
export default (() => ComponentName) satisfies QuartzComponentConstructor
```
## TypeScript Conventions
### Type Safety
- Always use proper TypeScript types, never `any`
- Import types from [quartz/components/types.ts](mdc:quartz/components/types.ts)
- Use `QuartzComponentProps` for component props
- For utility functions, import from [quartz/util/](mdc:quartz/util/)
### Required Imports
```typescript
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
```
### File Data Access
Components receive file metadata through `fileData`:
```typescript
const title = fileData.frontmatter?.title
const slug = fileData.slug
const content = fileData.description
```
## Component Patterns
### Conditional Rendering
```typescript
if (!fileData.frontmatter?.title) {
return null
}
```
### CSS Classes
- Use `displayClass` prop for responsive visibility
- Add component-specific classes with BEM methodology
- SCSS files should be named to match component
### Client-Side Scripts
For interactive components, create accompanying scripts in `quartz/components/scripts/`:
```typescript
// In script file
document.addEventListener("nav", () => {
// Re-initialize after page navigation
})
```
## Component Registration
### In quartz.layout.ts
Add new components to the appropriate layout section:
```typescript
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.Breadcrumbs(),
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
],
left: [
Component.PageTitle(),
Component.MobileOnly(Component.Spacer()),
Component.Search(),
Component.Darkmode(),
Component.DesktopOnly(Component.Explorer()),
],
right: [
Component.Graph(),
Component.DesktopOnly(Component.TableOfContents()),
Component.Backlinks(),
],
}
```
### Component Exports
All components must be exported in [quartz/components/index.ts](mdc:quartz/components/index.ts):
```typescript
export { default as YourComponent } from "./YourComponent"
```
## Best Practices
### Performance
- Use functional components (avoid class components)
- Minimize DOM manipulation; prefer declarative JSX
- For heavy computations, consider memoization
### Accessibility
- Use semantic HTML elements
- Include proper ARIA labels where needed
- Ensure keyboard navigation works
### Responsive Design
- Use `displayClass` for responsive hiding/showing
- Test components at different screen sizes
- Consider mobile-first design approach
### Error Handling
- Handle missing data gracefully
- Provide fallbacks for optional frontmatter fields
- Use optional chaining: `fileData.frontmatter?.field`
## Debugging
- Use `console.log` sparingly; prefer TypeScript for catching errors
- Test component isolation by temporarily removing from layout
- Check browser dev tools for client-side script errors
## Integration with Plugins
Components often work with Quartz plugins:
- Transformers modify content before components receive it
- Emitters use components to generate final HTML
- Check [quartz/plugins/](mdc:quartz/plugins/) for relevant plugin APIs