0
# Utility Components
1
2
Utility components for common functionality including click-away listeners, portals, transitions, and hooks.
3
4
## Capabilities
5
6
### ClickAwayListener
7
8
Utility component for detecting clicks outside an element.
9
10
```typescript { .api }
11
/**
12
* Utility component for detecting clicks outside element
13
* @param props - ClickAwayListener configuration
14
* @returns ClickAwayListener component
15
*/
16
function ClickAwayListener(props: ClickAwayListenerProps): JSX.Element;
17
18
interface ClickAwayListenerProps {
19
/** The wrapped element */
20
children: React.ReactElement;
21
/** If true, the React tree is ignored and only the DOM tree is considered */
22
disableReactTree?: boolean;
23
/** The mouse event to listen to */
24
mouseEvent?: 'onClick' | 'onMouseDown' | 'onMouseUp' | false;
25
/** Callback fired when a "click away" event is detected */
26
onClickAway: (event: MouseEvent | TouchEvent) => void;
27
/** The touch event to listen to */
28
touchEvent?: 'onTouchStart' | 'onTouchEnd' | false;
29
}
30
```
31
32
### Portal
33
34
Component for rendering children into a DOM node outside the normal hierarchy.
35
36
```typescript { .api }
37
/**
38
* Component for rendering children outside normal hierarchy
39
* @param props - Portal configuration
40
* @returns Portal component
41
*/
42
function Portal(props: PortalProps): JSX.Element;
43
44
interface PortalProps {
45
/** The children to render into the container */
46
children?: React.ReactNode;
47
/** An HTML element or a function that returns one */
48
container?: Element | (() => Element | null) | null;
49
/** If true, the children stay within their DOM hierarchy */
50
disablePortal?: boolean;
51
}
52
```
53
54
### Transitions
55
56
Transition components for animating component state changes.
57
58
```typescript { .api }
59
/**
60
* Fade transition component
61
* @param props - Fade configuration
62
* @returns Fade component
63
*/
64
function Fade(props: FadeProps): JSX.Element;
65
66
/**
67
* Grow transition component
68
* @param props - Grow configuration
69
* @returns Grow component
70
*/
71
function Grow(props: GrowProps): JSX.Element;
72
73
/**
74
* Slide transition component
75
* @param props - Slide configuration
76
* @returns Slide component
77
*/
78
function Slide(props: SlideProps): JSX.Element;
79
80
/**
81
* Collapse transition component
82
* @param props - Collapse configuration
83
* @returns Collapse component
84
*/
85
function Collapse(props: CollapseProps): JSX.Element;
86
87
/**
88
* Zoom transition component
89
* @param props - Zoom configuration
90
* @returns Zoom component
91
*/
92
function Zoom(props: ZoomProps): JSX.Element;
93
94
interface FadeProps extends TransitionProps {
95
/** A single child content element */
96
children?: React.ReactElement;
97
/** The transition timing function */
98
easing?: {
99
enter?: string;
100
exit?: string;
101
} | string;
102
/** If true, the component will transition in */
103
in?: boolean;
104
/** The duration for the transition */
105
timeout?: number | {
106
appear?: number;
107
enter?: number;
108
exit?: number;
109
};
110
}
111
112
interface GrowProps extends TransitionProps {
113
/** A single child content element */
114
children?: React.ReactElement;
115
/** If true, the component will transition in */
116
in?: boolean;
117
/** The duration for the transition */
118
timeout?: number | 'auto' | {
119
appear?: number;
120
enter?: number;
121
exit?: number;
122
};
123
}
124
125
interface SlideProps extends TransitionProps {
126
/** A single child content element */
127
children?: React.ReactElement;
128
/** An HTML element, or a function that returns one */
129
container?: Element | (() => Element | null) | null;
130
/** Direction the child node will enter from */
131
direction?: 'left' | 'right' | 'up' | 'down';
132
/** If true, the component will transition in */
133
in?: boolean;
134
/** The duration for the transition */
135
timeout?: number | {
136
appear?: number;
137
enter?: number;
138
exit?: number;
139
};
140
}
141
142
interface CollapseProps extends TransitionProps {
143
/** The content node to be collapsed */
144
children?: React.ReactNode;
145
/** The width (horizontal) or height (vertical) of the container when collapsed */
146
collapsedSize?: number | string;
147
/** The component used for the root node */
148
component?: React.ElementType;
149
/** If true, the component will transition in */
150
in?: boolean;
151
/** The collapse transition orientation */
152
orientation?: 'horizontal' | 'vertical';
153
/** The duration for the transition */
154
timeout?: number | 'auto' | {
155
appear?: number;
156
enter?: number;
157
exit?: number;
158
};
159
}
160
161
interface ZoomProps extends TransitionProps {
162
/** A single child content element */
163
children?: React.ReactElement;
164
/** If true, the component will transition in */
165
in?: boolean;
166
/** The duration for the transition */
167
timeout?: number | {
168
appear?: number;
169
enter?: number;
170
exit?: number;
171
};
172
}
173
```
174
175
**Usage Examples:**
176
177
```typescript
178
import {
179
ClickAwayListener,
180
Portal,
181
Fade,
182
Grow,
183
Slide,
184
Collapse,
185
Zoom,
186
Box,
187
Button,
188
Paper
189
} from "@mui/material";
190
191
// ClickAwayListener example
192
function DropdownMenu() {
193
const [open, setOpen] = useState(false);
194
195
const handleClickAway = () => {
196
setOpen(false);
197
};
198
199
return (
200
<ClickAwayListener onClickAway={handleClickAway}>
201
<Box>
202
<Button onClick={() => setOpen(!open)}>
203
Toggle Menu
204
</Button>
205
{open && (
206
<Paper sx={{ position: 'absolute', mt: 1, p: 1 }}>
207
Menu content
208
</Paper>
209
)}
210
</Box>
211
</ClickAwayListener>
212
);
213
}
214
215
// Portal example
216
<Portal container={document.body}>
217
<Box sx={{ position: 'fixed', top: 0, left: 0, zIndex: 9999 }}>
218
This content is rendered in document.body
219
</Box>
220
</Portal>
221
222
// Transition examples
223
<Fade in={fadeIn} timeout={500}>
224
<Box>Fade transition content</Box>
225
</Fade>
226
227
<Grow in={growIn} timeout={300}>
228
<Paper elevation={4} sx={{ p: 2 }}>
229
Grow transition content
230
</Paper>
231
</Grow>
232
233
<Slide direction="up" in={slideIn} mountOnEnter unmountOnExit>
234
<Alert severity="success">
235
Slide transition alert
236
</Alert>
237
</Slide>
238
239
<Collapse in={collapseIn}>
240
<Box sx={{ p: 2, bgcolor: 'background.paper' }}>
241
Collapsible content that can be hidden or shown
242
</Box>
243
</Collapse>
244
```
245
246
### Hooks
247
248
Utility hooks for common functionality.
249
250
```typescript { .api }
251
/**
252
* Hook for responsive design with media queries
253
* @param query - Media query string or function
254
* @param options - Additional options
255
* @returns Boolean indicating if query matches
256
*/
257
function useMediaQuery<Theme = DefaultTheme>(
258
query: string | ((theme: Theme) => string),
259
options?: UseMediaQueryOptions
260
): boolean;
261
262
/**
263
* Hook for triggering actions based on scroll position
264
* @param options - Scroll trigger options
265
* @returns Boolean indicating if trigger is active
266
*/
267
function useScrollTrigger(options?: UseScrollTriggerOptions): boolean;
268
269
interface UseMediaQueryOptions {
270
/** The default value for the match result */
271
defaultMatches?: boolean;
272
/** Whether to match during hydration */
273
matchMedia?: (query: string) => { matches: boolean; media: string; onchange: any; addListener: any; removeListener: any; };
274
/** If true, the hook will not re-render on media query changes */
275
noSsr?: boolean;
276
/** If true, SSR compatibility mode is enabled */
277
ssrMatchMedia?: (query: string) => { matches: boolean };
278
}
279
280
interface UseScrollTriggerOptions {
281
/** The node to listen to for scroll events */
282
target?: Node | Window;
283
/** If true, hide trigger will be true when scrolling down */
284
disableHysteresis?: boolean;
285
/** The scroll threshold */
286
threshold?: number;
287
}
288
```
289
290
**Usage Examples:**
291
292
```typescript
293
import { useMediaQuery, useScrollTrigger, useTheme } from "@mui/material";
294
import { AppBar, Toolbar, Typography, Slide } from "@mui/material";
295
296
// Media query hook
297
function ResponsiveComponent() {
298
const theme = useTheme();
299
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
300
const isTablet = useMediaQuery(theme.breakpoints.between('md', 'lg'));
301
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'));
302
303
return (
304
<Box>
305
{isMobile && <Typography>Mobile View</Typography>}
306
{isTablet && <Typography>Tablet View</Typography>}
307
{isDesktop && <Typography>Desktop View</Typography>}
308
</Box>
309
);
310
}
311
312
// Scroll trigger hook
313
function HideOnScroll({ children }: { children: React.ReactElement }) {
314
const trigger = useScrollTrigger({
315
target: window,
316
disableHysteresis: true,
317
threshold: 100,
318
});
319
320
return (
321
<Slide appear={false} direction="down" in={!trigger}>
322
{children}
323
</Slide>
324
);
325
}
326
327
// Usage with AppBar
328
<HideOnScroll>
329
<AppBar>
330
<Toolbar>
331
<Typography variant="h6">Hide on Scroll AppBar</Typography>
332
</Toolbar>
333
</AppBar>
334
</HideOnScroll>
335
```
336
337
### NoSsr
338
339
Utility component for preventing server-side rendering.
340
341
```typescript { .api }
342
/**
343
* Utility component for preventing server-side rendering
344
* @param props - NoSsr configuration
345
* @returns NoSsr component
346
*/
347
function NoSsr(props: NoSsrProps): JSX.Element;
348
349
interface NoSsrProps {
350
/** The content */
351
children?: React.ReactNode;
352
/** If true, the component will defer the rendering of the children into a different screen frame */
353
defer?: boolean;
354
/** The fallback content to display during SSR */
355
fallback?: React.ReactNode;
356
}
357
```
358
359
### TextareaAutosize
360
361
Auto-resizing textarea component.
362
363
```typescript { .api }
364
/**
365
* Auto-resizing textarea component
366
* @param props - TextareaAutosize configuration
367
* @returns TextareaAutosize component
368
*/
369
function TextareaAutosize(props: TextareaAutosizeProps): JSX.Element;
370
371
interface TextareaAutosizeProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
372
/** Maximum number of rows to display */
373
maxRows?: number;
374
/** Minimum number of rows to display */
375
minRows?: number;
376
/** Callback fired when the textarea is resized */
377
onResize?: (event: Event) => void;
378
}
379
```
380
381
**Usage Examples:**
382
383
```typescript
384
import { NoSsr, TextareaAutosize, Box } from "@mui/material";
385
386
// NoSsr example - useful for components that behave differently on client vs server
387
<NoSsr fallback={<Box>Loading...</Box>}>
388
<SomeClientOnlyComponent />
389
</NoSsr>
390
391
// TextareaAutosize example
392
<TextareaAutosize
393
minRows={3}
394
maxRows={10}
395
placeholder="Enter your message here..."
396
style={{
397
width: '100%',
398
fontSize: '16px',
399
fontFamily: 'inherit',
400
padding: '8px',
401
border: '1px solid #ccc',
402
borderRadius: '4px',
403
resize: 'none',
404
}}
405
/>
406
```
407
408
## Common Utility Patterns
409
410
### Conditional Rendering with Media Queries
411
412
```typescript
413
import { useMediaQuery, useTheme, Hidden } from "@mui/material";
414
415
function ConditionalContent() {
416
const theme = useTheme();
417
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
418
419
return (
420
<Box>
421
{/* Using hook */}
422
{isMobile ? (
423
<MobileNavigation />
424
) : (
425
<DesktopNavigation />
426
)}
427
428
{/* Using Hidden component (deprecated but still available) */}
429
<Hidden mdDown>
430
<DesktopSidebar />
431
</Hidden>
432
<Hidden mdUp>
433
<MobileDrawer />
434
</Hidden>
435
</Box>
436
);
437
}
438
```
439
440
### Scroll-based Interactions
441
442
```typescript
443
import { useScrollTrigger, Fab, Zoom } from "@mui/material";
444
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
445
446
function ScrollToTop() {
447
const trigger = useScrollTrigger({
448
disableHysteresis: true,
449
threshold: 100,
450
});
451
452
const handleClick = () => {
453
window.scrollTo({
454
top: 0,
455
behavior: 'smooth',
456
});
457
};
458
459
return (
460
<Zoom in={trigger}>
461
<Fab
462
onClick={handleClick}
463
color="primary"
464
size="small"
465
aria-label="scroll back to top"
466
sx={{
467
position: 'fixed',
468
bottom: 16,
469
right: 16,
470
}}
471
>
472
<KeyboardArrowUpIcon />
473
</Fab>
474
</Zoom>
475
);
476
}
477
```