Category Archives: Lightning Components

Implementing a “Deck of Cards” Layout in Salesforce Lightning Components

A “Deck of Cards” layout is where multiple “cards” of information are stacked on top of each other. Only one card is visible at any given time. Essentially, this is similar to a tab panel, but it gives you the flexibility to design your own ux for swapping the cards in and out.

I’ve implemented this as a single component that can be easily invoked from an app, or other cmp file:

<aura:application >
    <c:cardLayout aura:Id="myCardLayout">
        <div class="card">
            This is card 1
        </div>
        <div class="card">
            This is card 2
        </div>
        <div class="card">
            This is card 3
        </div>
    </c:cardLayout>
    
    <div style="position:fixed; bottom:10px; border: 1px solid black">
    <ui:button 
        label="Show Card 1"
        press="{!c.showCard1}" />
    <ui:button 
        label="Show Card 2"
        press="{!c.showCard2}" />
    <ui:button 
        label="Show Card 3"
        press="{!c.showCard3}" />
   </div>
</aura:application>

The corresponding controller simply calls a public method on the cardLayout component:

({
  showCard1 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(0);
  },
  showCard2 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(1);
  },
  showCard3 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(2);
  }
})

Pretty simple, right?

Now, let’s take a look at the cardLayout component. It’s relatively straightforward:

<aura:component>
   
   <aura:method 
                name="setActiveCard" 
                action="{!c.doSetActiveCard}" 
                access="global" />
   
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
 
 
   <aura:attribute 
                   name="activeCard" 
                   type="String" 
                   default="0" access="global" />
	
   <div class="cardContainer">
     {!v.body}
   </div>
</aura:component>

The controller logic simply applies or removes a custom css class:

({
    doSetActiveCard : function(component, event, helper) {
        var currentActiveCard = component.get('v.activeCard');
        
        var params = event.getParam('arguments');
        var newCardId = params[0];
        
        var oldCard = component.get('v.body')[currentActiveCard];
        $A.util.removeClass(oldCard,"card--on");
        
        var newCard = component.get('v.body')[newCardId];
        
        $A.util.addClass(newCard,"card--on");
        component.set('v.activeCard',newCardId);
        
    },
    
    doInit: function(component, event, helper) {
        component.setActiveCard(component.get('v.activeCard'));
    }
})

And the CSS…well, it just defines a couple of classes for defining card visibility along with a “fade” animation

.THIS {
    height: 100%;
}

.THIS.cardContainer {
  position: relative;
  display: flex;
  flex: 1 0 auto;
  height: 100%;
}

.THIS .card {
  transition: 0.2s opacity linear; 
  visibility: visible;
  overflow: auto;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  position: absolute !important;
  opacity: 0;          
  visibility: hidden;
}

.THIS .card--on {
  opacity: 1;
  visibility: visible;
}

I’ll be discussing this technique, as well as other solutions at my presentation on “Lightning Component Best Practices” at the Dreamforce conference in Thursday, Oct 6. See you there!