Skip to content

use_sliver_prefix

v0.4.0WarningFixConfigurableWidget Best Practices

Flags a widget whose build returns a sliver while the class name does not start with Sliver.

Slivers and box widgets are not interchangeable, and the type system does not separate them — both are just Widget. Drop a sliver-returning widget into a Column and you get a runtime error about RenderSliver not being a RenderBox, from a stack that points into the framework rather than at your file. The name is the only signal at the call site, which is why Flutter’s own framework uses it throughout. The quick fix renames the class.

This rule is in the pedantic preset.

See also: CustomScrollView

many_lints.yaml
rules:
use_sliver_prefix: true

Nothing at the call site says ProductList cannot go in a Column:

class ProductList extends StatelessWidget {
const ProductList({super.key});
@override
Widget build(BuildContext context) {
return SliverList(delegate: SliverChildListDelegate([]));
}
}
class SliverProductList extends StatelessWidget {
const SliverProductList({super.key});
@override
Widget build(BuildContext context) {
return SliverList(delegate: SliverChildListDelegate([]));
}
}
// The name now makes the only valid parent obvious
final scroll = CustomScrollView(slivers: const [SliverProductList()]);

The build lives on the State, but the diagnostic — and the rename — land on the widget class, since that is the name callers write:

// Don't
class ProductHeader extends StatefulWidget {
const ProductHeader({super.key});
@override
State<ProductHeader> createState() => _ProductHeaderState();
}
class _ProductHeaderState extends State<ProductHeader> {
@override
Widget build(BuildContext context) => const SliverAppBar();
}
// Do — rename the widget; the private State follows for readability
class SliverProductHeader extends StatefulWidget {
const SliverProductHeader({super.key});
@override
State<SliverProductHeader> createState() => _SliverProductHeaderState();
}
class _SliverProductHeaderState extends State<SliverProductHeader> {
@override
Widget build(BuildContext context) => const SliverAppBar();
}

If your project’s state classes extend something of your own instead of Flutter’s State, name that base so the pairing still works:

analysis_options.yaml
many_lints:
rules:
use_sliver_prefix:
state_base_classes: [AppState]

Only a single-return build is examined. A build that branches — an if with two returns, or a body building a local first — is not reported even when every path returns a sliver:

// Not reported: two return statements
@override
Widget build(BuildContext context) {
if (isEmpty) return const SliverToBoxAdapter(child: SizedBox());
return SliverList(delegate: SliverChildListDelegate([]));
}

Only Flutter’s own slivers count. The returned type must be declared in package:flutter and its name must start with Sliver, so a sliver from sliver_tools or one of your own does not trigger the rule.

Renaming the class is not automatic beyond the declaration — call sites are updated by your IDE’s rename refactoring, not by the quick fix.

Option Type Default Description
state_base_classes list of strings [] Additional non-State base classes whose subclasses should be treated as state classes
many_lints.yaml
rules:
use_sliver_prefix: false

To keep the rule on but skip certain paths, use per-rule exclude.