Introduction

The navigation section of any Nextcloud app is the left sidebar. It is basically composed of

  • a primary action button
  • a menu
  • a settings area

The primary action button and the settings area are optional.

New button

Introduction

A primary action button is just a stylised button located above the navigation part of your app. The goal is to have an homogeneity of design across all apps using this button.

Basic layout

Navigation with a new button
<div id="app-navigation">
    <div class="app-navigation-new">
        <button type="button" class="icon-add">
            Add user
        </button>
    </div>

    <!-- Your navigation here -->
    <!-- Your settings here -->

</div>

Rules

  • Stay simple, don’t use overcomplicated text in this button.
  • Avoid using sentences longer than one line.
  • Do not edit the styling of this button.
  • Only one button is allowed here.

App navigation menu

Introduction

The main navigation menu represents the main navigation of your app.

It needs to be:

  • Organised
  • Simple
  • Responsive

Nextcloud provides a very organized way of building menus. We implemented various essential functions and provide easy way of using them.

Basic layout

Navigation screenshot
<div id="app-navigation">

    <!-- Your primary action button here -->

    <ul>
        <li><a href="#">First level entry</a></li>
        <li>
            <a href="#">First level container</a>
            <ul>
                <li><a href="#">Second level entry</a></li>
                <li><a href="#">Second level entry</a></li>
            </ul>
        </li>
    </ul>

    <!-- Your settings here -->

</div>

Basic rules

  • You can not change the default padding of the navigation elements.
  • We encourage you to add icons on every top-level item of your navigation for accessibility.
  • Do not override the default structure and/or CSS. Everything has been carefully tuned.

Utils: menu, counter & buttons

Each entry is allowed to have a counter and/or a button for user interaction.

  • The app-navigation-entry-utils snippet need to be placed right next to the main link of your entry.
  • Maximum two items are allowed into the utils section. You can have:
  • You can’t have more than two buttons, if you need more, you need to add a menu.
  • The order of the button and the counter are not interchangeable. You need to put the counter before the menu.
<div class="app-navigation-entry-utils">
    <ul>
        <li class="app-navigation-entry-utils-counter">1</li>
        <li class="app-navigation-entry-utils-menu-button">
            <button></button>
        </li>
    </ul>
</div>

Counter

If you need to add a counter to your menu entry, you can simply use this structure. Do not change the alignment of the text. If you’re using

Navigation entry with counter
<li class="app-navigation-entry-utils-counter">1</li>

The counter should be limited to 999 and turn to 999+ if any higher number is given. If AngularJS is used the following filter can be used to get the correct behavior:

app.filter('counterFormatter', function () {
    'use strict';
    return function (count) {
        if (count > 999) {
            return '999+';
        }
        return count;
    };
});

Use it like this:

<li class="app-navigation-entry-utils-counter">{{ count | counterFormatter }}</li>

Highlighted counter

The counter can also be highlighted to attract some focus, e.g. for unread chat messages

Navigation entry with highlighted counter
<li class="app-navigation-entry-utils-counter highlighted"><span>99+</span></li>

Buttons

The same way we display the menu three-dot-icon button, you’re allowed to use up to 2 buttons in a single entry.

  • The icon class goes directly on the button element.
  • If no class is set, the three-dot-icon will be used by default
Navigation entry with counter
<div class="app-navigation-entry-utils">
    <ul>
        <li class="app-navigation-entry-utils-menu-button">
            <button class="icon-edit"></button>
        </li>
        <li class="app-navigation-entry-utils-menu-button">
            <button class="icon-delete"></button>
        </li>
    </ul>
</div>

Drag and drop

The class which should be applied to a first level element li that hosts or can host a second level is drag-and-drop. This will cause the hovered entry to slide down giving a visual hint that it can accept the dragged element. In case of jQuery UI’s droppable feature, the hoverClass option should be set to the drag-and-drop class.

<div id="app-navigation">
    <ul>
        <li><a href="#">First level entry</a></li>
        <li class="drag-and-drop">
            <a href="#" class="icon-folder">Folder name</a>
            <ul>
                <li><a href="#">Folder contents</a></li>
                <li><a href="#">Folder contents</a></li>
            </ul>
        </li>
    </ul>
</div>

Collapsible entry

By default, all sub-entries are shown. This behavior can be changed by creating a collapsible menu. This way, the menu will be hidden and an arrow will be added in in front of it (replacing the icon if any).

The opening of the menu is activated and animated by the class open on the main li.

  • You can not have a collapsible menu on a sub-item, this can only exist on a top-level element.
  • You can set the open class by default if you want.
  • Do not use the collapsible menu if your element does not have sub-items.
  • You still need to use JS to handle the click event.

Important

  • If your top-level link is only used as a header, the entire a needs to be used to toggle the open class.
  • If your top-level link is used to redirect the user or to trigger something else, you need to add the collapsible button and use it as the open class toggle trigger.
Collapsible navigation entry
<li class="collapsible open">

    <!-- This is optional -->
    <button class="collapse"></button>

    <a href="#" class="icon-folder">Folder collapsed menu</a>
    <ul>
        <li><a href="#">Simple entry</a></li>
        <li><a href="#">Simple entry</a></li>
        <li><a href="#">Simple entry</a></li>
        <li>
            <a class="icon-folder" href="#">Simple folder</a>
        </li>
    </ul>
</li>

Entry bullet

Every entry can have a colored marker in front of it. We call it a bullet.

  • You can not combine an icon with a bullet.
  • You need to use the CSS to define the bullet color.
Navigation entry with bullet
<li>
    <div class="app-navigation-entry-bullet"></div>
    <a href="#">Entry with bullet</a>
</li>

Undo entry

  • Undo entries can be used on any level you want.
  • When an entry is deleted, please use the usual 7 seconds delay feedback before final deletion.
  • Please use the sentence Deleted XXXX as the feedback message.
  • You need to use the deleted class to trigger the animated hide/show of the undo entry.
Navigation entry with undo action
<li class="deleted">
    <a href="#" class="hidden">Important entry</a>
    <div class="app-navigation-entry-utils">
        <ul>
            <li class="app-navigation-entry-utils-menu-button">
                <button class="icon-delete"></button>
            </li>
        </ul>
    </div>
    <div class="app-navigation-entry-deleted">
        <div class="app-navigation-entry-deleted-description">Deleted important entry</div>
        <button class="app-navigation-entry-deleted-button icon-history" title="Undo"></button>
    </div>
</li>

Edit entry

  • Editable entries can be used on any level you want.
  • You can replace the form by a div if you wish to do your request with JS.
  • You need to use the editing class to trigger the animated hide/show of the input.
  • You’re allowed to use only one submit input. It must be the validation button.
  • The input must have the same value as the entry link text.
Editable navigation entry
<li class="editing">
    <a href="#" class="icon-folder">Folder entry</a>
    <div class="app-navigation-entry-utils">
        <ul>
            <li class="app-navigation-entry-utils-menu-button">
                <button class="icon-rename"></button>
            </li>
        </ul>
    </div>
    <div class="app-navigation-entry-edit">
        <form>
            <input type="text" value="Folder entry">
            <input type="submit" value="" class="icon-close">
            <input type="submit" value="" class="icon-checkmark">
        </form>
    </div>
</li>

Pinned entry

Every top-level entry can be pinned at the bottom.

  • All the pinned entries can be mixed between non-pinned entries.
  • All the pinned entries must have the pinned class.
  • The first pinned entry must also have the first-pinned class.
Pinned navigation entries
<ul>
    <li><a href="#">Non-pinned entry</a></li>
    <li><a href="#">Non-pinned entry</a></li>
    <li class="pinned first-pinned">
        <a href="#">Pinned entry</a>
    </li>
    <li class="pinned"><a href="#">Pinned entry</a></li>
    <li><a href="#">Non-pinned entry</a></li>
    <li><a href="#">Non-pinned entry</a></li>
    <li class="pinned"><a href="#">Pinned entry</a></li>
    <li class="pinned"><a href="#">Pinned entry</a></li>
</ul>

Various information

  • You can add the icon-loading-small class to any li element to set it in a loading state.
  • Every element as a min-height of 44px as that is the minimum recommended touch target. It also helps with clickability and separation on desktop environments.

Settings

Introduction

To create a settings area create a div with the id app-settings inside the app-navigation div.

  • The data attribute data-apps-slide-toggle slides up a target area using a jQuery selector and hides the area if the user clicks outside of it.
  • Max height of the settings area is 300px. Do not change that.
  • Keep it clear, organized and simple.

Basic layout

Settings
<div id="app-navigation">

    <!-- Your primary action button here -->
    <!-- Your navigation here -->

    <div id="app-settings">
        <div id="app-settings-header">
            <button class="settings-button"
                    data-apps-slide-toggle="#app-settings-content">
                Settings
            </button>
        </div>
        <div id="app-settings-content">
            <!-- Your settings content here -->
        </div>
    </div>
</div>