Component Props Standards
๐ Overviewโ
This document establishes standardized prop patterns for React components in the Uptime Watcher application to ensure consistency, maintainability, and improved developer experience.
๐ฏ Standardization Goalsโ
- Consistency: Uniform prop patterns across all components
- Type Safety: Strong TypeScript typing with predictable interfaces
- Accessibility: Built-in accessibility support through standardized props
- Developer Experience: Predictable API patterns and clear documentation
- Maintainability: Easier refactoring and component composition
๐๏ธ Core Prop Patternsโ
1. Interface Naming Conventionโ
Standard: Use Properties
suffix for all component prop interfaces
// โ
Correct
export interface ButtonProperties {
readonly onClick?: () => void;
}
// โ Avoid
export interface ButtonProps {
onClick?: () => void;
}
Rationale:
- Consistency with existing codebase patterns
- Clearer distinction from React's built-in
Props
types - Better alignment with TypeScript conventions
2. Property Mutabilityโ
Standard: All props should be readonly
to prevent accidental mutations
// โ
Correct
export interface ComponentProperties {
readonly title: string;
readonly disabled?: boolean;
readonly onClick?: () => void;
}
// โ Avoid
export interface ComponentProperties {
title: string;
disabled?: boolean;
onClick?: () => void;
}
Rationale:
- Prevents accidental mutations of props
- Encourages immutable data patterns
- Better TypeScript safety
3. Event Handler Patternsโ
Click Eventsโ
Standard: Use simple function signatures for click handlers unless event object is needed
// โ
Preferred (simple actions)
export interface SimpleButtonProperties {
readonly onClick?: () => void;
}
// โ
Acceptable (when event object is needed)
export interface EventButtonProperties {
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
// โ Avoid optional event parameters
export interface BadButtonProperties {
readonly onClick?: (event?: React.MouseEvent<HTMLButtonElement>) => void;
}
Change Eventsโ
Standard: Use value-based handlers for form components, event-based for low-level components
// โ
Form Components (high-level, value-focused)
export interface FormFieldBaseProperties {
readonly onChange: (value: string) => void;
}
// โ
Themed Components (low-level, event-focused)
export interface ThemedInputProperties {
readonly onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
Submit Eventsโ
Standard: Always include event object for form submissions
// โ
Correct
export interface FormProperties {
readonly onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
}
4. Common Prop Categoriesโ
Core Props (Present in most components)โ
export interface CoreComponentProperties {
/** Additional CSS classes for styling customization */
readonly className?: string;
/** Whether the component is disabled */
readonly disabled?: boolean;
/** Component content */
readonly children?: React.ReactNode;
}
Accessibility Propsโ
export interface AccessibilityProperties {
/** ARIA label for screen readers */
readonly "aria-label"?: string;
/** ARIA described-by reference */
readonly "aria-describedby"?: string;
/** ARIA labelledby reference */
readonly "aria-labelledby"?: string;
/** Role attribute for semantic meaning */
readonly role?: string;
}
Form Propsโ
export interface FormFieldBaseProperties {
/** Unique identifier for the field */
readonly id: string;
/** Field label text */
readonly label: string;
/** Whether the field is required */
readonly required?: boolean;
/** Error message to display */
readonly error?: string;
/** Help text for guidance */
readonly helpText?: string;
}
Styling Propsโ
export interface StylingProperties {
/** Size variant */
readonly size?: "xs" | "sm" | "md" | "lg" | "xl";
/** Visual variant */
readonly variant?:
| "primary"
| "secondary"
| "danger"
| "success"
| "warning";
/** Whether component takes full width */
readonly fullWidth?: boolean;
}
State Propsโ
export interface StateProperties {
/** Loading state indicator */
readonly loading?: boolean;
/** Whether component is in an active state */
readonly active?: boolean;
/** Whether component is selected */
readonly selected?: boolean;
}
๐ Size and Variant Standardsโ
Size Optionsโ
Standard sizes: "xs" | "sm" | "md" | "lg" | "xl"
// โ
Standard size variants
export interface SizedComponentProperties {
readonly size?: "xs" | "sm" | "md" | "lg" | "xl";
}
// Default: "md"
Visual Variantsโ
Standard variants: "primary" | "secondary" | "danger" | "success" | "warning" | "ghost"
// โ
Standard visual variants
export interface VariantComponentProperties {
readonly variant?:
| "primary"
| "secondary"
| "danger"
| "success"
| "warning"
| "ghost";
}
// Default: "primary"
๐งฉ Composition Patternsโ
Prop Interface Compositionโ
Standard: Compose interfaces using intersection types rather than extension
// โ
Preferred (composition)
export interface ButtonProperties
extends CoreComponentProperties,
AccessibilityProperties,
StylingProperties,
StateProperties {
readonly onClick?: () => void;
readonly type?: "button" | "submit" | "reset";
}
// โ
Also acceptable (intersection)
export type ButtonProperties = CoreComponentProperties &
AccessibilityProperties &
StylingProperties &
StateProperties & {
readonly onClick?: () => void;
readonly type?: "button" | "submit" | "reset";
};
Icon Integrationโ
Standard: Consistent icon prop patterns across components
export interface IconComponentProperties {
/** Icon element to display */
readonly icon?: React.ReactNode;
/** Icon position relative to content */
readonly iconPosition?: "left" | "right";
/** Icon color theme */
readonly iconColor?: string;
}
๐ Documentation Standardsโ
Property Documentationโ
Standard: Use TSDoc comments with clear descriptions
export interface ComponentProperties {
/**
* Primary action handler for the component.
*
* @remarks
* Called when user interacts with the component. Should handle any
* necessary validation or state updates.
*
* @example
*
* ```tsx
* <Component onClick={() => console.log("Clicked!")} />;
* ```
*/
readonly onClick?: () => void;
/**
* Visual size variant for the component.
*
* @defaultValue "md"
*/
readonly size?: "xs" | "sm" | "md" | "lg" | "xl";
}
Component Documentationโ
Standard: Include comprehensive examples and usage patterns
/**
* Button component with theming, states, and accessibility support.
*
* @remarks
* Provides a comprehensive button implementation with various visual variants,
* sizes, loading states, and full accessibility support.
*
* @example Basic usage:
*
* ```tsx
* <Button onClick={handleClick}>Click me</Button>;
* ```
*
* @example With loading state:
*
* ```tsx
* <Button
* onClick={handleSubmit}
* loading={isSubmitting}
* disabled={!isValid}
* >
* Submit Form
* </Button>;
* ```
*
* @public
*/
๐จ Implementation Templatesโ
Basic Component Templateโ
/**
* [Component] - [brief description]
*
* @remarks
* [Detailed description of component purpose and features]
*
* @example
*
* ```tsx
* <ComponentName prop="value" />;
* ```
*/
import React from "react";
/**
* Properties for the [Component] component.
*/
export interface ComponentNameProperties
extends CoreComponentProperties,
AccessibilityProperties {
/** Component-specific props */
readonly specificProp?: string;
/** Event handlers */
readonly onClick?: () => void;
}
/**
* [Component description]
*
* @param props - Component properties
*
* @returns JSX element
*/
export const ComponentName: React.FC<ComponentNameProperties> = React.memo(
({
className,
disabled = false,
children,
specificProp,
onClick,
...accessibilityProps
}) => {
// Component implementation
return (
<div className={className} {...accessibilityProps}>
{children}
</div>
);
}
);
ComponentName.displayName = "ComponentName";
export default ComponentName;
Form Component Templateโ
/**
* [FormComponent] - [description]
*/
import React, { useCallback } from "react";
export interface FormComponentProperties
extends FormFieldBaseProperties,
CoreComponentProperties {
/** Current value */
readonly value: string;
/** Change handler */
readonly onChange: (value: string) => void;
/** Component-specific props */
readonly placeholder?: string;
}
export const FormComponent: React.FC<FormComponentProperties> = React.memo(
({
id,
label,
value,
onChange,
required = false,
error,
helpText,
placeholder,
disabled = false,
className,
}) => {
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
onChange(event.target.value);
},
[onChange]
);
return (
<BaseFormField
id={id}
label={label}
required={required}
error={error}
helpText={helpText}
>
{(ariaProps) => (
<input
{...ariaProps}
type="text"
value={value}
onChange={handleChange}
placeholder={placeholder}
disabled={disabled}
className={className}
/>
)}
</BaseFormField>
);
}
);
FormComponent.displayName = "FormComponent";
export default FormComponent;
โ Compliance Checklistโ
Interface Designโ
- [ ] Uses
Properties
suffix for prop interfaces - [ ] All props marked as
readonly
- [ ] Proper TSDoc documentation for all props
- [ ] Consistent event handler signatures
- [ ] Appropriate use of optional vs required props
Event Handlersโ
- [ ] Simple
() => void
for basic actions - [ ] Event object included when needed
- [ ] Consistent naming (onClick, onChange, onSubmit)
- [ ] Value-based handlers for form components
Accessibilityโ
- [ ] Appropriate ARIA props included
- [ ] Screen reader considerations
- [ ] Keyboard navigation support
- [ ] Focus management
Documentationโ
- [ ] Component purpose clearly documented
- [ ] Usage examples provided
- [ ] Props documented with descriptions
- [ ] Default values specified
Type Safetyโ
- [ ] Strong TypeScript typing
- [ ] No
any
types used - [ ] Proper generic constraints
- [ ] Interface composition over inheritance
๐ง Migration Guideโ
Updating Existing Componentsโ
-
Interface Naming:
// Before
interface ButtonProps {
onClick?: () => void;
}
// After
interface ButtonProperties {
readonly onClick?: () => void;
} -
Event Handlers:
// Before
readonly onClick?: (e?: React.MouseEvent) => void;
// After
readonly onClick?: () => void;
// OR (if event needed)
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void; -
Property Mutability:
// Before
interface ComponentProps {
title: string;
disabled?: boolean;
}
// After
interface ComponentProperties {
readonly title: string;
readonly disabled?: boolean;
}
๐ Related Documentationโ
- UI Feature Development Guide
- Development Patterns Guide
- Accessibility Guidelines
- TypeScript Standards
This document should be reviewed and updated as new patterns emerge or requirements change. All new components must follow these standards for consistency.