Saved Views & Saved Filters
If you're building B2B SaaS in 2026 with data tables / lists / dashboards, power users want to save filter combinations as named views — "My open tickets", "Q3 enterprise deals", "High-priority bugs". Linear, Notion, Airtable, Asana, GitHub Projects all have them. The naive approach: filters reset on every page load. The structured approach: save view-state as named entities, share with team, set defaults, support per-user customization, sync via URL. Saved views graduate a product from "useful" to "indispensable" — once users build their workflow around saved views, they don't leave. This guide covers the implementation craft. (Related: data-tables-sort-filter-bulk-chat for filter mechanics; this is for saving / managing filters.)
1. Decide view scope — personal, shared, or both
Decide view scope.
Personal views (my views):
- Created by user; visible to user only
- Each team member has own views
- Most flexible
Shared views (team views):
- Created and shared
- All members see same view
- "Open bugs" - team-shared
Workspace views:
- Set by admin; default for all members
- Standard reports
Hybrid (recommended):
- Personal views by default
- "Share with team" toggle to make shared
- Admin can mark default workspace views
For [USE CASE]:
Linear pattern:
- Personal views by default
- Shared workspace views possible
- Default views per team
Notion pattern:
- Database views shared by default
- Each user can customize their own version
- Confusing to onboard
Airtable pattern:
- Personal vs shared views distinct
- Permissions per view
Recommendation:
- Personal-first; add sharing as feature
- Mark default views (admin)
Output:
1. Scope model
2. Sharing rules
3. Default-view selection
4. Per-user customization
5. Migration if changing model
The Linear personal-first pattern: each user gets own view; can opt-in to share. Lowers cognitive load; users don't worry about "did I just change everyone's view?"
2. Schema design
Design saved views schema.
Core table:
saved_views:
- id (UUID)
- workspace_id (multi-tenant)
- resource_type (enum: 'tasks', 'projects', 'customers')
- name (string)
- description (optional)
- filters (JSONB)
- sort (JSONB)
- group_by (string, optional)
- columns (JSONB - for tables)
- chart_config (JSONB - for charts)
- visualization_type (enum: 'table', 'kanban', 'calendar', 'list')
- owner_user_id
- visibility (enum: 'private', 'workspace', 'public')
- shared_with_user_ids (array, for granular)
- pinned (boolean)
- order (int, for sorting in nav)
- icon / emoji (optional)
- created_at, updated_at
Filter shape (JSONB):
{
"operator": "AND",
"conditions": [
{"field": "status", "op": "in", "value": ["open", "in_progress"]},
{"field": "assignee", "op": "eq", "value": "current_user"},
{"field": "due_date", "op": "before", "value": "today + 7 days"}
]
}
Special values:
- "current_user" - dynamic (changes per viewer)
- "today" / "today + N days" - relative dates
- "@me" - shorthand for current user
Sort shape:
[{"field": "priority", "direction": "desc"}, {"field": "due_date", "direction": "asc"}]
Indexes:
- (workspace_id, resource_type, owner_user_id)
- (workspace_id, visibility) for shared views
Output:
1. Schema (DDL)
2. Filter JSONB structure
3. Special values for dynamic filters
4. Indexing
5. Multi-tenant scoping
The "current_user" dynamic: shared view "My open tickets" works for everyone. User who opens it sees their tickets, not creator's. Implemented via special placeholder.
3. Save view UI
Build save-view UI.
Flow:
1. User adjusts filters / sort / columns
2. Detect "current state differs from any saved view"
3. Show "Save view" button
4. Click → modal: name + visibility + icon
5. Save → view appears in nav
States:
Unsaved (filter changed):
- Filter bar shows "Modified"
- "Save" button highlighted
Saved (current state matches view):
- View name shown active
- "Save" button hidden / disabled
Modified saved view:
- View name + "Modified" indicator
- "Save changes" / "Save as new" / "Discard" options
Save dialog:
- Name (required)
- Description (optional)
- Icon / emoji (optional)
- Visibility:
- Private (only me)
- Workspace (everyone)
- Pin to sidebar (optional)
Update existing view:
- "Save changes" overwrites
- "Save as new" creates separate
- Permission check (can edit?)
Inline rename:
- Right-click view → rename
- Save without modal
Anti-patterns:
- "Save" auto-overwrites without ask
- No "save as new" option
- Modal too complex for simple saves
Output:
1. Save dialog
2. State indicators (unsaved / saved / modified)
3. Save flow (overwrite vs new)
4. Inline rename
5. Pinning to nav
The "Modified" indicator pattern: subtle "View name • Modified" tells users they've changed something. Clear "Save" / "Discard" actions.
4. View navigation — sidebar / tabs
How users see + access views.
Design view navigation.
Patterns:
Pattern A: Sidebar list (Linear / Notion)
- Dedicated sidebar section per resource type
- "My Views" + "Workspace Views" sections
- Star / pin to top
- Drag to reorder
Pattern B: Tabs above content
- Horizontal tabs at top of list
- Active view highlighted
- "+" to add new
- Used by: Notion databases
Pattern C: Dropdown
- Click view name → dropdown of all views
- More compact
- Used by: HubSpot
Pattern D: Hybrid
- Pinned views as tabs/sidebar
- All views in dropdown
Recommended for power-user products: sidebar (Linear-style); allows many views.
Sidebar UI:
Section structure:
- Default views (system; can't delete)
- My views (user-created)
- Team views (workspace-shared)
Each view item:
- Icon / emoji
- Name
- Count (optional - "12 open tickets")
- Active highlight
- Hover → context menu (rename, duplicate, delete, share)
Drag-and-drop reorder:
- Within section
- Persists to backend
Pinning:
- Star to pin to top
- Or: drag to "Pinned" subsection
Mobile:
- Sidebar hides; drawer / sheet
- Or: dropdown for narrow screens
Output:
1. Navigation pattern choice
2. Sidebar structure
3. View item design
4. Drag-reorder
5. Mobile fallback
The Linear sidebar pattern feels best for productivity tools: many views in compact list, easy to scan + select.
5. Filter UI — building queries
Saved views need a way to build them. Filter UI matters.
Build filter UI.
Approaches:
Faceted filters (recommended for most):
- Predefined facets: Status, Priority, Assignee, Tags
- Click facet → multi-select dropdown
- Pills above list show active filters
- Combinations: AND across facets, OR within
Operators per field:
- Text: contains, equals, starts with
- Date: is, before, after, between, in last X days
- Number: =, !=, <, >, between
- Single-select: is, is not
- Multi-select: contains, doesn't contain
Filter pills:
Display:
"Status: Open, In Progress" (multi-value)
"Assignee: @me" (special)
"Created: Last 7 days" (relative)
Click pill → reopen dropdown to edit
X icon → remove filter
"+ Add filter" button → field picker
Power-user query builder (advanced):
- Linear / Notion advanced filter
- AND / OR / nested groups
- For complex queries
Visualizations of filters:
- Compact pills above list
- Or: dedicated filter sidebar (Asana)
Empty state when filters return nothing:
- "No items match these filters"
- "Clear filters" button
URL state:
- Filters serialized to URL
- ?filters[status]=open,in_progress
- Shareable + bookmarkable
Output:
1. Faceted vs query-builder
2. Operators per field type
3. Pills design
4. URL state
5. Empty / no-match state
The "faceted by default + advanced when needed" pattern: 80% of users use faceted; 20% want SQL-like power. Don't force the simple users into the complex UI.
6. Sharing views — collaborative
Shared views require careful permission + edit handling.
Implement view sharing.
Visibility levels:
Private (default):
- Owner only
- Hidden from others
Workspace:
- All members can see + use
- Edit permission: owner only OR admin OR all
Specific users:
- Share with named members
- Granular control
Public link:
- Read-only URL share with non-members
- Risk: data exposure
- Requires explicit opt-in
Edit semantics:
Personal copy:
- User can edit local copy without affecting source
- "Save as new" creates personal version
Live sync:
- Edits to shared view affect everyone
- Owner / admin only can edit
- Confirmation on edit
Read-only:
- Use the view; can't modify
Recommendation:
- Workspace shared = read-only for non-owners
- Owner can edit; cascade to all viewers
- "Duplicate" for personal customization
Conflict scenarios:
Two users edit shared view at once:
- Last-writer-wins OR merge attempt
- Show warning: "This view has been updated"
Owner deletes shared view:
- Notify users who pinned it
- Option to "save as personal copy first"
User leaves workspace:
- Their personal views deleted (or transferred to admin)
Output:
1. Visibility levels
2. Edit semantics
3. Conflict handling
4. Owner-leaves rules
5. Audit log
The "personal copy" affordance: shared view becomes user's starting point; they "save as" to customize. Otherwise users feel locked out of personalization.
7. Default views per workspace / role
Workspace admins want to define defaults.
Default view configuration.
Patterns:
System defaults:
- "All" view (no filter)
- Recent / pinned
- Always available
- Can't be deleted
Workspace defaults:
- Admin sets "All open tickets" as default for everyone
- Users override per-session
- Used as starting point for new members
Role-based defaults:
- Different default for admins vs members
- Different for support vs engineering team
Per-resource defaults:
- Default view per database / table
- "Tasks" defaults to "My open"
- "Customers" defaults to "Active"
User override:
- User sets their own default
- Persists per workspace
- Falls back to workspace default if unset
Implementation:
User preferences:
- user_preferences table: default_view_id per resource_type per workspace
Workspace settings:
- workspace_settings: default_view_id per resource_type
Resolution:
- User pref > workspace default > system default
Onboarding:
- New user lands on workspace default (or system)
- Tour highlights views feature
Output:
1. Default-view hierarchy
2. User preference storage
3. Workspace admin UI
4. Role-based variants
5. Onboarding integration
The "smart default" rule: don't show "All" as default. Show "My open / In progress" for tasks; "Active customers" for customers. Filtered defaults match user intent better.
8. Performance — many views, large datasets
Saved views can multiply queries. Plan performance.
Optimize view performance.
Query patterns:
View count:
- "Show count next to view name (e.g., '12 open tickets')"
- Each view = COUNT query
- 10 views in sidebar = 10 COUNTs
- Combine into single query (subquery per view)
- Or: cache counts; refresh on data change
View load:
- Server-side filter + sort + paginate
- Don't load all data + filter client-side
- Index commonly-filtered fields
Real-time updates:
- WebSocket / SSE: when data changes, update relevant view counts
- Don't refetch all views; just invalidate affected
Stale data:
- Show last-updated timestamp on view
- Refresh button if user wants fresh
Pagination:
- 50-100 items per page typical
- Cursor pagination for large datasets
- See data-tables-sort-filter-bulk
Query plan:
- EXPLAIN ANALYZE common view queries
- Add indexes if seq-scanning
- Avoid: WHERE on computed columns without indexes
Caching:
- Per-view cache (Redis / in-memory)
- TTL: 30s for active views; longer for stale
- Invalidate on relevant data change
Anti-patterns:
- Loading all data + client-filtering (slow at 1000+ items)
- COUNT(*) on every view in sidebar (N+1)
- No indexing on filtered fields
Output:
1. Server-side filtering pattern
2. Index strategy per view
3. Count optimization
4. Caching strategy
5. Real-time invalidation
The N+1 view-count trap: 10 views in sidebar = 10 SELECT COUNT queries on every page load. Combine into single CTE / subquery; massive perf gain.
9. View as URL — shareable + deep-linkable
URLs make views shareable.
URL state for views.
Pattern:
/[workspace]/tasks/views/[view_id]
Or
/[workspace]/tasks?view=view_id
Or
/[workspace]/tasks?filters[status]=open&sort=priority
Tradeoffs:
By view ID (clean):
- Shorter URL
- View must exist + be accessible
- Renaming view doesn't break URL
By filter params (transparent):
- URL shows filters explicitly
- Shareable even if recipient doesn't have view saved
- Longer URLs
Hybrid (recommended):
- Saved views: by ID
- Ad-hoc filters: by params
- Switch URL when user saves
Sharing flow:
User clicks share:
- Get URL
- Copy to clipboard
- Send
Recipient clicks:
- If view exists + recipient has access → load
- If not (different workspace, deleted, no permission) → fallback to "All" + show error
Embedded views:
- Embed view in email / external doc
- Static snapshot at time of embed
- Or: live link (recipient must auth)
Mobile:
- Same URL pattern works
- Native app deep-link if available
Output:
1. URL pattern decision
2. View ID vs params
3. Share flow
4. Fallback handling
5. Mobile / embed support
The pattern most-loved by users: URL preserves whatever you're looking at. Reload doesn't lose state; bookmark works; share works.
10. Templates — pre-built views
Provide templates so users don't start from scratch.
Pre-built view templates.
System templates per resource type:
Tasks:
- "All tasks"
- "My open tasks"
- "Due this week"
- "Completed last 7 days"
- "Blocked"
Projects:
- "All projects"
- "Active projects"
- "Projects I own"
Customers:
- "All customers"
- "Active customers"
- "Recently signed up"
- "At risk"
Each template:
- Pre-set filters
- Pre-set sort
- Default visualization
- Editable copy if user wants to customize
Onboarding:
- Show templates during first-time
- "Add template view to your sidebar"
- Lower friction than building from scratch
User-shareable templates:
- Power user creates view → shares as workspace template
- Other users adopt as starting point
AI suggestions (advanced):
- LLM analyzes user's data patterns
- Suggests views: "You filter by 'urgent' often. Save as view?"
- Used by: Notion AI
Output:
1. System template library per resource
2. Template UI in onboarding
3. User-shared templates
4. AI suggestions (optional)
5. Template management
The "default view library" reduces blank-page problem. New user opens app, sees pre-built useful views, immediately productive.
What Done Looks Like
A v1 saved-views system for B2B SaaS in 2026:
- Schema with views table + filter / sort JSONB
- Personal + workspace-shared views
- Save / update / delete view UI
- Sidebar / tab navigation
- Faceted filter UI with pills
- URL state per view
- Defaults per user + workspace
- Multi-tenant isolation
- Performance (indexed; cached counts)
- Mobile-friendly UX
- System templates for new users
Add later when product is mature:
- Advanced query builder (AND / OR / nested)
- AI-suggested views
- View templates from community
- Pinning to sidebar
- Per-view notifications ("alert when count changes")
- View analytics (most-used views)
The mistake to avoid: view-state on every page load = COUNT explosion. Combine; cache.
The second mistake: shared views with no edit clarity. Confusing whose changes affect whom. Personal-first model is safer.
The third mistake: no URL state. Sharing / bookmarking broken.
See Also
- Data Tables: Sort, Filter, Pagination, Bulk Actions — filter mechanics (companion)
- Tags & Labels System — tag-based filters
- Search & Autocomplete Typeahead — adjacent search
- Workspace, Org & Tenant Switcher — workspace scope
- Multi-Tenancy — multi-tenant isolation
- Drag-and-Drop & Kanban Boards — kanban as view type
- Charts & Data Visualization — chart views
- Settings & Account Management Pages — adjacent settings
- Inline Editing Patterns — inline view editing
- Empty States, Loading & Error States — view empty states
- Real-Time Collaboration — collaborative views
- Roles & Permissions — view permissions
- Performance Optimization — perf
- VibeReference: Components — UI primitives
- VibeReference: Spreadsheet-Database Tools — Notion / Airtable inspiration
- VibeReference: Internal Tool Builders — Retool views