| 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
# Initialize Ultracite in your project
npx ultracite init
# Format and fix code automatically
npx ultracite fix
# Check for issues without fixing
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
accessKeyattribute 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
typeattribute for button elements - ✅ Always include a
langattribute on the html element - ✅ Always include a
titleattribute for iframe elements - ✅ Accompany
onClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress - ✅ Accompany
onMouseOver/onMouseOutwithonFocus/onBlur - ✅ Include caption tracks for audio and video elements
- ✅ Use semantic elements instead of role attributes in JSX
- ✅ Always include a
titleelement for SVG elements
Example - Good Accessibility:
// ✅ Good: Proper button with type and accessible events
<button
type="button"
onClick={handleClick}
onKeyDown={handleKeyDown}
>
Submit
</button>
// ✅ Good: Accessible image with meaningful alt
<img src="/photo.jpg" alt="Team celebrating product launch" />
// ❌ Bad: Missing type, keyboard support, and poor alt text
<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
childrenanddangerouslySetInnerHTMLprops - ❌ 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:
// ✅ Good: Component defined at top level with proper hooks
function UserList({ users }) {
const [selected, setSelected] = useState(null);
useEffect(() => {
// All dependencies listed
loadData();
}, [loadData]);
return (
<>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</>
);
}
// ❌ Bad: Component defined inside, index as key, missing deps
function ParentComponent() {
function ChildComponent() { // Bad: nested component
useEffect(() => {
doSomething(); // Bad: missing dependency
}, []);
return <div>Child</div>;
}
return items.map((item, i) => (
<div key={i}>{item}</div> // Bad: index as key
));
}
3. TypeScript Best Practices
Critical TypeScript requirements:
- ❌ Don't use TypeScript enums (use
as constobjects instead) - ❌ Don't use the
anytype - ❌ 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 typefor types - ✅ Use
import typefor types - ✅ Use
as constinstead of literal types and type annotations - ✅ Use either
T[]orArray<T>consistently
Example - Good TypeScript Patterns:
// ✅ Good: Use const objects instead of enums
const Status = {
PENDING: 'pending',
ACTIVE: 'active',
COMPLETED: 'completed'
} as const;
type Status = typeof Status[keyof typeof Status];
// ✅ Good: Import/export types properly
import type { User } from './types';
export type { User };
// ✅ Good: Specific types, no any
function processUser(user: User): Result<User> {
return { success: true, data: user };
}
// ❌ Bad: Using enum, any, and non-null assertion
enum Status { PENDING, ACTIVE } // Bad: use const object
function process(data: any) { // Bad: use specific type
return data!.value; // Bad: avoid non-null assertion
}
4. Code Quality and Correctness
Critical correctness requirements:
- ❌ Don't use
argumentsobject (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...ofstatements instead ofArray.forEach - ✅ Use concise optional chaining
- ✅ Make sure Promise-like statements are handled appropriately
Example - Good Code Quality:
// ✅ Good: Arrow functions, for-of, proper async handling
const processItems = async (items: Item[]) => {
const results = [];
for (const item of items) {
const result = await processItem(item);
results.push(result);
}
return results;
};
// ✅ Good: Optional chaining
const userName = user?.profile?.name ?? 'Anonymous';
// ❌ Bad: Function expression, forEach, await in loop
const processItems = function(items) {
const results = [];
items.forEach(async (item) => { // Bad: async in forEach
await processItem(item); // Bad: await in loop (via forEach)
});
return results;
};
5. Error Handling
Error handling best practices:
- ✅ Always throw Error objects (not strings or other values)
- ✅ Use
newwhen 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:
// ✅ Good: Comprehensive 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'
};
}
}
// ❌ Bad: Swallowing errors, throwing strings
async function fetchData(url: string) {
try {
const response = await fetch(url);
return await response.json();
} catch (e) {
console.log(e); // Bad: just logging
throw 'Failed to fetch'; // Bad: throwing string
}
}
6. Style and Consistency
Key style requirements:
- ✅ Use
constdeclarations 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 ofMath.pow - ✅ Use
newwhen throwing an error - ✅ Don't use
var(useconstorlet) - ✅ Don't use console (except in development utilities)
- ✅ Don't use debugger statements
Example - Good Style:
// ✅ Good: Modern, consistent style
const calculateTotal = (items: Item[]): number => {
let total = 0;
for (const item of items) {
total += item.price * item.quantity;
}
return total ** 2; // Use ** instead of Math.pow
};
const message = `Total: $${calculateTotal(items)}`; // Template literal
// ❌ Bad: Inconsistent, outdated style
function calculateTotal(items) {
var total = 0; // Bad: use const/let
for (var i = 0; i < items.length; i++) { // Bad: use for-of
total = total + items[i].price; // Bad: use +=
}
return Math.pow(total, 2); // Bad: use **
}
var message = 'Total: $' + calculateTotal(items); // Bad: use template literal
7. Next.js Specific Rules
When working with Next.js:
- ❌ Don't use
<img>elements (usenext/imageinstead) - ❌ Don't use
<head>elements (usenext/headinstead) - ❌ Don't import
next/documentoutside ofpages/_document.jsx - ❌ Don't use the
next/headmodule inpages/_document.js
Example - Good Next.js Patterns:
// ✅ Good: Use Next.js Image component
import Image from 'next/image';
export default function Profile() {
return (
<Image
src="/profile.jpg"
alt="User profile"
width={500}
height={500}
/>
);
}
// ❌ Bad: Using native img tag
export default function Profile() {
return <img src="/profile.jpg" alt="User profile" />;
}
Quick Reference
Most Common Violations
- Missing key props in list items
- Using
anytype 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
// Before
var count = 0;
// After
let count = 0;
Fix 2: Replace any with specific types
// Before
function process(data: any) { }
// After
function process(data: User) { }
Fix 3: Replace enum with const object
// Before
enum Status { ACTIVE, INACTIVE }
// After
const Status = {
ACTIVE: 'active',
INACTIVE: 'inactive'
} as const;
type Status = typeof Status[keyof typeof Status];
Fix 4: Add proper error handling
// Before
async function fetchData() {
return await fetch('/api/data');
}
// After
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
// Before
items.map((item, i) => <div key={i}>{item}</div>)
// After
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/