AbsoluteJS

absolute/localize-react-props

Disallow variables that are only passed to a single custom child component; move them into that component instead.

React & JSXSuggestion
View on GitHub

#Rule Details

Encourages colocating state and data with the component that actually consumes it. If a variable — or a useState pair — is only ever passed to a single custom child, the rule suggests moving the declaration into that child instead of threading it through the parent as a prop.

For useState, both the state value and its setter must be used exclusively inside one custom (uppercase-tagged) child element before the rule fires. For plain variables, the rule waits until the end of the file and only reports a value when it is the sole candidate for a given child component — if two or more values flow to the same component, they are assumed to be settings that belong on the parent.

There are deliberate escape hatches: anything derived from a custom hook (useX) is exempt, usage on a native lowercase element counts as "used outside" and suppresses the report, and values passed to a *Provider/*Context value prop are ignored.

#Examples

Incorrect

State + setter to a single child

TSX
function Counter() {
	const [count, setCount] = useState(0);
	// Both state and setter only reach <Display /> → move them inside it
	return <Display count={count} setCount={setCount} />;
}
TSX
function Page() {
	const heading = 'Welcome';
	return (
		<section>
			<Header title={heading} /> {/* only consumer */}
		</section>
	);
}
Correct
TSX
function Toolbar() {
	const label = 'Save';
	// Passed to two different children → assumed shared, not flagged
	return (
		<div>
			<PrimaryButton text={label} />
			<MenuItem text={label} />
		</div>
	);
}
TSX
function Profile() {
	const firstName = 'Ada';
	const lastName = 'Lovelace';
	// Two candidates for the same component → treated as parent-owned settings
	return <NameTag firstName={firstName} lastName={lastName} />;
}

Hook-derived values are exempt

TSX
function Feed() {
	const data = useFetch('/api/posts'); // hook-derived
	const posts = data.posts;            // references a hook resultexempt
	return <PostList posts={posts} />;
}

#Configuration

Enable this rule in your ESLint configuration:

JS
{
	rules: {
		'absolute/localize-react-props': 'error'
	}
}

#When Not To Use It

Container/presentational architectures intentionally hoist state into a parent and pass it down to a single dumb child. If that pattern is core to your codebase, this rule will produce false positives — disable it or restrict it to leaf modules.

#Resources