Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Fixed Bars Laravel Package

stephenlake/nova-fixed-bars

A Laravel Nova extension that keeps the header and navigation bars fixed while scrolling, improving usability in long resource and dashboard views. Simple to install and configure, it delivers a cleaner, more consistent admin experience with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm you have Nova before anything else. This package is a small CSS/JS overlay for Nova's compiled front-end. It requires the private nova.laravel.com Composer repo and auth.json credentials — without Nova installed, the package does nothing. Check the laravel/nova constraint in its composer.json first; a release from January 2020 against Nova 4.x/5.x is the primary adoption risk.

Install:

composer require stephenlake/nova-fixed-bars

No vendor:publish is required in the normal path. The service provider is auto-discovered via extra.laravel.providers. If package discovery is disabled in your app, register StephenLake\NovaFixedBars\NovaFixedBarsServiceProvider in config/app.php.

Read these three things, in this order:

  1. vendor/stephenlake/nova-fixed-bars/src/ — the service provider. Find the Nova::style(...) (and any Nova::script(...)) call. That single line is the integration.
  2. The stylesheet it registers. It is small — read it end to end. Everything else in the package is packaging.
  3. composer.json — the Nova version constraint, and the NOASSERTION license, which is a decision input, not a footnote.

First use case — the ten-minute validation spike. On a throwaway branch, create a resource with 40+ fields (or seed one with 50 related records so the edit form scrolls). Open the create/edit screen and scroll to the bottom. Verify:

  • No 404s in the console for the registered asset.
  • The action bar — Create, Save, Delete, and any resource tool buttons — is still reachable at the bottom of a long form.
  • Form content is not hidden underneath the pinned bar (check the last field and validation error messages).
  • On /nova/resources/users detail and index screens, nothing overlaps.
  • At 375px the mobile drawer still opens and the bar does not cover the nav.

That answers most of the adoption question before you commit to anything.

The realistic default is to lift the CSS. With a last release of January 2020, zero dependents, and a NOASSERTION license, treat the package as a reference implementation. Read their stylesheet, write your own ~40–60 lines, and register it yourself in NovaServiceProvider::boot():

use Laravel\Nova\Nova;

public function boot()
{
    parent::boot();

    Nova::style('fixed-bars', __DIR__.'/../resources/css/fixed-bars.css');
}

Implementation Patterns

1. Comment the source in the file you copy. When you lift the CSS, annotate it:

/* Adapted from stephenlake/nova-fixed-bars @ <tag>, <date>.
   Nova class names are compiled and not a public API — re-verify on every Nova upgrade. */

That note is what makes the file debuggable in six months and during a Nova bump. It also keeps the licensing question visible to whoever reads it next.

2. Gate the style behind config so you can kill it in one deploy. Never ship a visual override you cannot disable without a revert:

// config/nova.php
'fixed_bars' => env('NOVA_FIXED_BARS', true),
if (config('nova.fixed_bars')) {
    Nova::style('fixed-bars', __DIR__.'/../resources/css/fixed-bars.css');
}

3. Tokenize the bar height; never hardcode pixels in two places. Nova's layout math assumes the action bar sits in normal document flow. Once you take it out of flow, you must compensate the content that used to sit below it:

:root { --nova-action-bar-height: 62px; }

body.nova-fixed-bars .content {
    padding-bottom: var(--nova-action-bar-height);
}

body.nova-fixed-bars [data-testid="resource-actions"],
body.nova-fixed-bars .action-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--colors-white, #fff);
    border-top: 1px solid var(--colors-gray-200, #e5e7eb);
}

Scope every rule under a body class you control — one switch, contained specificity.

4. Prefer a bottom-pinned bar over a top-pinned one. Nova's top area already carries the resource title, breadcrumbs, and search. Pinning more chrome up top eats vertical space that tables and forms need, and it collides with the existing header stacking. A bottom bar mirrors the mobile-friendly pattern users already expect and avoids the whole top-header overlap class of bugs.

5. Let Nova own small widths. Nova's mobile layout already reflows action buttons into a different arrangement under ~1024px. Explicitly scope your fixed rules to desktop widths:

@media (max-width: 1024px) {
    body.nova-fixed-bars .action-bar { position: static; }
    body.nova-fixed-bars .content { padding-bottom: 0; }
}

This is where nearly every layout regression shows up. Check it every time.

6. Do not compute offsets with JS. Nova is a Vue SPA — navigating from an index to an edit screen swaps content without a full page load, so any offset measured onload goes stale the moment the user clicks through. Use calc() and CSS custom properties so the layout is correct on every route change for free.

7. Register per panel, not globally. If you run multiple Nova panels, register only where it helps — typically the internal ops console:

use Laravel\Nova\Nova;
use Laravel\Nova\NovaApplication;

Nova::whenServing(function (NovaApplication $nova) {
    $nova->style('fixed-bars', __DIR__.'/../resources/css/fixed-bars.css');
}, 'ops');

8. Make it work with custom tools, not just resources. Custom Nova tools and cards render their own Vue components. If a tool has its own action row, either adopt the same --nova-action-bar-height token in that component or explicitly opt out with a class (<div class="tool-no-fixed-bar">) so the global rule doesn't double up.

9. Inherit Nova's CSS variables for colors and borders. A hardcoded white bar with a #ddd border looks wrong the moment a theme or dark mode lands. Using Nova's own tokens (--colors-white, --colors-gray-200) keeps you consistent without maintenance.

10. Screenshot-diff every screen class, every change. Nova moves markup between minor versions. A minimal loop:

  • Branch, apply the CSS, build assets (npm run build if you Mix/Vite your Nova assets).
  • Screenshot at 375 / 768 / 1024 / 1440 px on: dashboard, resource index, resource detail, create/edit, a modal, and a screen with an already-sticky toolbar.
  • Diff against main. PR with before/after images and a line stating the Nova version you validated against.

Gotchas and Tips

Nova's class names are not a public API. Selectors like .sidebar, .content, .action-bar, and [data-testid="..."] are compiled implementation detail. Assume every Nova upgrade needs devtools re-inspection and selector retuning. Budget roughly half a day per major version.

"Doesn't stay fixed" almost always means an ancestor. When the bar won't pin, check three things in order:

  1. Your rule appears in computed styles at all (asset loaded, selector matching).
  2. Nova's own rule is not winning on specificity.
  3. No ancestor has overflow: hidden, overflow: auto, or a transform/filter/perspective. Each creates a new containing block and silently breaks position: fixed. This accounts for a surprising share of "the CSS is right but nothing happens" — and Nova's layout wrappers are a common culprit.

z-index is a stack of competing contexts. Modals, dropdowns, toasts, the search overlay, and the mobile drawer each have their own stacking. A value too high covers modal backdrops; too low and dropdowns open behind the bar. Use the lowest value that pins the bar above page content, then explicitly verify: open a modal, open a resource action dropdown, trigger a toast, and open the global search after every change.

!important compounds fast. You will need some — you are overriding shipped CSS — but confine it to specific properties (position, bottom, padding-bottom), never whole rules. If specificity escalates, add a scoping class to a wrapper instead of another !important.

Fixed chrome silently breaks keyboard focus order and zoom. Tabbing through a long form with a pinned action bar can jump focus out of visual order; 200% browser zoom can push the bar over form fields. Test both before shipping. No upstream maintainer is watching for this — it is on you.

Print and PDF exports lose the bar (or clip the page). Always add an escape hatch:

@media print {
    body.nova-fixed-bars .action-bar { position: static !important; }
    body.nova-fixed-bars .content { padding-bottom: 0 !important; }
}

Never patch anything under vendor/laravel/nova. It is overwritten on every install and update. All work goes through Nova::style() in your provider or a published asset under your resources/.

vendor:publish overwrites your edits. If the package ships publishable assets and you edit the published copy, you have silently forked it. Commit the file, then remove the Composer dependency so nobody re-publishes over you. If you do keep the package, pin the exact version:

"stephenlake/nova-fixed-bars": "1.1.4"

Not a caret range — a 2020-era front-end overlay should never auto-update.

Asset caching hides your changes. After editing CSS or upgrading the package, run php artisan nova:publish, then hard-refresh. Version the asset name (Nova::style('fixed-bars-v2', ...)) so browsers pick up the new file without a cache-bust dance.

There is no changelog and no release notes. Read the git tag diff directly before bumping. An unexplained future tag should never land in your admin UI automatically.

License is NOASSERTION. For anything commercial or client-delivered, get legal to classify or waive it in writing before this lands in a shipped product. Reading their CSS and writing your own file is the cleanest route around the question, and at this size of implementation it is often less work than the legal conversation.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource