# current-device: Conditional CSS and JavaScript by Device, OS and Orientation

> current-device is an MIT-licensed npm package that writes device classes onto the html element and exposes matching JavaScript checks. It is a good fit for legacy mobile CSS work and a poor fit for anything that needs reliable hardware detection.

**matthewhudson/current-device** — 📱 The easiest way to write conditional CSS and/or JavaScript based on device operating system (iOS, Android, Blackberry, Windows, Firefox OS, MeeGo), orientation (Portrait vs. Landscape), and type (Tablet vs. Mobile).

- Repository: https://github.com/matthewhudson/current-device
- Website: https://matthewhudson.github.io/current-device/
- Stars: 3,926 · Forks: 572
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/matthewhudson-current-device

## What current-device solves, and for whom

Media queries answer questions about the viewport. They do not answer questions about the device. A 1024px-wide window on a desktop and a 1024px-wide window on a tablet can be the same width and still need different treatment, and no width query can tell them apart. current-device exists to close that gap for the specific case where the answer only needs to be roughly right.

The README frames the project as a way to write conditional CSS and/or JavaScript based on device operating system, orientation and type. It inserts CSS classes into the html element, and it exposes JavaScript methods that return booleans for the same characteristics. The audience is front-end developers who already have a stylesheet full of layout rules and want to branch them without rewriting the whole thing around container queries or feature detection.

The supported device list in the README is a useful signal about intent: iOS (iPhone, iPod, iPad), macOS, Android phones and tablets, BlackBerry phones and tablets, Windows phones, tablets and desktops, and Firefox OS phones and tablets. MeeGo, AppleTV and television appear in the class and method tables. That list is a snapshot of a particular era of mobile web development, and it is worth reading as a statement about which platforms the maintainer considered worth naming.

## How the class injection and the getters actually work

The mechanism is deliberately small. The README states that including the script causes it to update the html section with the appropriate classes based on the device's characteristics. There is no configuration step, no initialization call and no options object documented. You load the module and the classes appear.

The class vocabulary is a flat set of tokens. An iPad gets ios ipad tablet. An iPhone gets ios iphone mobile. A Mac gets macos desktop. An Android phone gets android mobile, an Android tablet gets android tablet. Orientation adds either landscape or portrait. Because the tokens are independent, a stylesheet can target `.ios.tablet.portrait` and get a compound selector without any JavaScript in the page.

The JavaScript side mirrors the same vocabulary as methods: device.mobile(), device.tablet(), device.desktop(), device.ios(), device.ipad(), device.iphone(), device.ipod(), device.macos(), device.android(), device.androidPhone(), device.androidTablet(), device.blackberry(), device.blackberryPhone(), device.blackberryTablet(), device.windows(), device.windowsPhone(), device.windowsTablet(), device.fxos(), device.fxosPhone(), device.fxosTablet(), device.meego(), device.television(), device.landscape() and device.portrait(). Each returns a boolean.

Three properties give you the first match on an attribute without looping through the getters: device.type returns 'mobile', 'tablet', 'desktop' or 'unknown'; device.orientation returns 'landscape', 'portrait' or 'unknown'; device.os returns one of 'ios', 'iphone', 'ipad', 'ipod', 'android', 'blackberry', 'windows', 'macos', 'fxos', 'meego', 'television' or 'unknown'. The 'unknown' fallback is the honest part of the design, and it is the value you should plan for.

## Installing current-device and using it on a real page

The README gives a single install command. It requires Node 16 or newer according to the engines field in package.json.

```bash
npm install current-device
```

After installation, the recommended import is the ES module form. The README also documents a CommonJS form that pulls the default export.

```ts
// ES modules (recommended)
import device from "current-device";

// CommonJS
const device = require("current-device").default;
```

If you are not using a bundler, the README documents a script tag pointed at a CDN, with the global exposed as device. The console line in the README prints the type, which will be 'mobile', 'tablet' or 'desktop'.

```html
<script src="https://unpkg.com/current-device/dist/index.global.js"></script>
<script>
  console.log(device.type); // 'mobile', 'tablet', or 'desktop'
</script>
```

The package ships its own TypeScript types, and the README shows importing the named types alongside the default export. This is the part worth copying if you are in a typed codebase, because it stops you comparing device.os against a string that is not in the union.

```ts
import device from "current-device";
import type { Device, DeviceType, DeviceOs, DeviceOrientation } from "current-device";

const os: DeviceOs = device.os;
const type: DeviceType = device.type;
const isPhone: boolean = device.mobile();
```

For orientation changes after load, the README documents a callback rather than an event listener you register yourself. The callback receives the new orientation as either "landscape" or "portrait".

```ts
device.onChangeOrientation((newOrientation: "landscape" | "portrait") => {
  console.log(`New orientation is ${newOrientation}`);
});
```

One utility is documented: device.noConflict() returns the device variable to its previous owner and returns a reference to the device object. That matters only if you are loading the global build on a page that already defines a global named device, which is a real risk on pages with other scripts.

## Where current-device breaks down

The README's own best practices section begins with the words "Environment detection ha" and is truncated in the published text. That truncation is itself informative: the project acknowledges that environment detection has limits, and the guidance on how to handle those limits is not visible in the README as published.

The larger limitation is structural. The class list is built from device names, not from capabilities. There is no documented method for touch support, pointer type, screen density, available memory or anything else that would let you branch on what the browser can do. If your real question is "can this device handle a heavy WebGL scene", current-device cannot answer it, and no amount of extra device names will make it able to.

The 'unknown' values are the other failure surface. device.type, device.orientation and device.os can each return 'unknown', and the README does not describe what triggers that state or how often it occurs. Any code that assumes device.os is one of the named values will need a fallback branch, and the fallback branch is the one that runs on whatever device the detection logic does not recognize.

Finally, the device list is a maintenance liability as much as a feature. A project that names BlackBerry, Firefox OS and MeeGo in its public API is carrying vocabulary that most current users will never match. That is not a bug, but it does mean the class names on your html element are partly a historical record.

## current-device against Modernizr and plain media queries

Modernizr asks what the browser supports. current-device asks what the device appears to be. The difference matters when you need to decide something.

If you want to know whether the browser supports WebP, Modernizr-style feature detection gives you an answer that is correct on every device, including ones released after your code was written. If you want to know whether the visitor is on an iPad so you can serve a different layout, current-device gives you a class you can put in a stylesheet without writing any JavaScript at all. The second approach is shorter to write and narrower in what it can express.

Plain media queries sit underneath both. They are the right tool for anything that is genuinely about available space, and they have no dependency and no bundle cost. current-device is worth its weight only when the decision cannot be expressed as a width, height or resolution query. If every branch you need is already expressible as a media query, adding current-device is adding a dependency for nothing.

The practical split: use media queries for layout, use feature detection for capability, and use current-device when the branch is genuinely about the device class and a class on the html element is the cheapest place to put it.

## Maintenance, licensing and what an upgrade costs you

The repository is not archived, and the last push was on 2026-06-08. The most recent release listed is v2.0.1 on 2026-02-25, following v2.0.0 on the same day. Before that, the previous release was v0.10.2 on 2021-01-15. That gap is the thing to understand before you adopt: this package spent roughly five years between releases and then shipped a major version bump.

The version in package.json is 2.1.0, which is ahead of the most recent release listed. If you are pinning, pin to a published version rather than tracking main.

The build is tsup, the test runner is vitest, and the package manager is pnpm at version 10.30.1. The published files array contains only dist, so consumers get the built output and the type declarations, not the source. The release script uses pnpm publish with --provenance, which is a supply-chain signal worth noting if your organization cares about that.

Licensing is MIT. That permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. This is a description of the licence text, not legal advice, and the LICENSE file in the repository is the authoritative source.

The upgrade cost between major versions is the real question, and the README does not document a migration path from v0.10.x to v2.x. The CHANGELOG.md file exists at the repository root and is where that information would live. Read it before you upgrade an existing integration, because the module format changed between the two eras: the current package exposes both dist/index.mjs for import and dist/index.js for require, with separate type declaration files for each.

## Conclusion

Adopt current-device if you maintain a CSS codebase where a class on the html element is the cheapest way to branch layout, and if the devices you care about are the ones the README lists. Do not adopt it if your decisions depend on hardware capability, because the README describes the mechanism as environment detection and the class list is device-name based. Before committing, check the two things the README does not settle: whether your build pipeline consumes dist/index.mjs or dist/index.global.js, and whether the orientation classes are enough for your layout or you need device.onChangeOrientation to re-run JavaScript.

## FAQ

### What is current-device?

It is an npm package that inserts CSS classes into the html element and exposes JavaScript methods, so you can write conditional CSS and JavaScript based on device operating system, orientation and type. It is licensed MIT and ships with TypeScript types.

### How do I install current-device?

Run npm install current-device, then import the default export from "current-device" for ES modules or use require("current-device").default for CommonJS. A CDN script tag pointing at dist/index.global.js is also documented for pages without a bundler.

### What is the current-device environment error?

The README does not document any error by that name, and nothing in the repository files describes an environment error state. The closest documented behavior is the 'unknown' value returned by device.type, device.orientation and device.os when no match is found.

## Sources

- [License: MIT](https://github.com/matthewhudson/current-device/blob/main/LICENSE)
- [matthewhudson/current-device on GitHub](https://github.com/matthewhudson/current-device)
- [Project website](https://matthewhudson.github.io/current-device/)
- [README](https://github.com/matthewhudson/current-device/blob/main/README.md)
- [Releases](https://github.com/matthewhudson/current-device/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/matthewhudson-current-device
