---
title: .client modules
---
# `.client` modules
[MODES: framework]
## Summary
You may have a file or dependency that uses module side effects in the browser. You can use `*.client.ts` on file names or nest files within `.client` directories to force them out of server bundles.
```ts filename=feature-check.client.ts
// this would break the server
export const supportsVibrationAPI =
"vibrate" in window.navigator;
```
Note that values exported from this module will all be `undefined` on the server, so the only places to use them are in [`useEffect`][use_effect] and user events like click handlers.
```ts
import { supportsVibrationAPI } from "./feature-check.client.ts";
console.log(supportsVibrationAPI);
// server: undefined
// client: true | false
```
If you need more sophisticated control over what is included in the client/server bundles, check out the [`vite-env-only` plugin](https://github.com/pcattori/vite-env-only).
## Usage Patterns
### Individual Files
Mark individual files as client-only by adding `.client` to the filename:
```txt
app/
├── utils.client.ts 👈 client-only file
├── feature-detection.client.ts
└── root.tsx
```
### Client Directories
Mark entire directories as client-only by using `.client` in the directory name:
```txt
app/
├── .client/ 👈 entire directory is client-only
│ ├── analytics.ts
│ ├── feature-detection.ts
│ └── browser-utils.ts
├── components/
└── root.tsx
```
## Examples
### Browser Feature Detection
```ts filename=app/utils/browser.client.ts
export const canUseDOM = typeof window !== "undefined";
export const hasWebGL = !!window.WebGLRenderingContext;
export const supportsVibrationAPI =
"vibrate" in window.navigator;
```
### Client-Only Libraries
```ts filename=app/analytics.client.ts
// This would break on the server
import { track } from "some-browser-only-analytics-lib";
export function trackEvent(eventName: string, data: any) {
track(eventName, data);
}
```
### Using Client Modules
```tsx filename=app/routes/dashboard.tsx
import { useEffect } from "react";
import {
canUseDOM,
supportsLocalStorage,
supportsVibrationAPI,
} from "../utils/browser.client.ts";
import { trackEvent } from "../analytics.client.ts";
export default function Dashboard() {
useEffect(() => {
// These values are undefined on the server
if (canUseDOM && supportsVibrationAPI) {
console.log("Device supports vibration");
}
// Safe localStorage usage
const savedTheme =
supportsLocalStorage.getItem("theme");
if (savedTheme) {
document.body.className = savedTheme;
}
trackEvent("dashboard_viewed", {
timestamp: Date.now(),
});
}, []);
return
Dashboard
;
}
```
[use_effect]: https://react.dev/reference/react/useEffect