Web components implementing the PatternFly v6 design system.
PatternFly Elements v6 is a web component library built with LitElement that implements the PatternFly v6+ design system for non-React environments. This enables developers to use PatternFly v6+ component designs in Vue, Angular, Svelte, vanilla JavaScript, and server-side platforms like Drupal and Ruby on Rails.
- 1:1 Visual Parity: Components must be visually identical to React PatternFly v6
- Framework Agnostic: Work in any framework or vanilla JavaScript
- Standards-Based: Built on Web Components standards (Custom Elements, Shadow DOM)
- Design Token Integration: Use PatternFly v6 design tokens for theming
- Node.js 24.x (LTS) - See
.nvmrcfor version - npm 10+
This project uses Node.js 24.x. We recommend using nvm for Node.js version management.
Install nvm:
macOS/Linux:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bashOr with wget:
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bashWindows:
Download and install nvm-windows
After installation:
# Install the project's Node.js version (reads from .nvmrc)
nvm install
# Use the project's Node.js version
nvm useThe .nvmrc file in the project root specifies the exact Node.js version. Running nvm use automatically switches to this version.
npm ciWhat happens on postinstall:
- Cache PatternFly sources - Clones React PatternFly and core PatternFly to
.cache/ - Analyze dependencies - Generates
react-dependency-tree.jsonmapping component dependencies - Copy React demos - Extracts React demo files to
patternfly-react/for comparison testing - Copy PatternFly assets - Copies base CSS, fonts, and images to
dev-server/
These steps ensure:
- React component sources are available for conversion reference
- Dependency analysis enables optimal component conversion order
- Side-by-side React comparison demos for visual parity validation
# Start development server
npm run dev
# Opens http://localhost:8000 with the development index page
# Compile TypeScript
npm run compile
# Run linters
npm run lint
# Run unit tests
npm run test
# Run E2E tests
npm run e2e
# Analyze component dependencies
npm run analyze-dependencies
# Find next component to convert (after running analyze-dependencies)
npx tsx scripts/find-blockers.tsDevelopment Pages:
/- Main development index with auto-generated component list/elements/pfv6-{name}/demo/- Lit component demo index (lists all demos for the component)/elements/pfv6-{name}/demo/{page}/- Individual Lit component demo pages/elements/pfv6-{name}/react/- React component demo index (comparison demos)/elements/pfv6-{name}/react/{page}/- Individual React component demo pages
This project uses specialized AI subagents to convert React PatternFly components to LitElement web components.
Use the find subagent to identify the optimal next component based on dependency analysis:
Prompt:
Use the find.md subagent to locate the next component we should build
The find subagent:
- Analyzes the dependency tree in
react-dependency-tree.json - Identifies components with fewest dependencies (easier to convert)
- Prioritizes components that unblock the most other components
- Recommends the next best candidate with reasoning
Once you have a component recommendation, use the create subagent to perform the conversion:
Prompt:
Use the create.md subagent following strict delegation rules, convert {{ Component Name }}
Replace {{ Component Name }} with the component name from the find recommendation (e.g., "Brand", "Spinner", "Divider").
The create subagent orchestrates the full conversion workflow:
- API Design - Translates React props to LitElement properties
- Implementation - Creates the component TypeScript file
- Demos - Converts React examples to HTML demos
- CSS - Translates React SCSS to Shadow DOM CSS
- Accessibility - Validates ARIA patterns and keyboard interactions
- Tests - Generates unit tests, visual parity tests, and CSS API tests
Example workflow:
# Step 1: Find next component
> Use the find.md subagent to locate the next component we should build
# Agent responds: "Next Component: Spinner (0 dependencies, blocks 6 components)"
# Step 2: Convert the component
> Use the create.md subagent following strict delegation rules, convert Spinner
# Agent performs full conversion with automated validationFor more details on the conversion process, see the subagent documentation in agents/.
/elements/ - Web component implementations
/pfv6-card/ - Example: Card component
pfv6-card.ts - Component TypeScript
pfv6-card.css - Component styles
/demo/ - Component demo files (minimal HTML fragments)
index.html - Primary demo page
variants.html - Additional demos (optional)
/test/ - Component unit tests
pfv6-card.spec.ts
/lib/ - Shared utilities and contexts
/dev-server/ - Development server configuration
index.html - Main development page (served at /)
/plugins/ - Custom dev server plugins (routing, import maps, demo discovery)
/styles/ - Global styles and PatternFly base CSS
/assets/ - Static resources
/tests/ - E2E test files and page objects
/docs/ - Project documentation
Demo Files: Each component's /demo/ folder contains simple HTML fragments (no boilerplate). The dev server automatically wraps them using dev-server/index.html as the template, replacing only the <main> content with the demo markup.
All components use the pfv6- prefix:
pfv6-buttonpfv6-cardpfv6-modal- etc.
Demo CSS Files:
Our demos use two PatternFly CSS files:
-
base.css- Core PatternFly design tokens and base styles- Copied from
@patternfly/react-core/dist/styles/base.css - Used by all demos (Lit and React)
- Location:
/dev-server/styles/patternfly/base.css
- Copied from
-
patternfly.css- Full PatternFly CSS (includes component styles and layout utilities)- Copied from
@patternfly/patternfly/patternfly.css - Used by all demos (Lit and React)
- Location:
/dev-server/styles/patternfly/patternfly.css
- Copied from
Why patternfly.css for Lit demos?
While Lit components use Shadow DOM with scoped styles, we still need patternfly.css for layout utility classes like pf-v6-l-flex, pf-v6-l-gallery, and pf-v6-l-grid.
Layout components are NOT converted to custom elements. Instead, demos use raw HTML with PatternFly layout CSS classes:
- ✅ Component demos: Use custom elements (
<pfv6-card>,<pfv6-button>) - ✅ Layout usage: Use HTML + CSS classes (
<div class="pf-v6-l-flex pf-m-row">)
This approach maintains pixel-perfect parity with React while leveraging PatternFly's battle-tested layout system.
Problem: Some components use display: contents to act as semantically invisible wrappers (e.g., pfv6-divider, pfv6-skeleton, pfv6-backdrop, pfv6-background-image). However, elements with display: contents become invisible to CSS child selectors like .pf-v6-l-flex > *, causing layout spacing and properties to not apply correctly.
Solution: We use a CSS variable contract pattern to bridge layout containers and display: contents components:
- Light DOM CSS (
styles/layout.css) sets private CSS variables on custom elements inside layout containers - Shadow DOM CSS (component styles) consumes these variables to apply spacing
Architecture:
Layout Container (.pf-v6-l-flex)
↓ sets --_layout-* variables
Custom Element (pfv6-divider)
↓ consumes variables
Shadow DOM (inner <hr>)
✓ spacing applied
Usage in Your Project:
Include the layout integration CSS in your HTML:
<link rel="stylesheet" href="/styles/layout.css">This CSS file is distributed with the component library (not dev-server only) and should be included alongside PatternFly CSS.
How It Works:
The styles/layout.css file explicitly targets components with display: contents and passes through layout properties:
/* Flex layout integration */
.pf-v6-l-flex {
& > :is(pfv6-divider, pfv6-skeleton, pfv6-backdrop, pfv6-background-image) {
--_layout-order: var(--pf-v6-l-flex--item--Order);
--_layout-max-width: 100%;
--_layout-margin-block-start: 0;
--_layout-margin-block-end: 0;
--_layout-margin-inline-start: 0;
--_layout-margin-inline-end: 0;
}
}
/* Direction-specific rules */
.pf-v6-l-flex.pf-m-column {
& > :is(pfv6-divider, pfv6-skeleton, pfv6-backdrop, pfv6-background-image) {
--_layout-margin-block-end: var(--pf-v6-l-flex--spacer--row);
}
}Components then consume these variables in their shadow DOM:
/* In pfv6-divider.css */
hr, div {
order: var(--_layout-order);
max-width: var(--_layout-max-width);
margin-block: var(--_layout-margin-block-start) var(--_layout-margin-block-end);
margin-inline: var(--_layout-margin-inline-start) var(--_layout-margin-inline-end);
}Supported Layouts:
Layout integration is implemented for all 7 PatternFly layout systems:
- Flex - Full margin control for all direction modifiers (
pf-m-row,pf-m-column,pf-m-row-reverse,pf-m-column-reverse) - Grid - Column placement and grid-specific properties
- Gallery - Works automatically via CSS
gap - Stack - Works automatically via CSS
gap - Level - Works automatically via CSS
gap - Split - Works automatically via CSS
gap - Bullseye - Uses container padding (no child spacing needed)
Adding New Components:
When creating a new component with display: contents:
- Add component to
:is()selector lists instyles/layout.css - Consume layout variables in component shadow DOM CSS
- Test in Flex, Grid, and Gallery layouts to verify spacing
Variable Naming Convention:
- Use
--_prefix for "private" variables (internal contract between layout CSS and components) - Standard layout variables:
--_layout-order,--_layout-max-width,--_layout-margin-*,--_layout-grid-*
This pattern ensures visual parity with React components while maintaining the encapsulation benefits of Shadow DOM.
- See
CLAUDE.mdfor comprehensive development guidelines - See
docs/for component documentation
- TypeScript - Compiled to ES6 JavaScript
- Lit - Web component framework
- PatternFly v6 - Design system and tokens
- @web/dev-server - Development server
- @web/test-runner - Unit testing
- Playwright - E2E testing
- Wireit - Task orchestration
See CLAUDE.md for detailed coding standards and guidelines.
MIT