Direction Attribute Missing
Ensure dir="ltr"
or dir="rtl"
is set on your HTML element
The plugin works out of the box with zero configuration, but offers powerful customization options for advanced use cases.
module.exports = { plugins: [ require('postcss-logical-polyfill')() ]}
const logicalPolyfill = require('postcss-logical-polyfill');
module.exports = { plugins: [ logicalPolyfill({ // Direction selectors (default shown) rtl: { selector: '[dir="rtl"]' }, ltr: { selector: '[dir="ltr"]' },
// Output order for unscoped properties outputOrder: 'ltr-first' // or 'rtl-first' }) ]}
Control how the plugin generates direction-specific selectors:
{ rtl: { selector: '[dir="rtl"]' }, ltr: { selector: '[dir="ltr"]' }}
{ rtl: { selector: '.rtl' }, ltr: { selector: '.ltr' }}
{ rtl: { selector: '[data-theme="rtl"]' }, ltr: { selector: '[data-theme="ltr"]' }}
Control the order of generated rules for unscoped properties:
{ outputOrder: 'ltr-first' // Default: LTR rules first, then RTL // outputOrder: 'rtl-first' // RTL rules first, then LTR}
Example Output:
.container { margin-left: 1rem; margin-right: 1rem;}[dir="ltr"] .container { padding-left: 1rem;}[dir="rtl"] .container { padding-right: 1rem;}
.container { margin-left: 1rem; margin-right: 1rem;}[dir="rtl"] .container { padding-right: 1rem;}[dir="ltr"] .container { padding-left: 1rem;}
module.exports = { webpack: (config) => { config.module.rules.push({ test: /\.css$/, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ require('postcss-logical-polyfill')({ rtl: { selector: '[dir="rtl"]' }, ltr: { selector: '[dir="ltr"]' } }) ] } } } ] }); return config; }};
import { defineConfig } from 'vite';
export default defineConfig({ css: { postcss: { plugins: [ require('postcss-logical-polyfill')({ outputOrder: 'ltr-first' }) ] } }});
module.exports = { module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ require('postcss-logical-polyfill')({ rtl: { selector: '.rtl' }, ltr: { selector: '.ltr' } }) ] } } } ] } ] }};
module.exports = { content: ['./src/**/*.{html,js}'], theme: { extend: {} }, plugins: [], // Add to PostCSS processing corePlugins: { // Disable Tailwind's logical properties if using this plugin margin: true, padding: true }};
// postcss.config.jsmodule.exports = { plugins: [ require('tailwindcss'), require('postcss-logical-polyfill')(), require('autoprefixer') ]};
For complex scenarios, you can use advanced selector patterns:
{ rtl: { selector: 'html[dir="rtl"]', // More specific }, ltr: { selector: 'html[dir="ltr"]', }}
{ rtl: { selector: '[dir="rtl"], .rtl-mode' // Multiple selectors }, ltr: { selector: '[dir="ltr"], .ltr-mode' }}
You must set the dir
attribute on your HTML for the generated CSS to work:
<!DOCTYPE html><html dir="ltr"> <!-- For left-to-right layouts --><head> <meta charset="UTF-8"> <title>My App</title></head><body> <!-- Your content --></body></html>
For RTL languages:
<html dir="rtl"> <!-- For right-to-left layouts -->
For applications that support dynamic direction switching:
// JavaScript to toggle directionfunction toggleDirection() { const html = document.documentElement; const currentDir = html.getAttribute('dir'); html.setAttribute('dir', currentDir === 'rtl' ? 'ltr' : 'rtl');}
import { useState } from 'react';
function App() { const [direction, setDirection] = useState('ltr');
useEffect(() => { document.documentElement.setAttribute('dir', direction); }, [direction]);
return ( <div> <button onClick={() => setDirection(direction === 'ltr' ? 'rtl' : 'ltr')}> Switch to {direction === 'ltr' ? 'RTL' : 'LTR'} </button> {/* Your app content */} </div> );}
The plugin automatically optimizes block-direction properties to generate fewer rules:
/* Input */.element { margin-block: 1rem; padding-block-start: 0.5rem;}
/* Optimized Output - No direction selectors needed */.element { margin-top: 1rem; margin-bottom: 1rem; padding-top: 0.5rem;}
For large codebases, consider processing only files that contain logical properties:
// Only process certain file patternsmodule.exports = { plugins: [ // Other plugins require('postcss-logical-polyfill')() ]};
You can debug the transformation process by examining the generated CSS:
const postcss = require('postcss');const logicalPolyfill = require('postcss-logical-polyfill');
const result = postcss([logicalPolyfill()]) .process(css, { from: undefined });
console.log('Original CSS:', css);console.log('Transformed CSS:', result.css);
Direction Attribute Missing
Ensure dir="ltr"
or dir="rtl"
is set on your HTML element
Selector Specificity
Check that your direction selectors have appropriate specificity
Order Matters
Consider the outputOrder
option for consistent rule ordering
dir
attribute on your <html>
element/* Before: Physical properties */.element { margin-left: 1rem; margin-right: 2rem; padding-left: 0.5rem;}
/* After: Logical properties */.element { margin-inline: 1rem 2rem; padding-inline-start: 0.5rem;}
If migrating from other logical property tools, note that this plugin works in the opposite direction - it converts logical properties TO physical properties for compatibility.