This document outlines the process for deprecating components, props, and features in Forma 36. Following a consistent deprecation process ensures that consumers of the design system have adequate time to migrate away from deprecated APIs while maintaining stability and clear communication.
- When to Deprecate
- Deprecation Timeline
- Communication Process
- Implementation Guidelines
- Creating Changesets for Deprecations
- Migration Guide Requirements
- Examples
Deprecation is specifically for breaking changes. The deprecation process allows us to introduce breaking changes in a controlled manner by giving consumers advance notice and time to migrate. If a change can be made without breaking existing functionality (e.g., adding new props, extending accepted values, adding new components), it does not require deprecation.
Consider deprecating a component, prop, or feature when:
- Replacement available: A better alternative exists that provides the same or improved functionality
- Design system evolution: The component no longer aligns with current design principles
- Performance issues: A more performant solution is available
- Accessibility improvements: A more accessible alternative exists
- API simplification: Consolidating similar functionality to reduce confusion
- Technical debt: Removing outdated patterns or dependencies
Do NOT deprecate when:
- No clear migration path exists
- The feature is still widely used without a suitable alternative
- The change would cause excessive disruption without significant benefit
- The change can be performed non-breaking e.g. adding additional properties or extending accepted values
We follow a gradual deprecation approach aligned with semantic versioning:
- Mark the feature as deprecated
- Add an entry for this feature or component in the deprecation log
- Add runtime console warnings (development only)
- Update documentation with deprecation notices
- Provide migration guide
- Create codemod if applicable
- Feature remains fully functional
- Feature is in maintenance mode and will receive security updates
Minimum duration: At least one major version cycle or 6 months, whichever is longer
- Remove the deprecated feature in the next major version
- Update documentation and examples
- Update migration guides
- Update deprecation log
v4.10.0 (Minor) - Component deprecated, warnings added
v4.11.0 - v4.x - Deprecated but functional
v5.0.0 (Major) - Component removed
Or if the next major version is sooner than 6 months
v4.10.0 (Minor) - Component deprecated, warnings added
v4.11.0 - v4.x - Deprecated but functional
v5.0.0 (Major) - Deprecated but functional
v5.0.0 - v5.x - Deprecated but functional
v6.0.0 (Major) - Component removed
Effective communication is crucial for successful deprecations. Follow these steps:
- Discuss deprecation with the forma36 owners
- Document reasons and alternatives
- Plan migration strategy
- Consider impact on known consumers
Update the following locations:
Add a prominent deprecation notice at the top of the component page:
> **⚠️ Deprecated**: This component is deprecated and will be removed in next major version
> Please use [NewComponent](link) instead. See the [migration guide](#migration).Include deprecation notices in the package CHANGELOG:
### Deprecated
- **ComponentName**: Deprecated in favor of NewComponent. Will be removed in next major versionDocument the deprecated feature or component in the Deprecation log
Add console warnings in development mode:
if (process.env.NODE_ENV === 'development') {
console.warn(
'Warning: `OldComponent` is deprecated and will be removed in next major version ' +
'Please use `NewComponent` instead. ' +
'See migration guide: https://f36.contentful.com/components/old-component#migration',
);
}For deprecated props on components still in use:
if (process.env.NODE_ENV === 'development' && oldProp !== undefined) {
console.warn(
'`oldProp` on ComponentName is deprecated and will be removed in next major version ' +
'Please use `newProp` instead.',
);
}- Announce deprecation in release notes
- Consider posting in community channels
- Consider a blog post for deprecations that affect more than one component
Use TypeScript's @deprecated JSDoc tag for IDE support:
/**
* @deprecated Use NewComponent instead. Will be removed in the next major version.
* @see {@link NewComponent}
*/
export const OldComponent: React.FC<OldComponentProps> = (props) => {
// Implementation
};For individual props, keep the prop functional but add type annotations:
export interface ComponentProps {
/**
* @deprecated Use `variant` prop instead. Will be removed in the next major version.
*/
type?: 'primary' | 'secondary';
/** The variant of the component */
variant?: 'primary' | 'secondary';
}When adding a deprecation, create a changeset that clearly indicates the deprecation:
npx changesetStructure the changeset with clear messaging:
---
'@contentful/f36-components': minor
'@contentful/f36-button': minor
---
**Deprecated**
- `OldButton`: Deprecated in favor of `Button` with `variant` prop. Will be removed in v5.0.0
- Migration guide available at: https://f36.contentful.com/components/button#migration- Version bump: Deprecations are
minorchanges (new warnings, not breaking) - Label clearly: Start with
**Deprecated**in the description - Provide context: Explain what's deprecated and what to use instead
- Link to docs: Always include a link to migration guidance
- Removal is major: When actually removing, use
majorversion bump
Every deprecation must include a migration guide. The guide should contain:
- What is being deprecated
- When it will be removed
- Why it's being deprecated
// ❌ Deprecated - will be removed in next major version
<OldButton type="primary">Click me</OldButton>
// ✅ Recommended
<Button variant="primary">Click me</Button>For complex components, provide a mapping:
| Old Prop | New Prop | Notes |
|---|---|---|
type |
variant |
Direct replacement |
size |
size |
Unchanged |
isDisabled |
disabled |
Renamed for consistency |
Document any behavioral differences:
### Important Changes
- The new component uses CSS Grid instead of Flexbox
- Default spacing has changed from 16px to 12px
- Event handlers now receive synthetic events (previously native)If a codemod is available, provide instructions:
npx @contentful/forma-36-codemod old-button-to-button path/to/filesProvide a way to get help:
If you encounter issues during migration, please:
- Check our [GitHub Issues](https://github.com/contentful/forma-36/issues) or create a new one
- Send us direct feedback via our feedback form on our [website](https://f36.contentful.com/)export interface ButtonProps {
/**
* The visual style of the button
*/
variant?: 'primary' | 'secondary' | 'positive' | 'negative';
/**
* @deprecated Use `variant` instead. Will be removed in the next Major version.
*/
buttonType?: 'primary' | 'secondary' | 'positive' | 'negative';
}
export const Button: React.FC<ButtonProps> = ({
variant,
buttonType,
...props
}) => {
if (process.env.NODE_ENV === 'development' && buttonType) {
console.warn(
'Button: `buttonType` prop is deprecated. Use `variant` instead. ' +
'This prop will be removed in the next major version'
);
} else if ( process.env.NODE_ENV === 'development' && buttonType && variant) {
console.warn(
'Button: `buttonType` prop is deprecated in favor of `variant` and will be ignored.' +
'This prop will be removed in the next major version'
);
}
const actualVariant = variant ?? buttonType ?? 'primary';
return <button className={`button-${actualVariant}`} {...props} />;
};// NewCard.tsx - The replacement component
export const Card: React.FC<CardProps> = (props) => {
// New implementation
};
// OldCard.tsx - The deprecated component
import { Card } from './Card';
/**
* @deprecated Use `Card` from '@contentful/f36-card' instead.
* Will be removed in next Major Version
*
* @see {@link Card} for the replacement component
* @example
* ```tsx
* // Before
* <LegacyCard padding="large">Content</LegacyCard>
*
* // After
* <Card padding="12px">Content</Card>
* ```
*/
export const LegacyCard: React.FC<LegacyCardProps> = (props) => {
if (process.env.NODE_ENV === 'development') {
console.warn(
'LegacyCard is deprecated and will be removed in next major version ' +
'Please migrate to Card. ' +
'See: https://f36.contentful.com/components/card#migration'
);
}
// Map old props to new props
const newProps = {
padding: props.padding === 'large' ? '24px' : '12px',
...props,
};
return <Card {...newProps} />;
};- Releases Process - How to create changesets and publish releases
- Migration Guides - Existing migration documentation
- Contributing Guidelines - General contribution process
- Semantic Versioning - Versioning specification we follow
If you have questions about the deprecation process:
- Check existing deprecation examples in the codebase
- Ask in the team's internal channels
- Review previous deprecation PRs for reference
- Consult with the design system team leads
Remember: Deprecation is about making change manageable, not avoiding it. Clear communication and adequate transition time are key to maintaining trust with the community.