Building an AEM Admin interface, also known as a console, is not a trivial task at first glance. This post describes how to create an admin console for AEM 6.2 to list, sort, create, and delete centralized data.

Source Code: available here

What are we building?

A method to create content in centralized location that can be shared across many different sites and locales. In our case, we will be creating calendar entries to convey data center uptime for our Pug Ranch's Live Video Feed.

Why are we building this?

Typically components get localized across many locales. This creates live copies of data across our Oak repository. Our data does not need to be localized because our data center uptime covers all locales. By centralizing the data, we remove it from the localization process and remove unnecessary localized nodes.

High Level Design

The design can be broken down into three high-level pieces.

  1. Admin Console Menu Item
  2. Admin Console Content, Components, and Clientlibs
  3. Servlet to handle creating and editing of data

Creating Console Menu Item

Below is the structure of our menu item. It's important to know that we need to overlay the existing libs/cq/core/content/nav/tools/operations nodes. 


  • The id corresponds to the consoleId (defined later)
  • Icon should be labeled with a corresponding Coral UI icon name.
  • Href should point to the location of your console (defined later)

The full uptime menu item JCR node description:

Once you have made the above nodes, you will be able navigate to AEM (1) Tools (2) Operations (3) and Data Center Uptime (4).

Admin Console Content, Components, and Clientlibs

The next piece we need to build is the actual console and the components within the console. This is the most complex piece, so let's break this down further:

  1. Content
    1. Admin - This is the main view to list our entries. It's defined by a .content.xml
    2. createEntry - This is the create view. It's is also defined by a .content.xml
    3. editEntry - This is the edit view. Surprise, also defined by a .content.xml
  2. Components
    1. Datasource - This is a JSP that provides data (our entries) to our list.
    2. Uptimeentry - As we iterate through our list of entries, this defines the view for each entry.
    3. Uptimeform - This handles both create and edit operations.
  3. Clientlibs - This single JS will provide:
    1. A Granite Delete Confirmation Dialog
    2. AJAX Call to delete an entry. It leverages the SlingPostServlet for simplicity.
    3. Pass a path parameter to our editEntry page.

Content / Admin

This file is huge, so go take a look here. If you've ever worked with ui.content this file should feel familiar as we're declaring almost all of our layout in XML.


  • consoleId should match our Menu Item "id" we created above.
  • The clientlibs node allows us to include clientlibs. In our case, Coral 3 and our own uptime clientlib.
  • Our list and datasource are what pull in the list of entries. The datasource component will be covered later.
  • itemResourceType is used to display each entry. It will also be covered later.
  • Within actions, the selection nodes (delete, edit) are used when selecting an item in the list. 
  • Within actions, the secondary action always shows and is used for create. It's uses a plain href property since no params need to be passed.

Content / createEntry & Content / editEntry

You can find createEntry here. You can find editEntry here.


  • These files are identical with the exception of one line: the text property of the title node.
  • The content node that has a property of granite/ui/components/coral/foundation/form. This has a property of action that submits to our servlet, /bin/pugranch/uptimeEntry which will be defined later.
  • The node uptimeform has a sling:resourceType of pugranch/admin/ext/uptime/components/uptimeform which we will build later using Sightly, Coral, and HTML.

Components / datasource

This component is not a typical front-end style component. We only need the folder and the JSP. You can find the source here.


  • The goal of the data source is to find resources, and build an iterable list of those resources.
  • It's important to know that for any value you want exposed, you must add that to the ValueMap of the child. You cannot rely on typical resource methods I.E. resource.getPath, resource.getName if you do not include those values in the datasource.
  • Working in JSP is not fun, but it's a bit more direct than Sightly + Java.

Components / uptimeentry

This component takes the entries from our data source and uses the values provided to display each entry. Source here.


  • Again, it's important to know that the only values we have available to us are coming directly from the datasource. Typical methods you would use to get values from a resource are not available here.
  • Note data-id and data-path. Our Javascript will be acting on these properties as needed.
  • A lot of the Coral UI classes and naming conventions are using 6.2 conventions. Your mileage may very.

Components / uptimeform

This component is the inside of our createEntry and editEntry form. In the case of editEntry, we have a use class to provide additional logic to pull in information. Source here.


  • We're again using some Coral Kung Fu to create our form elements.
  • We are using a Sling convention, :redirect to provide our servlet with the location we want to be redirected to upon successful entry creation.
  • Remember, our form action and method were declared in our content nodes, so the do not need to be declared here.
  • The step value (.01) seems to have a bug with rouding, so we fix this in our servlet.

Clientlibs / pugranch.uptime

The client library only contains on Javascript file. It's relatively straight-forward with only four functions. The source is here.

Functions to Note:

  • Register the buttons during a selection change.
  • Toggle the Delete Dialog when "Delete" is clicked.
  • Handle the Confirm Deletion - Uses an AJAX call and Sling Post Servlet conventions to delete the node.
  • Handle the "Edit" action - Passes the path to the editEntry.


The Uptime Entry Servlet Performs the functions listed below. Source code here.

  1. Create an uptimeCalendar sling:OrderedFolder if needed.
  2. Create or update an uptime entry. The naming convention is YEAR-Month.
  3. Redirect to the location based on :redirect.


In the end, you should have something that resembles the screenshot below. It can seem daunting at first, but if you walk through each piece, creating an admin console can be very similar to a lot of core AEM concepts.