<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fyodor</title>
    <description>The latest articles on DEV Community by Fyodor (@kroxiksut).</description>
    <link>https://dev.to/kroxiksut</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4023932%2F23bb9341-ba1c-4954-9262-0479ad477c7e.jpg</url>
      <title>DEV Community: Fyodor</title>
      <link>https://dev.to/kroxiksut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kroxiksut"/>
    <language>en</language>
    <item>
      <title>I Needed Collapsible App Groups in Django Admin, So I Built a Package</title>
      <dc:creator>Fyodor</dc:creator>
      <pubDate>Fri, 10 Jul 2026 12:59:01 +0000</pubDate>
      <link>https://dev.to/kroxiksut/i-needed-collapsible-app-groups-in-django-admin-so-i-built-a-package-45nm</link>
      <guid>https://dev.to/kroxiksut/i-needed-collapsible-app-groups-in-django-admin-so-i-built-a-package-45nm</guid>
      <description>&lt;p&gt;The built-in Django Admin works well, especially while a project is still small. But as a project grows, the sidebar gradually fills up with more applications and models: users, permissions, products, orders, reports, integrations, internal reference data, and many other sections.&lt;/p&gt;

&lt;p&gt;Most of these sections are not used all the time. In one project, an administrator may spend most of the day working with orders and customers, while dozens of rarely used models remain visible in the sidebar.&lt;/p&gt;

&lt;p&gt;At some point, I wanted to add a very simple feature to the standard Django Admin sidebar: click an arrow next to an application name and collapse its list of models.&lt;/p&gt;

&lt;p&gt;It seemed like a small interface improvement. However, I could not find a lightweight package that added exactly this behavior to the standard Django Admin without replacing it with a custom theme.&lt;/p&gt;

&lt;p&gt;So I built django-admin-collapse-apps.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What the package does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The package adds a toggle next to every application group heading. When the toggle is clicked, the model list is hidden and only the application name remains visible.&lt;/p&gt;

&lt;p&gt;The selected state is stored in a cookie. After refreshing the page or returning to the admin later, previously collapsed groups remain collapsed. When the user expands all application groups again, the cookie is removed.&lt;/p&gt;

&lt;p&gt;The package does not replace Django’s standard navigation, change the order of applications or models, or interfere with permission checks. It only adds collapsible behavior to the application groups already generated by Django.&lt;/p&gt;

&lt;p&gt;This is what the sidebar looks like before collapsing groups:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy4h3k2hpx70vzu93fr0b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy4h3k2hpx70vzu93fr0b.png" alt="Application groups in their default expanded state." width="552" height="1618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is what it looks like after:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0uwlw0ckxpuf8rkik4p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0uwlw0ckxpuf8rkik4p.jpg" alt="Collapsed application groups in the standard Django Admin sidebar." width="552" height="1076"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The package is available on PyPI and can be installed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m pip install django-admin-collapse-apps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installation, add it to INSTALLED_APPS before django.contrib.admin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    "django_admin_collapse_apps",
    "django.contrib.admin",
    # Other project applications
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all that is required for the basic setup. After restarting the project, collapse toggles will appear next to all application groups in the standard Django Admin sidebar.&lt;/p&gt;

&lt;p&gt;The position before django.contrib.admin is important because the package adds its own templates and static files on top of the standard admin templates.&lt;/p&gt;

&lt;p&gt;Restricting collapse toggles to selected applications&lt;/p&gt;

&lt;p&gt;By default, toggles are added to every application group. For most projects, this is the simplest behavior because each user can decide which sections should remain visible.&lt;/p&gt;

&lt;p&gt;In some cases, however, part of the menu should always stay expanded. For example, you may want to allow collapsing only for rarely used internal applications.&lt;/p&gt;

&lt;p&gt;To do this, add a list of Django app labels to the project settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ADMIN_COLLAPSE_APPS = [
    "auth",
    "reports",
    "integrations",
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, toggles will only appear for the listed applications. All other groups will continue to behave like regular Django Admin navigation items.&lt;/p&gt;

&lt;p&gt;These values are Django app labels, not application display names. In most projects, the label matches the application name, but in more complex configurations it is better to check the application’s AppConfig.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why cookies instead of localStorage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first, localStorage seemed like the obvious choice for storing the collapsed state. This is a purely client-side feature, so using browser storage would have been reasonable.&lt;/p&gt;

&lt;p&gt;However, cookies have one practical advantage here: they can be scoped to a particular admin path and separated between multiple administrative interfaces hosted on the same domain.&lt;/p&gt;

&lt;p&gt;The cookie stores only the app labels of collapsed applications. It does not contain user data, model content, or any other information from the admin interface.&lt;/p&gt;

&lt;p&gt;A simplified value looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;catalog,orders,reports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the user expands the final collapsed group, the cookie is no longer needed and is deleted.&lt;/p&gt;

&lt;p&gt;If several independent admin interfaces are hosted on the same domain, each one can use its own namespace:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ADMIN_COLLAPSE_APPS_COOKIE_NAMESPACE = "backoffice"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This prevents the menu state from one admin interface from being accidentally applied to another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Working with Django Admin search&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The standard Django Admin sidebar includes a search field for filtering applications and models.&lt;/p&gt;

&lt;p&gt;This created a less obvious edge case: what should happen when a matching model belongs to a collapsed application group?&lt;/p&gt;

&lt;p&gt;Without additional handling, Django would find the model, but the user would not see it because its group would still be collapsed. To avoid this, matching application groups are temporarily expanded while the search field contains text.&lt;/p&gt;

&lt;p&gt;When the search field is cleared, the interface returns to the state selected by the user before the search started. Searching does not overwrite the saved collapse state or permanently expand any applications.&lt;/p&gt;

&lt;p&gt;It is a small detail, but without it the collapse feature would conflict with one of the useful built-in Django Admin tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I did not completely replace the navigation template&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most direct way to implement this feature would be to copy the standard Django Admin navigation template and modify it.&lt;/p&gt;

&lt;p&gt;That approach works, but it leaves the project with its own copy of a relatively large Django template. After every Django update, the copied template has to be compared with the new standard version.&lt;/p&gt;

&lt;p&gt;Django may add markup changes, accessibility improvements, or new features that do not automatically appear in the copied template.&lt;/p&gt;

&lt;p&gt;For this reason, the package tries to interfere with the standard admin as little as possible. Django still generates the applications, models, links, ordering, and permissions. The package’s JavaScript only finds the existing groups in the DOM and adds collapse buttons.&lt;/p&gt;

&lt;p&gt;This approach still depends on the structure of the standard Django Admin, but the amount of overridden behavior is much smaller than it would be with a complete template replacement.&lt;/p&gt;

&lt;p&gt;If the expected markup is not present on a page, the script simply stops. The admin remains available and continues working without the collapse feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The admin should still work without JavaScript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The feature is implemented as progressive enhancement. JavaScript improves the interface, but it is not required to access administrative sections.&lt;/p&gt;

&lt;p&gt;If the script fails to load, is blocked, or JavaScript is disabled in the browser, every application group remains expanded. Links to models continue working, and the user does not lose access to any admin functionality.&lt;/p&gt;

&lt;p&gt;In the worst case, Django Admin simply returns to its normal default behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The toggles are implemented as real  elements rather than clickable div or span elements. This makes them keyboard accessible and allows them to receive focus correctly.&lt;/p&gt;


&lt;p&gt;When the state changes, the package updates the aria-expanded attribute. Each button is also connected to its model list through aria-controls.&lt;/p&gt;

&lt;p&gt;The styles take the prefers-reduced-motion setting and forced-colors mode into account. This does not replace a full accessibility audit of Django Admin, but it helps ensure that the package does not make the standard interface less accessible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customizing the arrows and appearance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, the package uses simple Unicode symbols: a downward arrow for an expanded group and a right-pointing arrow for a collapsed group.&lt;/p&gt;

&lt;p&gt;This avoids adding an icon library, SVG sprite, or any external dependency. The symbols can still be replaced through CSS variables:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:root {&lt;br&gt;
    --django-admin-collapse-apps-toggle-expanded-symbol: "▼";&lt;br&gt;
    --django-admin-collapse-apps-toggle-collapsed-symbol: "▶";&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;CSS can also be used to change the button color, symbol size, spacing, and focus styling.&lt;/p&gt;

&lt;p&gt;The package uses colors from the standard Django Admin interface and works with both its light and dark modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the package deliberately does not do&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;django-admin-collapse-apps is intentionally a small enhancement. It does not replace Django Admin with a custom theme, rebuild the menu, reorder models, add a separate user settings system, or store preferences in the database.&lt;/p&gt;

&lt;p&gt;It does not use jQuery, third-party JavaScript libraries, a CDN, or external resources. The entire feature is implemented with a small amount of JavaScript and CSS.&lt;/p&gt;

&lt;p&gt;This also defines the main limitation of the package: it is designed primarily for the standard Django Admin interface. Themes that completely replace the sidebar may use different markup and usually provide their own navigation features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why publish a package for one small feature?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Collapsible application groups can be implemented directly inside a single project. Installing another dependency is not strictly necessary.&lt;/p&gt;

&lt;p&gt;However, when the same improvement is needed in several projects, it becomes necessary to copy templates, JavaScript, styles, cookie settings, and fixes for various edge cases.&lt;/p&gt;

&lt;p&gt;At that point, maintaining one small package is easier than maintaining several slightly different local implementations.&lt;/p&gt;

&lt;p&gt;Publishing the feature as a separate project also encourages more careful work on compatibility, documentation, tests, and behavior across different Django versions.&lt;/p&gt;

&lt;p&gt;The result is a small package without any attempt to become a new admin platform. It does one thing: it allows users to hide application groups they do not currently need.&lt;/p&gt;

&lt;p&gt;The source code is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kroxiksut/django-admin-collapse-apps" rel="noopener noreferrer"&gt;https://github.com/kroxiksut/django-admin-collapse-apps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The package is available on PyPI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/django-admin-collapse-apps/" rel="noopener noreferrer"&gt;https://pypi.org/project/django-admin-collapse-apps/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback is welcome, especially from developers using the package in large projects with heavily extended Django Admin interfaces. If you find a bug or an unusual edge case, feel free to open an issue on GitHub.&lt;/p&gt;


</description>
      <category>webdev</category>
      <category>django</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
