The @source directive tells Tailwind CSS where to look for utility class names in your project files. This is the CSS equivalent of the content configuration option.
Syntax
@source "path/to/files/**/*.{html,js}";
Basic Usage
Single Source Path
Define a glob pattern to scan for class names:
@source "./src/**/*.{html,js,jsx}";
@tailwind utilities;
Tailwind will scan all .html, .js, and .jsx files in the ./src directory and its subdirectories.
Multiple Source Paths
You can specify multiple @source directives:
@source "./src/**/*.tsx";
@source "./components/**/*.vue";
@source "./pages/**/*.php";
@tailwind utilities;
Quoted Paths Required
Source paths must be wrapped in quotes (single or double).
/* ❌ Invalid - missing quotes */
@source ./src/**/*.html;
/* ✅ Valid - double quotes */
@source "./src/**/*.html";
/* ✅ Valid - single quotes */
@source './src/**/*.html';
Negating Paths
Exclude specific paths using the not keyword:
@source "./src/**/*.js";
@source not "./src/vendor/**";
This scans all JavaScript files in ./src except those in ./src/vendor.
Multiple Negations
@source "./src/**/*.ts";
@source not "./src/**/*.test.ts";
@source not "./src/**/*.spec.ts";
Inline Candidates
The inline() function allows you to specify utility classes directly in CSS, ensuring they’re always included:
Basic Inline
@source inline("flex items-center justify-center");
@tailwind utilities;
This guarantees that flex, items-center, and justify-center are always generated, even if they’re not found in your source files.
Use Cases for Inline
Always-included utilities
Dynamic class names
Third-party components
/* Ensure base utilities are always available */
@source inline("block inline flex grid");
Brace Expansion
Inline sources support brace expansion for generating multiple candidates:
@source inline("bg-red-{50,100,200,300,400,500}");
Expands to:
bg-red-50
bg-red-100
bg-red-200
bg-red-300
bg-red-400
bg-red-500
Numeric Ranges
Generate numeric sequences:
@source inline("bg-red-{100..900..100}");
Expands to:
bg-red-100
bg-red-200
bg-red-300
...
bg-red-900
Complex Expansions
Combine multiple patterns:
@source inline("bg-{red,blue,green}-{500,600,700}");
Expands to:
bg-red-500, bg-red-600, bg-red-700
bg-blue-500, bg-blue-600, bg-blue-700
bg-green-500, bg-green-600, bg-green-700
Negating Inline Candidates
Exclude specific inline candidates:
@source inline("flex grid block");
@source not inline("grid");
This includes flex and block but excludes grid.
Path Resolution
Paths are resolved relative to the CSS file’s location or the configured base directory.
Relative Paths
/* Relative to CSS file */
@source "../components/**/*.jsx";
@source "./templates/**/*.html";
Absolute-like Paths
/* From project root */
@source "/src/**/*.ts";
Base Directory
When using the compile API, paths are resolved from the base option:
const { sources } = await compile (
`@source "./src/**/*.js";` ,
{ base: '/project/root' }
)
// sources = [{
// pattern: './src/**/*.js',
// base: '/project/root',
// negated: false
// }]
Restrictions
Top-level Only
@source must be at the top level and cannot be nested inside other rules.
/* ❌ Invalid - nested */
@media ( min-width : 768 px ) {
@source "./src/**/*.js";
}
/* ✅ Valid - top level */
@source "./src/**/*.js";
No Body
@source cannot have a body with CSS rules.
/* ❌ Invalid - has body */
@source "./src/**/*.js" {
color: red;
}
/* ✅ Valid - no body */
@source "./src/**/*.js";
Using with @tailwind utilities
The @tailwind utilities directive can also specify a source path:
@tailwind utilities source("./src/**/*.jsx");
Or use source(none) to disable automatic scanning:
@tailwind utilities source(none);
This is useful when you want complete control via @source directives:
@source inline("flex grid");
@tailwind utilities source(none);
Parsing Logic
From the source code (index.ts:256-307), here’s how @source is processed:
if ( node . name === '@source' ) {
if ( node . nodes . length > 0 ) {
throw new Error ( '`@source` cannot have a body.' );
}
if ( ctx . parent !== null ) {
throw new Error ( '`@source` cannot be nested.' );
}
let not = false ;
let inline = false ;
let path = node . params ;
// Handle 'not' prefix
if ( path . startsWith ( 'not ' )) {
not = true ;
path = path . slice ( 4 );
}
// Handle 'inline()' function
if ( path . startsWith ( 'inline(' )) {
inline = true ;
path = path . slice ( 7 , - 1 ). trim ();
}
// Validate quoted path
if ( ! isQuoted ( path )) {
throw new Error ( '`@source` paths must be quoted.' );
}
let source = path . slice ( 1 , - 1 );
if ( inline ) {
// Process inline candidates with brace expansion
let destination = not ? ignoredCandidates : inlineCandidates ;
for ( let candidate of expand ( source )) {
destination . push ( candidate );
}
} else {
// Add to sources array for scanning
sources . push ({
base: ctx . context . base ,
pattern: source ,
negated: not ,
});
}
// Remove @source from output
return WalkAction . ReplaceSkip ([]);
}
Output
The @source directive is removed from the final CSS output. It only affects which utility classes are generated:
/* Input */
@source "./src/**/*.html";
@source inline("flex");
@tailwind utilities;
/* Output (only if 'flex' is used) */
.flex {
display : flex ;
}
/* @source directives are removed */
API Usage
When using the JavaScript API, sources are returned:
import { compile } from 'tailwindcss'
const { sources , build } = await compile ( `
@source "./src/**/*.tsx";
@source not "./src/**/*.test.tsx";
@tailwind utilities;
` )
console . log ( sources )
// [
// { pattern: './src/**/*.tsx', base: '', negated: false },
// { pattern: './src/**/*.test.tsx', base: '', negated: true }
// ]