| name | ultracite |
| description | Enforce strict type safety, accessibility standards, and code quality for TypeScript/JavaScript projects using Biome's formatter and linter. Use when writing, reviewing, or fixing TS/JS/TSX/JSX code, checking for a11y issues, linting errors, type safety problems, or when the user mentions code quality, formatting, accessibility, or best practices. |
| allowed-tools | Read, Grep, Glob, Edit |
Ultracite - AI-Ready Formatter and Linter
Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Biome's lightning-fast formatter and linter.
Key Principles
- Zero configuration required: Works out of the box
- Subsecond performance: Lightning-fast checks and fixes
- Maximum type safety: Catch errors before runtime
- AI-friendly code generation: Optimized for AI-assisted development
Before Writing Code
When writing or reviewing code, follow this checklist:
- Analyze existing patterns in the codebase
- Consider edge cases and error scenarios
- Follow the rules below strictly
- Validate accessibility requirements
Common Commands
npx ultracite init
npx ultracite fix
npx ultracite check
Instructions
When working with TypeScript/JavaScript code:
- Read the code using the Read tool before making changes
- Check for violations of the rules below
- Apply fixes using the Edit tool
- Verify accessibility standards are met
- Ensure type safety with TypeScript
Core Rule Categories
1. Accessibility (a11y)
Critical accessibility requirements:
- ❌ Don't use
accessKey attribute on any HTML element
- ❌ Don't set
aria-hidden="true" on focusable elements
- ❌ Don't use distracting elements like
<marquee> or <blink>
- ❌ Don't include "image", "picture", or "photo" in img alt prop
- ✅ Make sure label elements have text content and are associated with an input
- ✅ Give all elements requiring alt text meaningful information for screen readers
- ✅ Always include a
type attribute for button elements
- ✅ Always include a
lang attribute on the html element
- ✅ Always include a
title attribute for iframe elements
- ✅ Accompany
onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
- ✅ Accompany
onMouseOver/onMouseOut with onFocus/onBlur
- ✅ Include caption tracks for audio and video elements
- ✅ Use semantic elements instead of role attributes in JSX
- ✅ Always include a
title element for SVG elements
Example - Good Accessibility:
<button
type="button"
onClick={handleClick}
onKeyDown={handleKeyDown}
>
Submit
</button>
<img src="/photo.jpg" alt="Team celebrating product launch" />
<button onClick={handleClick}>Submit</button>
<img src="/photo.jpg" alt="image of photo" />
2. React and JSX Best Practices
Critical React requirements:
- ❌ Don't destructure props inside JSX components in Solid projects
- ❌ Don't define React components inside other components
- ❌ Don't use Array index in keys
- ❌ Don't assign JSX properties multiple times
- ❌ Don't use both
children and dangerouslySetInnerHTML props
- ❌ Don't pass children as props
- ✅ Make sure all dependencies are correctly specified in React hooks
- ✅ Make sure all React hooks are called from the top level
- ✅ Don't forget key props in iterators and collection literals
- ✅ Use
<>...</> instead of <Fragment>...</Fragment>
Example - Good React Patterns:
function UserList({ users }) {
const [selected, setSelected] = useState(null);
useEffect(() => {
loadData();
}, [loadData]);
return (
<>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</>
);
}
function ParentComponent() {
function ChildComponent() {
useEffect(() => {
doSomething();
}, []);
return <div>Child</div>;
}
return items.map((item, i) => (
<div key={i}>{item}</div>
));
}
3. TypeScript Best Practices
Critical TypeScript requirements:
- ❌ Don't use TypeScript enums (use
as const objects instead)
- ❌ Don't use the
any type
- ❌ Don't use non-null assertions with the exclamation mark postfix operator
- ❌ Don't use TypeScript namespaces
- ❌ Don't use parameter properties in class constructors
- ❌ Don't declare empty interfaces
- ✅ Use
export type for types
- ✅ Use
import type for types
- ✅ Use
as const instead of literal types and type annotations
- ✅ Use either
T[] or Array<T> consistently
Example - Good TypeScript Patterns:
const Status = {
PENDING: 'pending',
ACTIVE: 'active',
COMPLETED: 'completed'
} as const;
type Status = typeof Status[keyof typeof Status];
import type { User } from './types';
export type { User };
function processUser(user: User): Result<User> {
return { success: true, data: user };
}
enum Status { PENDING, ACTIVE }
function process(data: any) {
return data!.value;
}
4. Code Quality and Correctness
Critical correctness requirements:
- ❌ Don't use
arguments object (use rest parameters)
- ❌ Don't use unnecessary nested block statements
- ❌ Don't use the void operators
- ❌ Don't reassign const variables
- ❌ Don't use constant expressions in conditions
- ❌ Don't use variables before they're declared
- ❌ Don't use await inside loops
- ❌ Don't shadow variables from outer scopes
- ✅ Use arrow functions instead of function expressions
- ✅ Use
for...of statements instead of Array.forEach
- ✅ Use concise optional chaining
- ✅ Make sure Promise-like statements are handled appropriately
Example - Good Code Quality:
const processItems = async (items: Item[]) => {
const results = [];
for (const item of items) {
const result = await processItem(item);
results.push(result);
}
return results;
};
const userName = user?.profile?.name ?? 'Anonymous';
const processItems = function(items) {
const results = [];
items.forEach(async (item) => {
await processItem(item);
});
return results;
};
5. Error Handling
Error handling best practices:
- ✅ Always throw Error objects (not strings or other values)
- ✅ Use
new when throwing an error
- ✅ Handle promises appropriately (await or .catch())
- ✅ Don't use control flow statements in finally blocks
- ✅ Make sure to pass a message value when creating built-in errors
Example - Good Error Handling:
async function fetchData(url: string): Promise<Result<Data>> {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return { success: true, data };
} catch (error) {
console.error('API call failed:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
async function fetchData(url: string) {
try {
const response = await fetch(url);
return await response.json();
} catch (e) {
console.log(e);
throw 'Failed to fetch';
}
}
6. Style and Consistency
Key style requirements:
- ✅ Use
const declarations for variables that are only assigned once
- ✅ Use strict equality (===) and strict inequality (!==) instead of loose equality (==) and loose inequality (!=)
- ✅ Use template literals over string concatenation
- ✅ Use assignment operator shorthand where possible (
+=, -=, etc.)
- ✅ Use the
** operator instead of Math.pow
- ✅ Use
new when throwing an error
- ✅ Don't use
var (use const or let)
- ✅ Don't use console (except in development utilities)
- ✅ Don't use debugger statements
Example - Good Style:
const calculateTotal = (items: Item[]): number => {
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
return total ** 2;
};
const message = `Total: $${calculateTotal(items)}`;
function calculateTotal(items) {
var total = 0;
for (var i = 0; i < items.length; i++) {
total = total + items[i].price;
}
return Math.pow(total, 2);
}
var message = 'Total: $' + calculateTotal(items);
7. Next.js Specific Rules
When working with Next.js:
- ❌ Don't use
<img> elements (use next/image instead)
- ❌ Don't use
<head> elements (use next/head instead)
- ❌ Don't import
next/document outside of pages/_document.jsx
- ❌ Don't use the
next/head module in pages/_document.js
Example - Good Next.js Patterns:
import Image from 'next/image';
export default function Profile() {
return (
<Image
src="/profile.jpg"
alt="User profile"
width={500}
height={500}
/>
);
}
export default function Profile() {
return <img src="/profile.jpg" alt="User profile" />;
}
Quick Reference
Most Common Violations
- Missing key props in list items
- Using
any type instead of specific types
- Missing accessibility attributes (type, alt, aria-*)
- Using var instead of const/let
- Index as key in React lists
- Missing error handling in async functions
- Using enums instead of const objects
- Non-null assertions (postfix exclamation mark) in TypeScript
- Await in loops instead of Promise.all
- Missing dependencies in useEffect
Common Fixes
Fix 1: Replace var with const/let
var count = 0;
let count = 0;
Fix 2: Replace any with specific types
function process(data: any) { }
function process(data: User) { }
Fix 3: Replace enum with const object
enum Status { ACTIVE, INACTIVE }
const Status = {
ACTIVE: 'active',
INACTIVE: 'inactive'
} as const;
type Status = typeof Status[keyof typeof Status];
Fix 4: Add proper error handling
async function fetchData() {
return await fetch('/api/data');
}
async function fetchData(): Promise<Result<Data>> {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
return { success: true, data };
} catch (error) {
console.error('Fetch failed:', error);
return { success: false, error };
}
}
Fix 5: Use proper keys in lists
items.map((item, i) => <div key={i}>{item}</div>)
items.map(item => <div key={item.id}>{item.name}</div>)
When to Use This Skill
Use this skill when:
- Writing new TypeScript/JavaScript code
- Reviewing existing code for issues
- Fixing linting or type errors
- Ensuring accessibility compliance
- Refactoring code to follow best practices
- Setting up code quality standards
- Preparing code for production
Additional Resources
For a complete list of all rules and detailed explanations, refer to the Biome documentation at https://biomejs.dev/linter/rules/