This is the example I have been working on to display a list of "news" items, with the possibility of differentiating the displayed rendering-variant according to whether or not the news item was the first in the results.
I have used a Sitecore custom "rule" for determining whether or not the item being displayed is the first item (as recommended by another poster).
Note that this example is part of a proof-of-concept (and SXA learning exercise) I have been working on, so it is definitely not representative of "best practice", and some classes and logic are really superfluous (as they were really only made to help in my learning). So this is presented "as is".
I also took a lot of inspiration from "https://alan-null.github.io/2017/12/sxa-blog#search-results-page". So if any of the below description does not make sense, then it's probably because I made a mistake, and you should check the this url.
The most relevant stuff below is probably in steps 5, 7 and 16.
(A) SITECORE Items:
1. Clone Page List.
Clone SXA's "Page List" rendering (from "/sitecore/layout/Renderings/Feature/Experience Accelerator/Page Content/Page List").
Call the new rendering "News List", set the "Parameters" to "make a copy"; and the "Datasource" to "make a copy". Set the View to a new view called "News List.cshtml".
In the newly cloned controller-rendering, set or check the fields:
Name="Controller"; Value="Quotation.Controller.NewsListController,Quotation.Controller"
Name="Controller Action"; Value="Index"
Name="Parameters Template"; Value= points to a cloned parameters template
Name="Rendering css class"; Value="news-list"
Name="Rendering view path"; Value="~/Views/News/News List.cshtml" (or as specified when the rendering was cloned)
Name="Other Properties"; Value=IsPaginationEnabledRendering=true, IsRenderingsWithDynamicPlaceholders=true
2. Rendering Parameters
Find the rendering parameters item (as created in step #1).

Set/check the fields:
"Base template" field. Set the value to:
{8CA06D6A-B353-44E8-BC31-B528C7306971}|{A9F8A74E-5F7D-4506-8661-B08E7B9A7B91}|{D959F476-2A2C-40C6-81F5-FB75342BBFB9}|{FF75632A-03ED-4D31-B42A-1EEE45E5147F}|{5E680478-0705-4452-A14B-42B945EB1AB6}|{5BDF5EFE-B334-407B-BD42-ABFF8595B691}|{5C74E985-E055-43FF-B28C-DB6C6A6450A2}|{3DB3EB10-F8D0-4CC9-BE26-18CE7B139EC8}|{6DA8A00F-473E-487D-BEFE-6834350D5B67}
"Droplink" field called "SourceType". Set the "Source" to:
query:/sitecore/system/Settings/Foundation/Experience Accelerator/Search/Item Queries//[@@templatename='Query']|$site/[@@name='Settings']/Item Queries//[@@templatename='Query']|$sharedSites/[@@name='Settings']/Item Queries//*[@@templatename='Query']
3. Page Templates
Under "Templates/Project/..." (as appropriate for your site), create a page-template for the news-list page ("News List Page Template") and the news-detail page ("News Page Template").

In the "News Page Template" create fields:
Name="Date"; Type=Date
Name="Teaser Image"; Type=Image; Source="query:$siteMedia"
4. Pages
Create some pages based on the templates created in step #3. For example, under your site's content, create a "News List Page Template" item.
Under this item, create several "News Page Template" items.

5. Custom Rule
Create a "Condition" item called "News Item Is First" under "/sitecore/system/Settings/Rules/Definitions/Elements/Indexing and Search"

Set the "Text" field value to "where the News item is first result".
Set the "Type" to "Quotation.Controller.IsFirstResultRule,Quotation.Controller"
(Note the namespace would be something more relevant in reality - this is simply placed where I had some existing code).
6. Available Renderings
Under your site's "Presentation/Available Renderings" item, create an "Available Renderings" item called "News List".
Edit the "Renderings" field, and select the News List controller-rendering created in step #1.

7. News List Variant Definition
Under your site's "Presentation/Rendering Variants" item, create a "Variants" item called "News List".

Under this, create a "Variant Definition" item called "Default News List".
Under this, create 2 "VariantSection" items called "News List Section First" and "News List Section Normal". It is these sections we "switch" on and off depending
on whether or not the news item being displayed is the first.
In the "News List Section First" item, edit the rule field - select the rule created in step #5.

In the "News List Section Normal" item, edit the rule field - select the rule created in step #5 (make it "except where").

Create the other display-field items as appropriate under the 2 variant-section items.
8. Page Content Variant Definition
Under your site's "Presentation/Rendering Variants/Page Content" item, create a "Variant Definition" item called "News Entry".
(I think "best practice" is to clone the "Page Content" rendering under "/sitecore/layout/Renderings/Feature/Experience Accelerator/Page Content", but I did not).
In any case, create sub-items to "News Entry" called
"Title"; type=Field
"Date"; type=Date
"Content"; type=Field
9. Query
Create the query for the page-list. Under your site, under the "Settings" folder, create a "Query" item called "News Item Query".

Set the Query field value to "+location:{EEF4E1F4-5B7B-48DF-BE28-84F40C462CB0};+template:{9BDD1D3D-855C-4A22-83A0-5BC67E505537};sort:date[desc]".
Note of course that the Sitecore IDs here relate to my specific site.
The location points to the News page for your site (step #4). The template is the "News Page Template" create in step #3.
(This can apparently be created using the query-builder, but I couldn't get it to work, so I typed it in manually).
10. Partial Designs.
Under your site's "Presentation/Partial Designs" folder, create partial designs for the news-list and news-details page.

On the "News List" partial design, place a "News List" rendering.
I did this using the experience editor for the "News List" partial design. You should see the "News List" rendering in the toolbox which you can drag-and-drop to the page.
Edit the rendering parameters - in the "Source Type" field, select the query from step #9.
On the "News" partial design, drag-and-drop a "Page Content" rendering. Set the Variant to "News Entry" (created in step #8).
11. Page Designs
Under your site's "Presentation/Page Designs" item, create 2 Page Design items, called "News List Page" and "News Page".
Set up the Partial Designs on each Page Design. For example:


12. Template/Design mappings
On your site's "Presentation/Page Designs" item, map the templates to the page-designs. For example:

(B) CODE
13. Model.
As stated, this is really only created as part of my proof-of-concept, and is not strictly required.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.XA.Foundation.Variants.Abstractions.Models;
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.RenderingVariants.Models;
using Sitecore.XA.Foundation.Mvc.Repositories.Base;
namespace Quotation.Controller
{
public class NewsListModel : VariantListsRenderingModel, IRenderingModelBase
{
public NewsListModel(VariantListsRenderingModel model)
{
if (model != null)
{
this.Attributes = model.Attributes;
this.CssClasses = model.CssClasses;
this.DataSourceItem = model.DataSourceItem;
this.HeadingTag = model.HeadingTag;
this.IsControlEditable = model.IsControlEditable;
this.IsEdit = model.IsEdit;
this.Item = model.Item;
this.Items = model.Items;
this.MessageEditHere = model.MessageEditHere;
this.MessageIsEmpty = model.MessageIsEmpty;
this.PageItem = model.PageItem;
this.Rendering = model.Rendering;
this.VariantFields = model.VariantFields;
if (this.Items != null && this.Items.Any())
{
FirstResultItem = this.Items.FirstOrDefault();
}
}
}
public Item FirstResultItem { get; private set; }
}
}
14. Controller.
This controller is simply a copy of SXA's PageListController, and as stated not strictly required.
using Sitecore.XA.Feature.PageContent.Repositories;
using Sitecore.XA.Foundation.RenderingVariants.Controllers.Base;
using Sitecore.XA.Foundation.RenderingVariants.Lists.Pagination;
using Sitecore.Data.Items;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.XA.Foundation.Mvc.Repositories.Base;
using Sitecore.XA.Foundation.RenderingVariants.Models;
namespace Quotation.Controller
{
/// <summary>
/// Copy of Sitecore.XA.Feature.PageContent.Controllers.PageListController.
/// </summary>
public class NewsListController : PaginableController
{
protected IPageListRepository PageListRepository { get; }
public NewsListController(IPageListRepository pageListRepository)
{
this.PageListRepository = pageListRepository;
}
protected override IListPagination PaginationConfiguration
{
get
{
var renderingParameters = this.Rendering.Parameters;
var keyFunc = (Func<KeyValuePair<string, string>, string>)(p => p.Key);
var valueFunc = (Func<KeyValuePair<string, string>, string>)(p => p.Value);
var dict = (IDictionary<string, string>)renderingParameters.ToDictionary<KeyValuePair<string, string>, string, string>(keyFunc, valueFunc);
var pg = (IListPagination)new ListPagination(dict, this.PageListRepository.Items.Count<Item>());
return pg;
}
}
protected override object GetModel()
{
IListPagination paginationConfiguration = this.PaginationConfiguration;
IRenderingModelBase renderingModelBase = this.PageListRepository.GetModel(paginationConfiguration);
NewsListModel res = new NewsListModel(renderingModelBase as VariantListsRenderingModel);
return res;
}
}
}
15. Service Registration
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Sitecore.DependencyInjection;
using Sitecore.XA.Foundation.RenderingVariants.Repositories;
namespace Quotation.Controller
{
public class RegisterNewsServices : IServicesConfigurator
{
public void Configure(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<NewsListController>();
}
}
}
16. Custom Rule
Note that if you haven't made a "custom controller" and model, then the model supplied to this rule will be "VariantListsRenderingModel".
using Sitecore.Rules;
using Sitecore.Rules.Conditions;
using Sitecore.XA.Foundation.RenderingVariants.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Quotation.Controller
{
public class IsFirstResultRule<T> : WhenCondition<T> where T : RuleContext
{
protected override bool Execute(T ruleContext)
{
var model = ruleContext.Parameters["Model"];
NewsListModel newsListModel = model as NewsListModel;
if (newsListModel != null)
{
var contextItem = ruleContext.Item;
if (contextItem != null)
{
var firstSearchResult = newsListModel.FirstResultItem;
if (firstSearchResult != null)
{
var isFirst = contextItem.ID == firstSearchResult.ID;
return isFirst;
}
}
}
return true;
}
}
}
17. Configuration.
Put in a patch file in "App_Config/Include".
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
<sitecore>
<services>
<configurator type="Quotation.Controller.RegisterNewsServices, Quotation.Controller" />
</services>
</sitecore>
</configuration>
18. View.
Create a cshtml called "News List.cshtml". I copied SXA's "Page List.cshtml".
@using Sitecore.Data.Items
@using Sitecore.XA.Foundation.MarkupDecorator.Extensions
@using Sitecore.XA.Foundation.RenderingVariants.Extensions
@using Sitecore.XA.Foundation.RenderingVariants.Fields
@using Sitecore.XA.Foundation.SitecoreExtensions.Extensions
@using Sitecore.XA.Foundation.Variants.Abstractions.Fields
@model Quotation.Controller.NewsListModel
@{
var newsListModel = Model;
}
<!-- News List -->
<div @Html.Sxa().Component(newsListModel.Rendering.RenderingCssClass ?? "page-list", newsListModel.Attributes)>
<div class="component-content">
@if (newsListModel.Items.Any() && newsListModel.VariantFields != null)
{
<ul class="items">
@foreach (Item item in newsListModel.Items)
{
<li class="item">
<!-- @item.ID -->
@if (item.ID == newsListModel.FirstResultItem.ID)
{
<!-- FIRST RESULT! -->
}
@foreach (BaseVariantField variantField in newsListModel.VariantFields)
{
@Html.RenderingVariants().RenderVariant(variantField, item, newsListModel.RenderingWebEditingParams, newsListModel)
}
</li>
}
</ul>
}
else
{
@newsListModel.MessageIsEmpty
}
</div>
</div>
<!-- /News List -->