animations-transitions
MUI transition components (Fade, Grow, Slide, Collapse, Zoom), custom transitions, TransitionGroup, and Framer Motion integration
What this skill does
# MUI Animations & Transitions
## 1. Built-in Transition Components
MUI provides five transition components built on top of `react-transition-group`. Each wraps a single child element and controls its enter/exit animation based on the `in` prop.
### Fade
Opacity transition from transparent to opaque.
```tsx
import { Fade, Box, Button } from '@mui/material';
import { useState } from 'react';
function FadeExample() {
const [visible, setVisible] = useState(false);
return (
<>
<Button onClick={() => setVisible((v) => !v)}>Toggle</Button>
<Fade in={visible} timeout={300}>
<Box sx={{ p: 2, bgcolor: 'primary.main', color: 'white' }}>
Fading content
</Box>
</Fade>
</>
);
}
```
**Key props:**
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `in` | `boolean` | `false` | Controls visibility |
| `timeout` | `number \| { enter, exit }` | `300` | Duration in ms |
| `appear` | `boolean` | `true` | Animate on initial mount when `in` is true |
| `unmountOnExit` | `boolean` | `false` | Remove DOM node when exited |
| `mountOnEnter` | `boolean` | `false` | Defer first mount until `in` is true |
### Grow
Combined scale and opacity transition. The element grows from the center (or a custom origin) while fading in.
```tsx
import { Grow, Paper } from '@mui/material';
function GrowExample({ visible }: { visible: boolean }) {
return (
<Grow
in={visible}
timeout={500}
style={{ transformOrigin: '0 0 0' }}
{...(visible ? { timeout: 1000 } : {})}
>
<Paper elevation={4} sx={{ p: 3, width: 200 }}>
Growing content
</Paper>
</Grow>
);
}
```
**Custom transform origin:**
```tsx
<Grow in={open} style={{ transformOrigin: 'center top' }}>
<MenuContent />
</Grow>
```
### Slide
Directional slide transition. The element slides in from an edge of the screen or a container.
```tsx
import { Slide, Paper } from '@mui/material';
import { useRef } from 'react';
function SlideExample({ visible }: { visible: boolean }) {
const containerRef = useRef<HTMLDivElement>(null);
return (
<Box ref={containerRef} sx={{ overflow: 'hidden', height: 200 }}>
<Slide
direction="up"
in={visible}
container={containerRef.current}
timeout={{ enter: 400, exit: 200 }}
>
<Paper sx={{ p: 2 }}>Slides up into view</Paper>
</Slide>
</Box>
);
}
```
**`direction` values:** `'up'` | `'down'` | `'left'` | `'right'`
When `container` is provided, the element slides relative to that container instead of the viewport.
### Collapse
Height (or width) animation that expands/collapses content.
```tsx
import { Collapse, List, ListItem, ListItemText, Button, Box } from '@mui/material';
function CollapseExample() {
const [expanded, setExpanded] = useState(false);
return (
<Box>
<Button onClick={() => setExpanded((e) => !e)}>
{expanded ? 'Collapse' : 'Expand'}
</Button>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<List>
<ListItem><ListItemText primary="Item 1" /></ListItem>
<ListItem><ListItemText primary="Item 2" /></ListItem>
<ListItem><ListItemText primary="Item 3" /></ListItem>
</List>
</Collapse>
</Box>
);
}
```
**Horizontal collapse:**
```tsx
<Collapse in={open} orientation="horizontal" collapsedSize={40}>
<Sidebar />
</Collapse>
```
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `collapsedSize` | `number \| string` | `'0px'` | Minimum size when collapsed (e.g., `40` to keep a peek visible) |
| `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Direction of collapse |
| `timeout` | `number \| 'auto'` | `duration.standard` | `'auto'` calculates duration from height |
### Zoom
Scale transition from the center of the child element.
```tsx
import { Zoom, Fab, AddIcon } from '@mui/material';
function ZoomFab({ visible }: { visible: boolean }) {
return (
<Zoom in={visible} timeout={200} unmountOnExit>
<Fab color="primary" sx={{ position: 'fixed', bottom: 16, right: 16 }}>
<AddIcon />
</Fab>
</Zoom>
);
}
```
---
## 2. Usage Patterns
### Basic Pattern
```tsx
<Fade in={visible} timeout={300}>
<Box>Content</Box>
</Fade>
```
### Ref Forwarding for Custom Components
MUI transition components pass a `ref` to their child. If the child is a custom component, it must forward the ref:
```tsx
import { forwardRef } from 'react';
import { Fade, FadeProps } from '@mui/material';
// Custom component that forwards ref
const CustomCard = forwardRef<HTMLDivElement, { title: string }>(
function CustomCard({ title, ...props }, ref) {
return (
<div ref={ref} {...props}>
<h3>{title}</h3>
</div>
);
}
);
// Usage inside a transition
function AnimatedCard({ visible }: { visible: boolean }) {
return (
<Fade in={visible}>
<CustomCard title="Hello" />
</Fade>
);
}
```
Without `forwardRef`, the transition will not work and React will warn about refs on function components.
### Conditional Rendering vs Visibility Toggle
**Visibility toggle** (keeps DOM node, hides with CSS):
```tsx
<Fade in={visible}>
<Box>Always in DOM, opacity changes</Box>
</Fade>
```
**Conditional rendering** (removes DOM node on exit):
```tsx
<Fade in={visible} unmountOnExit mountOnEnter>
<Box>Removed from DOM when hidden</Box>
</Fade>
```
Use `unmountOnExit` when:
- The hidden content is expensive (heavy components, iframes)
- You need to reset component state on re-entry
- You want to reduce DOM size for accessibility screen readers
Use visibility toggle when:
- You need instant re-show without remount cost
- The component maintains scroll position or form state
---
## 3. TransitionGroup -- Animating Lists
`TransitionGroup` from `react-transition-group` works with MUI transitions to animate items being added or removed from a list.
```tsx
import { TransitionGroup } from 'react-transition-group';
import {
Collapse,
List,
ListItem,
ListItemText,
IconButton,
Button,
Box,
} from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import { useState } from 'react';
interface Item {
id: number;
name: string;
}
function AnimatedList() {
const [items, setItems] = useState<Item[]>([
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' },
{ id: 3, name: 'Cherry' },
]);
const addItem = () => {
const id = Date.now();
setItems((prev) => [...prev, { id, name: `Item ${id}` }]);
};
const removeItem = (id: number) => {
setItems((prev) => prev.filter((item) => item.id !== id));
};
return (
<Box>
<Button onClick={addItem} variant="contained" sx={{ mb: 2 }}>
Add Item
</Button>
<List>
<TransitionGroup>
{items.map((item) => (
<Collapse key={item.id}>
<ListItem
secondaryAction={
<IconButton edge="end" onClick={() => removeItem(item.id)}>
<DeleteIcon />
</IconButton>
}
>
<ListItemText primary={item.name} />
</ListItem>
</Collapse>
))}
</TransitionGroup>
</List>
</Box>
);
}
```
**Using Fade instead of Collapse for list items:**
```tsx
<TransitionGroup>
{items.map((item) => (
<Fade key={item.id} timeout={500}>
<ListItem>
<ListItemText primary={item.name} />
</ListItem>
</Fade>
))}
</TransitionGroup>
```
**Important:** Each child of `TransitionGroup` must have a unique `key`. The transition component (Collapse, Fade, etc.) should be the direct child of TransitionGroup, wrapping the actual content.
---
## 4. Custom Transitions
Create reusable transition components using the `Transition` component from `react-transition-group`.
### Using MUI's `styled` + TransRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.