The Top Shelf is a great way to promote new content from your app. When a user hovers on your app icon, the Top Shelf will be displayed. With tvOS 13, a new fullscreen Top Shelf is introduced. This Top Shelf allows you to display a picture or a video, instead of a collection with static images.

The Top Shelf is only visible for apps that are in the first row of apps on the dashboard. Users can only set 5 apps for each row, so your Top Shelf may not visible if your user doesn’t put your app in the first row of apps.

The fullscreen Top Shelf on tvOS 13.

Adding a Top Shelf extension

To make use of the Top Shelf, you must add a Top Shelf extension to your project. So to start, add a new target to your project, which is the “TV Top Shelf Extension”. When adding the extension, be sure that ‘Embed in Application’ is set to the correct application where the Top Shelf belongs to.

Add the new target ‘TV Top Shelf Extension’ to your project using Xcode.

When the Top Shelf extension is added, your project folder contains a new folder where the ContentProvider.swift file is located. In this file, you can build up the Top Shelf.

When you open the file, you will see the function loadTopShelfContent is overridden. In this function, you’re able to fetch data and return the data using the completion handler.

By default, the loadTopShelfContent function sets the completionHandler to nil, which means no Top Shelf is available.

ContentProvider.swift with default implementation

import TVServices

class ContentProvider: TVTopShelfContentProvider {

    override func loadTopShelfContent(completionHandler: @escaping (TVTopShelfContent?) -> Void) {
        // Fetch content and call completionHandler

Build a fullscreen Top Shelf

Now that we have added the Top Shelf Extension to our project, we can start building the Top Shelf.

Remove the completionHandler from the loadTopShelfContent function and add the following code inside the function:

let item = TVTopShelfCarouselItem(identifier: "topshelf-blog")
item.title = "Top Shelf blogpost" 
item.contextTitle = "Featured blogs"

In the code above, we create a TVTopShelfCarouselItem, which contains a unique identifier. Also, the title and contextTitle for the item can be set to enrich the information.

Next, add the code to the function:

item.setImageURL(URL(string: ""), for: .screenScale1x)
item.setImageURL(URL(string: ""), for: .screenScale2x)

In this code, there will be a placeholder image set for your video. For the time that your video is buffering, the placeholder image is visible. If no video is set, the image will be visible instead of a video. You can also set the screen scale for 2x, which is needed to display a high-quality image for 4K televisions.

Next, we are going to add the action buttons. The fullscreen Top Shelf supports two action buttons, which are the ‘play’ and the ‘more info’ button. If one of the action buttons is not set in code, the button is not visible.

Add this code to add the action buttons:

item.displayAction = TVTopShelfAction(url:URL(string: "zonnevelddev://topshelf-blogpost")!)
item.playAction = TVTopShelfAction(url: URL(string: "zonnevelddev://topshelf-blogpost/play")!)

In the example above, the action URL in the TVTopShelfAction is a deeplink. When your user clicks on one of the buttons, the tvOS app will be opened with this deeplink.

Everything is set, except for the video URL. The video URL can be set using this code:

item.previewVideoURL = URL(string: "")

We did set all the information needed for the TVTopShelfCarouselItem. We can put this in the TVTopShelfCarouselContent.

let carouselContent = TVTopShelfCarouselContent(style: .actions, items: [item])

The TVTopShelfCarouselContent contains an array of items. In the code example above, only one item is set, but you can create multiple items and allow the user to swipe to the left and right to watch more videos.

Finish with the completion handler where you return the TVTopShelfCarouselContent object.

The code above is using static data. If you first need to fetch the data from the backend, it is possible that the network call fails, for example, because of a network error. In that case, you need to set the completionHandler(nil) to disable the Top Shelf.

Interact with the fullscreen Top Shelf

Using your fullscreen Top Shelf is very easy. As soon as your app icon is active in the tvOS menu, your video will play. At the top of the screen, the text ‘Swipe up for fullscreen’ appears.

When your user swipes up using the remote, the video (including music) will be played fullscreen. The screen contains two buttons (if set in code) with the options to play the full video or get more information about the video.

When the user swipes up with the remote, the video will be played fullscreen.

Debug the Top Shelf

It may happen that code you write isn’t working as you expect. In that case, you can debug the Top Shelf extension. By default, a breakpoint in an extension is not triggered, until you enable this for the extension.

To enable debug mode for an extension, select ‘Debug’ in the top menu of Xcode. Then select ‘Attach to Process’ and select the Top Shelf extension. From now on, the breakpoint will be triggered in your Top Shelf extension.


The fullscreen Top Shelf is a great new way to introduce content to your users. Use it to promote new content from your app and get more daily active users!

🚀 Like this article? Follow me on Twitter for more tvOS related news!