I recently published agnostic_split_view, an open-source Flutter package built around a simple idea:
A split-view layout shouldn't have to dictate which UI framework your application uses.
Flutter gives us Material and Cupertino, but underneath them is a more fundamental layer: Flutter's widget and rendering system.
So I wanted to explore what a split-view component would look like if it stayed at that lower, framework-agnostic level.
The Problem
When building custom interfaces such as:
- IDE-style layouts
- dashboards
- document editors
- developer tools
- desktop applications
- custom design systems
you may want resizable panes without coupling your layout primitive to Material or Cupertino.
The goal wasn't to build another opinionated UI component.
The goal was to build a headless layout primitive that handles complex layout and interaction logic while leaving visual design to the application.
That's where agnostic_split_view came from.
What is agnostic_split_view?
agnostic_split_view is a framework-agnostic split-view layout package for Flutter.
It is built using Flutter's neutral widgets. Dart layer rather than depending on Material or Cupertino.
That means you can use it with:
- Material applications
- Cupertino applications
- custom design systems
- third-party UI systems
- a bare WidgetsApp The package itself has no runtime dependencies beyond Flutter.
The Architecture
One of the main design decisions was to keep layout calculations separate from the divider's visual appearance.
The split view is responsible for things such as:
- pane geometry
- resizing
- constraints
- collapse behavior
- directionality
- controller state The application remains responsible for deciding how the divider should look. This is what makes the package headless.
CustomMultiChildLayout
The core layout is built around Flutter's CustomMultiChildLayout.
Instead of stacking multiple independent layout mechanisms together, the split-view geometry is calculated through a custom layout delegate.
Conceptually, the layout needs to answer a few questions:
How much space does the first pane receive?
↓
Where does the divider go?
↓
How much space remains for the second pane?
The delegate can then position the children according to the current split fraction and the available constraints.
This also gave me a much better understanding of Flutter's layout pipeline and how constraints flow through custom layouts.
Resizing
Dragging the divider changes the split position.
Instead of treating the divider as merely a visual element, its interaction is connected to the split-view controller.
That allows the layout to respond to user interaction while keeping the controller API independent from the divider's visual implementation.
The result is a separation between:
Interaction
Pointer movement
↓
Split position
↓
Constraints
↓
Layout
and:
Presentation
Divider builder
↓
Visual appearance
↓
Hover/drag/focus states.
Constraints
A split view becomes much more useful when pane sizes cannot grow or shrink indefinitely.
agnostic_split_view supports minimum and maximum pane constraints so applications can define sensible boundaries for each side.
For example:
┌──────────────────┬──────────────────────┐
│ │ │
│ Minimum size │ Main pane │
│ │ │
└──────────────────┴──────────────────────┘
↑
Divider
The available space and configured constraints determine how far the divider can move.
Collapsible Panes
I also wanted resizing to support a common desktop UI interaction:
drag → reach threshold → collapse
This makes it possible to create interfaces where a secondary pane can be temporarily hidden without requiring a completely separate navigation mechanism.
The controller can also be used to programmatically:
- collapse
- expand
- toggle
- resize
- reset the split view. That makes the component useful for both direct manipulation and application-driven state changes.
Collapsible Panes
I also wanted resizing to support a common desktop UI interaction:
drag → reach threshold → collapse
This makes it possible to create interfaces where a secondary pane can be temporarily hidden without requiring a completely separate navigation mechanism.
The controller can also be used to programmatically:
- collapse
- expand
- toggle
- resize
- reset the split view. That makes the component useful for both direct manipulation and application-driven state changes.
The Divider Is Not the Design System
One of the things I deliberately avoided was making the divider visually opinionated.
Instead, the package exposes divider builders.
That means an application can create something as simple as:
──────────│──────────
or something more interactive:
────────── ◉ ──────────
or a completely custom divider with hover, drag, and focus states.
The split-view logic doesn't need to know what the application's design system looks like.
That's an important distinction between a UI component and a layout primitive.
Why Build It?
This package started as more than an attempt to solve a UI problem.
I wanted to understand Flutter at a deeper level.
While building it, I spent time working with:
CustomMultiChildLayout
MultiChildLayoutDelegate
Flutter constraints
layout geometry
pointer interaction
controller-based state
Directionality
rebuild boundaries
headless component design
The interesting part wasn't simply getting a divider to move.
It was understanding** why the layout behaves the way it does.**
What I Learned
Building a reusable Flutter package is different from building a feature inside an application.
Inside an application, you already know:
- the design system
- the state-management approach
- the target platforms
- the expected interaction patterns
- the application's constraints A public package doesn't have those assumptions. You have to think about the developer who will use it differently from you. That changed how I approached the API. Instead of asking: "How can I make this UI work?" I started asking: "What should the developer be able to control without knowing how the layout works internally?" That shift was probably the most valuable part of building the package.
Try It
The package is now available on pub.dev:
Package: https://pub.dev/packages/agnostic_split_view
If you're building dashboards, IDE-style interfaces, editors, desktop applications, or custom Flutter design systems, I'd love to hear your feedback.
Especially if you find an API edge case, interaction problem, or a use case I haven't considered.
Final Thought
agnostic_split_view started with a relatively small question:
What if a split view didn't need to know what your design system was?
The result is a small Flutter package, but building it gave me a much deeper understanding of the framework's layout system.
And that's one of the reasons I enjoy building open source:
You start by trying to solve a problem.
You often finish by understanding the platform better.
#flutter #dart #opensource #programming












