# css-selector-parser

> Powerful and compliant CSS selector parser.

Latest version **3.3.0** (published 2025-12-14) · MIT license · 0 weekly downloads

## Install

```sh
npm install css-selector-parser
pnpm add css-selector-parser
yarn add css-selector-parser
bun add css-selector-parser
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.3.0 |
| Published | 2025-12-14 |
| First published | 2013-02-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 196.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Marat Dulin |
| Maintainers | mdevils |
| Keywords | css, css selector, css selector parser, pseudo-classes, pseudo-elements, css attributes, css tags, css classes |

## Links

- npm: https://www.npmjs.com/package/css-selector-parser
- Repository: https://github.com/mdevils/css-selector-parser
- Homepage: https://github.com/mdevils/css-selector-parser#readme
- Issues: https://github.com/mdevils/css-selector-parser/issues
- Funding: https://github.com/sponsors/mdevils
- npm.io page: https://npm.io/package/css-selector-parser

## Alternatives

- [style-dictionary](https://npm.io/package/style-dictionary.md) — 2.0M weekly downloads
- [postcss-merge-idents](https://npm.io/package/postcss-merge-idents.md) — 1.7M weekly downloads
- [@fontsource/noto-sans](https://npm.io/package/@fontsource/noto-sans.md) — 93.0K weekly downloads
- [uglifycss](https://npm.io/package/uglifycss.md) — 71.6K weekly downloads
- [mat4-interpolate](https://npm.io/package/mat4-interpolate.md) — 23.3K weekly downloads

## Recent versions

- 3.3.0 (latest) — 2025-12-14
- 3.2.0 — 2025-11-17
- 3.1.3 — 2025-06-23
- 3.1.2 — 2025-04-13
- 3.1.1 — 2025-03-16
- 3.1.0 — 2025-03-16
- 3.0.5 — 2024-03-02
- 3.0.4 — 2023-12-15
- 3.0.3 — 2023-12-08
- 3.0.2 — 2023-11-21
- 3.0.1 — 2023-11-20
- 3.0.0 — 2023-10-02
- 2.3.2 — 2023-06-25
- 2.3.1 — 2023-06-24
- 2.3.0 — 2023-06-24
- … 16 more at https://npm.io/package/css-selector-parser/versions

## README

# css-selector-parser

[![npm](https://img.shields.io/npm/v/css-selector-parser)](https://www.npmjs.com/package/css-selector-parser)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/css-selector-parser)](https://bundlephobia.com/package/css-selector-parser)
[![NPM License](https://img.shields.io/npm/l/css-selector-parser)](https://github.com/mdevils/css-selector-parser/blob/master/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/mdevils/css-selector-parser)](https://github.com/mdevils/css-selector-parser/stargazers)

A high-performance CSS selector parser with advanced features for modern web development.

## Features

- 🚀 **Fast and memory-efficient** parsing for all CSS selectors
- 🌳 **AST-based** object model for programmatic manipulation
- 🚶 **AST traversal** with visitor pattern for analyzing and transforming selectors
- 📊 **Full compliance** with all CSS selector specifications
- 🧪 **Comprehensive test coverage**
- 📚 **Well-documented API** with TypeScript support
- 🔄 **Two-way conversion** between CSS selectors and AST
- 🧩 **Modular support** for various CSS specifications
- 🎮 **[Interactive Playground](https://mdevils.github.io/css-selector-parser/)** - Try it in your browser!

## Playground

**[🎮 Launch Interactive Playground](https://mdevils.github.io/css-selector-parser/)**

Test CSS selectors in your browser with syntax highlighting, real-time AST visualization, and configurable parser options.

## Supported CSS Selector Standards

- `css1`: [W3C CSS1 Specification](https://www.w3.org/TR/CSS1/)
- `css2`: [W3C CSS2 Specification](https://www.w3.org/TR/CSS2/)
- `css3`/`selectors-3`: [W3C Selectors Level 3](https://www.w3.org/TR/selectors-3/)
- `selectors-4`: [W3C Selectors Level 4](https://www.w3.org/TR/selectors-4/)
- `latest`: refers to `selectors-4`
- `progressive`: `latest` + accepts unknown pseudo-classes, pseudo-elements and attribute case sensitivity modifiers

## Migration Guides

- [Migrating from 1.x to 3.x](CHANGELOG.md#migrating-from-1x-to-3x)
- [Migrating from 2.x to 3.x](CHANGELOG.md#migrating-from-2x-to-3x)
- [Migrating from 1.x to 2.x](CHANGELOG.md#220)

See [Changelog](CHANGELOG.md) for release details.

## Installation

```bash
npm install css-selector-parser
# or
yarn add css-selector-parser
# or
pnpm add css-selector-parser
```

## Usage

### Parsing Selectors

```javascript
import { createParser } from 'css-selector-parser';

const parse = createParser();
const selector = parse('a[href^="/"], .container:has(nav) > a[href]:nth-child(2)::before');

console.log(selector);
```

This produces an AST (Abstract Syntax Tree) output:

```javascript
({
    type: 'Selector',
    rules: [
        {
            type: 'Rule',
            items: [
                { type: 'TagName', name: 'a' },
                {
                    type: 'Attribute',
                    name: 'href',
                    operator: '^=',
                    value: { type: 'String', value: '/' }
                }
            ]
        },
        {
            type: 'Rule',
            items: [
                { type: 'ClassName', name: 'container' },
                {
                    type: 'PseudoClass',
                    name: 'has',
                    argument: {
                        type: 'Selector',
                        rules: [
                            {
                                type: 'Rule',
                                items: [ { type: 'TagName', name: 'nav' } ]
                            }
                        ]
                    }
                }
            ],
            nestedRule: {
                type: 'Rule',
                items: [
                    { type: 'TagName', name: 'a' },
                    { type: 'Attribute', name: 'href' },
                    {
                        type: 'PseudoClass',
                        name: 'nth-child',
                        argument: { type: 'Formula', a: 0, b: 2 }
                    },
                    {
                        type: 'PseudoElement',
                        name: 'before'
                    }
                ],
                combinator: '>'
            }
        }
    ]
})
```

### Building and Rendering Selectors

```javascript
import { ast, render } from 'css-selector-parser';

const selector = ast.selector({
    rules: [
        ast.rule({
            items: [
                ast.tagName({name: 'a'}),
                ast.attribute({name: 'href', operator: '^=', value: ast.string({value: '/'})})
            ]
        }),
        ast.rule({
            items: [
                ast.className({name: 'container'}),
                ast.pseudoClass({
                    name: 'has',
                    argument: ast.selector({
                        rules: [ast.rule({items: [ast.tagName({name: 'nav'})]})]
                    })
                })
            ],
            nestedRule: ast.rule({
                combinator: '>',
                items: [
                    ast.tagName({name: 'a'}),
                    ast.attribute({name: 'href'}),
                    ast.pseudoClass({
                        name: 'nth-child',
                        argument: ast.formula({a: 0, b: 2})
                    }),
                    ast.pseudoElement({name: 'before'})
                ]
            })
        })
    ]
});

console.log(render(selector)); // a[href^="/"], .container:has(nav) > a[href]:nth-child(2)::before
```

### Traversing the AST

The `traverse` function allows you to walk through the AST and visit each node, making it easy to analyze or transform selectors.

```javascript
import { createParser, traverse } from 'css-selector-parser';

const parse = createParser();
const selector = parse('div.foo > span#bar:hover::before');

// Simple visitor function - called for each node
traverse(selector, (node, context) => {
    console.log(node.type, context.parents.length);
});

// Visitor with enter/exit hooks
traverse(selector, {
    enter(node, context) {
        console.log('Entering:', node.type);
        if (node.type === 'ClassName') {
            console.log('Found class:', node.name);
        }
    },
    exit(node, context) {
        console.log('Leaving:', node.type);
    }
});

// Skip visiting children of specific nodes
traverse(selector, (node) => {
    if (node.type === 'PseudoClass') {
        // Don't visit children of pseudo-classes
        return false;
    }
});

// Practical example: collect all class names
const classNames = [];
traverse(selector, (node) => {
    if (node.type === 'ClassName') {
        classNames.push(node.name);
    }
});
console.log(classNames); // ['foo']

// Access parent information
traverse(selector, (node, context) => {
    console.log({
        type: node.type,
        parent: context.parent?.type,
        depth: context.parents.length,
        key: context.key,
        index: context.index
    });
});
```

The traversal context provides:
- `node`: The current AST node being visited
- `parent`: The parent node (undefined for root)
- `parents`: Array of all ancestor nodes from root to current
- `key`: Property name in parent that references this node
- `index`: Array index if this node is in an array

## CSS Modules Support

CSS Modules are specifications that add new selectors or modify existing ones. This parser supports various CSS modules that can be included in your syntax definition:

```javascript
import { createParser } from 'css-selector-parser';

// Create a parser with specific CSS modules enabled
const parse = createParser({
    syntax: 'selectors-4',
    modules: ['css-position-3', 'css-scoping-1']
});
```

### Supported CSS Modules

| Module | Description |
|--------|-------------|
| `css-position-1/2/3/4` | Position-related pseudo-classes |
| `css-scoping-1` | Shadow DOM selectors (`:host`, `:host-context()`, `::slotted()`) |
| `css-pseudo-4` | Modern pseudo-elements (`::selection`, `::backdrop`, etc.) |
| `css-shadow-parts-1` | `::part()` for styling shadow DOM components |
| `css-nesting-1` | CSS Nesting selector (`&`) |

The `latest` syntax automatically includes all modules marked as current specifications.

## API Documentation

- [Complete API Documentation](docs/modules.md)
- [Parsing CSS Selectors](docs/modules.md#createParser)
- [Constructing CSS AST](docs/modules.md#ast)
- [Rendering CSS AST](docs/modules.md#render)
- [Traversing CSS AST](docs/modules.md#traverse)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT

## Security Contact

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.

## Sponsorship

If you find this project useful, please consider [sponsoring the developer](https://github.com/sponsors/mdevils) or [supporting on Patreon](https://patreon.com/mdevils).

---
_Source: https://npm.io/package/css-selector-parser · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
