This page covers the settings and methods shared by every Storyteller view:
Story and Clips rows and grids, and the two Clips player views. For the
settings that only rows or only grids use, see
Add a Story or Clips row and
Add a Story or Clips grid.
Note
Most examples use StorytellerStoriesRowView. The same settings apply to StorytellerStoriesGridView, StorytellerClipsRowView, and StorytellerClipsGridView. Where StorytellerClipsPlayerView or StorytellerEmbeddedClipsPlayerView works differently, the section says so.
conststoryRow=newStoryteller.StorytellerStoriesRowView('stories-row-id');// All CategoriesconststoryRowWithCategories=newStoryteller.StorytellerStoriesRowView('stories-row-id',['category-1','category-2']);
StorytellerClipsPlayerView shows the Clips player in your container instead
of opening it from a row or grid. Pass a collection ID to play the collection,
or { clipId } or { externalId } to play one Clip. For a player inside other
page content, such as a live blog, use StorytellerEmbeddedClipsPlayerView.
Add a Clips player to a page compares
the two views.
Rows and grids can order Stories by what the user has already read. Storyteller
sets the ordering for your content in the Stories API response; you don't set
it in code. With the default read ordering, unread Stories come before read
Stories. With started-aware ordering, Stories appear in three groups: not
opened, started, and finished. Pinned Stories stay first, and Live Stories stay
ahead of the other Stories. Within each group, Stories keep the order set in
the Storyteller CMS.
Clips rows, grids, and players that show a collection load more Clips when the
user reaches the last loaded Clip, including inside a Clip Category. The SDK
skips Clips it has already shown and stops when the collection has no more
Clips. You don't need to change your code.
The Clips player shows a Clip's long description when the Clip has one. The
title, description, and Categories show a short preview, and one control
expands or collapses them. Long details scroll inside the player. A Clip
without a description shows its title and Categories. To hide the title, see
the Clips player theme settings.
The SDK reads the text direction from the view's container and its ancestors,
so one page can mix directions. For example, a left-to-right page can show one
Storyteller row inside a right-to-left section.
Set a view's options by assigning an object to its configuration property.
Assigning a partial object updates only the fields it contains. In TypeScript,
type the object with IListConfiguration<'StorytellerStoriesRowView'> (use the
view's class name), IStorytellerClipsPlayerConfiguration, or
IStorytellerEmbeddedClipsPlayerConfiguration.
TypeScript examples
The TypeScript examples in these guides assume import * as Storyteller from '@getstoryteller/storyteller-sdk-javascript'; and import the configuration types they use, for example import type { IListConfiguration } from '@getstoryteller/storyteller-sdk-javascript';.
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconststoryRow=newStoryteller.StorytellerStoriesRowView('stories-row-id');storyRow.configuration={basename:'top-stories',// Needed if there are multiple lists on the same pagecategories:['category1','category2','category3'],// Stories onlycellType:Storyteller.CellType.round,// StorytellerStoriesRowView onlycontext:{source:'homepage-stories',campaign:'summer-league'},displayLimit:10,preload:true,// Stories onlytheme:customTheme,uiStyle:Storyteller.UiStyle.dark,};
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconststoryRow=newStoryteller.StorytellerStoriesRowView('stories-row-id');conststoryRowConfiguration:IListConfiguration<'StorytellerStoriesRowView'>={basename:'top-stories',// Needed if there are multiple lists on the same pagecategories:['category1','category2','category3'],// Stories onlycellType:Storyteller.CellType.round,// StorytellerStoriesRowView onlycontext:{source:'homepage-stories',campaign:'summer-league'},displayLimit:10,preload:true,// Stories onlytheme:customTheme,uiStyle:Storyteller.UiStyle.dark,};storyRow.configuration=storyRowConfiguration;
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstclipsRow=newStoryteller.StorytellerClipsRowView('clips-row-id','collection-id');clipsRow.configuration={basename:'top-clips',// Needed if there are multiple lists with the same collection on the same pagecontext:{source:'homepage-clips',campaign:'summer-league'},displayLimit:10,theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstclipsRow=newStoryteller.StorytellerClipsRowView('clips-row-id','collection-id');constclipsRowConfiguration:IListConfiguration<'StorytellerClipsRowView'>={basename:'top-clips',// Needed if there are multiple lists with the same collection on the same pagecontext:{source:'homepage-clips',campaign:'summer-league'},displayLimit:10,theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};clipsRow.configuration=clipsRowConfiguration;
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstclipPlayer=newStoryteller.StorytellerClipsPlayerView('clips-player-id',{externalId:'clip-external-id'});clipPlayer.configuration={basename:'highlight-player',context:{source:'homepage-highlight',campaign:'google-highlights'},theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};clipPlayer.topLevelBackButtonEnabled=true;clipPlayer.delegate={onTopLevelBackTapped:()=>{window.history.back();},};
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstclipPlayer=newStoryteller.StorytellerClipsPlayerView('clips-player-id',{externalId:'clip-external-id'});constclipPlayerConfiguration:IStorytellerClipsPlayerConfiguration={basename:'highlight-player',context:{source:'homepage-highlight',campaign:'google-highlights'},theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};clipPlayer.configuration=clipPlayerConfiguration;clipPlayer.topLevelBackButtonEnabled=true;clipPlayer.delegate={onTopLevelBackTapped:()=>{window.history.back();},};
StorytellerEmbeddedClipsPlayerView uses the same configuration fields as
StorytellerClipsPlayerView:
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstembeddedClipPlayer=newStoryteller.StorytellerEmbeddedClipsPlayerView('embedded-clips-player-id',{externalId:'clip-external-id'});embeddedClipPlayer.configuration={basename:'live-blog-highlight-player',context:{location:'live-blog',module:'highlight-player',},theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};embeddedClipPlayer.topLevelBackButtonEnabled=true;embeddedClipPlayer.delegate={onTopLevelBackTapped:()=>{window.history.back();},};
constcustomTheme=newStoryteller.UiTheme();// See Customize themesconstembeddedClipPlayer=newStoryteller.StorytellerEmbeddedClipsPlayerView('embedded-clips-player-id',{externalId:'clip-external-id'});constembeddedClipPlayerConfiguration:IStorytellerEmbeddedClipsPlayerConfiguration={basename:'live-blog-highlight-player',context:{location:'live-blog',module:'highlight-player',},theme:customTheme,uiStyle:Storyteller.UiStyle.dark,};embeddedClipPlayer.configuration=embeddedClipPlayerConfiguration;embeddedClipPlayer.topLevelBackButtonEnabled=true;embeddedClipPlayer.delegate={onTopLevelBackTapped:()=>{window.history.back();},};
By default, the basename is stories for Stories views and clips for Clips
views. To change it, set basename in configuration:
storyRow.configuration={basename:'top-stories',};
If a page has only one Stories or Clips view, basename is optional. Opening a
Story then goes to #stories/story-id, and opening a Clip goes to
#clips/collection-id/clip-id.
If a page has several views, the SDK derives each view's basename from its
Categories or collection. If two views have the same Categories or collection,
set a different basename on each so that every view has a unique basename.
Views with different Categories don't need one, but you can set it to make the
player URL easier to read.
Note
The SDK removes every character from a basename except ASCII letters, numbers, dashes (-), and underscores (_).
Set exactly one source on a Clips player: collection, clipId, or
externalId. The constructor throws an Error if you pass no source or more
than one. A later configuration update with an invalid source logs an error
and keeps the current source.
The IStorytellerClipsPlayerConfiguration and
IStorytellerEmbeddedClipsPlayerConfiguration types include the same source
fields.
Set topLevelBackButtonEnabled on the player itself, not in configuration.
It shows a back button at the top of a StorytellerClipsPlayerView or
StorytellerEmbeddedClipsPlayerView:
Use context to identify the placement that produced an analytics event. The
SDK returns its value in UserActivityData.context for each
onUserActivityOccurred callback from the view.
The field accepts any value. An undefined value omits context from the
callback. Explicit values such as null, false, 0, and an empty string
stay in the callback. Reassign configuration to replace the value while the
view is on the page.
When a user opens related Story or Clip content through an SDK action, the
related player keeps the source view's context. If two matching placements
share a player, events use the context from the placement that the user chose.
The configured value returns after the player is dismissed.
The SDK adds context to the browser callback only. It doesn't add the field
to Storyteller analytics API requests. The callback runs only while
enableUserActivityTracking is on. Don't put credentials or personal data in
context. See Analytics for the supported views,
deep-link behavior, tracking controls, and data handling guidance.
Each Stories row or grid starts a low-priority download of the AMP player
script before the user opens a Story. Set preload to true to also prepare
the Story player in advance. The first Story then opens sooner if that work
finishes in time, but users who never open a Story download more code.
preload defaults to false. Keep the default when the first page load
matters most.
Set theme to a UiTheme to style one view. It overrides the global theme
(Storyteller.sharedInstance.theme) for that view only: the properties you set
replace the global values, and the rest come from the global theme. A theme set
in configuration stays in place when initialize runs again. See
Customize themes.
uiStyle sets whether the view uses the light theme, the dark theme, or
follows the system setting. It takes a Storyteller.UiStyle value. JavaScript
can also pass the strings 'auto', 'light', and 'dark'.
Storyteller.UiStyle.auto (default): the view follows the system light or dark mode
Storyteller.UiStyle.light: the view always uses the light theme
Storyteller.UiStyle.dark: the view always uses the dark theme
You can also set uiStyle on the container div with the data-ui-style
attribute:
reloadData loads the view's Stories or Clips from the API again. When the
request finishes, the view updates its tiles, starts prefetching content, and
updates the read status of its Stories or Clips. The view calls
onDataLoadStarted and then onDataLoadComplete on its delegate, with the
result of the request. Clips views load the first page again. The promise
resolves when loading finishes.
Call destroy before you remove or replace the view's container, for example
when a single-page application changes route. The view removes what it
rendered, removes its player container when no other view uses it, stops
loading content and calling its delegate, and stops following theme changes.
Calling destroy again does nothing. To show content in the same element
again, create a new view. destroy is available on every view from version
11.0.0.
{"slug": "storyteller-list-view", "page_title": "Configure Views", "page_url": "StorytellerListView/", "canonical_url": "/web/StorytellerListView/", "markdown": "# Configure views {#configuring-a-storytellerlistview}\n\nThis page covers the settings and methods shared by every Storyteller view:\nStory and Clips rows and grids, and the two Clips player views. For the\nsettings that only rows or only grids use, see\n[Add a Story or Clips row](StorytellerRowView.md) and\n[Add a Story or Clips grid](StorytellerGridView.md).\n\n!!! note\n\n Most examples use `StorytellerStoriesRowView`. The same settings apply to `StorytellerStoriesGridView`, `StorytellerClipsRowView`, and `StorytellerClipsGridView`. Where `StorytellerClipsPlayerView` or `StorytellerEmbeddedClipsPlayerView` works differently, the section says so.\n\n## Initialization\n\nCreate each view with the ID of an existing element on your page, followed by\nits content source.\n\n### Stories initialization\n\n```javascript\nconst storyRow = new Storyteller.StorytellerStoriesRowView('stories-row-id'); // All Categories\nconst storyRowWithCategories = new Storyteller.StorytellerStoriesRowView(\n 'stories-row-id',\n ['category-1', 'category-2']\n);\n```\n\n### Clips initialization\n\n```javascript\nconst clipsRow = new Storyteller.StorytellerClipsRowView(\n 'clips-row-id',\n 'clip-collection-id'\n);\n```\n\n### Clips player initialization\n\n`StorytellerClipsPlayerView` shows the Clips player in your container instead\nof opening it from a row or grid. Pass a collection ID to play the collection,\nor `{ clipId }` or `{ externalId }` to play one Clip. For a player inside other\npage content, such as a live blog, use `StorytellerEmbeddedClipsPlayerView`.\n[Add a Clips player to a page](StorytellerEmbeddedClipsPlayerView.md) compares\nthe two views.\n\n```javascript\nconst collectionPlayer = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n 'clip-collection-id'\n);\n\nconst singleClipPlayer = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { clipId: 'clip-id' }\n);\n\nconst singleClipPlayerByExternalId = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { externalId: 'clip-external-id' }\n);\n```\n\nThe constructor throws an `Error` if you pass no source or more than one\nsource.\n\nThe Storyteller Web Showcase picks a Stories row or grid for each feed module\nfrom its layout with\n[`isGridLikeLayout`](https://github.com/getstoryteller/storyteller-showcase-web/blob/11.0.0/nextjs/src/components/pages/showcase/home/showcase-sdk-module/ShowcaseStoriesModule.tsx#L70).\n\n## Story ordering\n\nRows and grids can order Stories by what the user has already read. Storyteller\nsets the ordering for your content in the Stories API response; you don't set\nit in code. With the default read ordering, unread Stories come before read\nStories. With started-aware ordering, Stories appear in three groups: not\nopened, started, and finished. Pinned Stories stay first, and Live Stories stay\nahead of the other Stories. Within each group, Stories keep the order set in\nthe Storyteller CMS.\n\n## Clips paging\n\nClips rows, grids, and players that show a collection load more Clips when the\nuser reaches the last loaded Clip, including inside a Clip Category. The SDK\nskips Clips it has already shown and stops when the collection has no more\nClips. You don't need to change your code.\n\n- [`reloadData`](#reloaddata) loads the first page again.\n- The view's [`onDataLoadComplete`](StorytellerListViewDelegate.md#ondataloadcomplete)\n callback reports the first page only. Later pages load without delegate\n callbacks.\n- A Clips player that shows one Clip, created with `{ clipId }` or\n `{ externalId }`, doesn't load more Clips.\n\n## Clip details\n\nThe Clips player shows a Clip's long description when the Clip has one. The\ntitle, description, and Categories show a short preview, and one control\nexpands or collapses them. Long details scroll inside the player. A Clip\nwithout a description shows its title and Categories. To hide the title, see\nthe [Clips player theme settings](Themes.md#clip-player).\n\n## Right-to-left (RTL) pages {#rtl-support}\n\nThe Web SDK supports right-to-left host pages for Stories rows, Clips rows, and\nthe Story player.\n\n### Host page setup\n\nSet `dir=\"rtl\"` on the page or on the closest container that wraps the SDK view:\n\n```html\n<section dir=\"rtl\">\n <div id=\"stories-row-id\"><\/div>\n<\/section>\n```\n\n```javascript\nconst storyRow = new Storyteller.StorytellerStoriesRowView('stories-row-id');\n```\n\nThe SDK reads the text direction from the view's container and its ancestors,\nso one page can mix directions. For example, a left-to-right page can show one\nStoryteller row inside a right-to-left section.\n\n### Supported surfaces\n\nRTL support applies to:\n\n- `StorytellerStoriesRowView`\n- `StorytellerClipsRowView`\n- Story players opened from Stories rows and grids\n\nIn a right-to-left row, the scroll controls, edge fades, and disabled states\nfollow the right-to-left scroll direction.\n\nWhen a Story opens from an RTL page, the Story player uses right-to-left text\nand controls.\n\n## Configuration\n\nSet a view's options by assigning an object to its `configuration` property.\nAssigning a partial object updates only the fields it contains. In TypeScript,\ntype the object with `IListConfiguration<'StorytellerStoriesRowView'>` (use the\nview's class name), `IStorytellerClipsPlayerConfiguration`, or\n`IStorytellerEmbeddedClipsPlayerConfiguration`.\n\n!!! note \"TypeScript examples\"\n\n The TypeScript examples in these guides assume `import * as Storyteller from '@getstoryteller/storyteller-sdk-javascript';` and import the configuration types they use, for example `import type { IListConfiguration } from '@getstoryteller/storyteller-sdk-javascript';`.\n\n### Stories configuration\n\n=== \"JavaScript\"\n\n ```javascript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const storyRow = new Storyteller.StorytellerStoriesRowView('stories-row-id');\n storyRow.configuration = {\n basename: 'top-stories', // Needed if there are multiple lists on the same page\n categories: ['category1', 'category2', 'category3'], // Stories only\n cellType: Storyteller.CellType.round, // StorytellerStoriesRowView only\n context: {\n source: 'homepage-stories',\n campaign: 'summer-league'\n },\n displayLimit: 10,\n preload: true, // Stories only\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n ```\n\n=== \"TypeScript\"\n\n ```typescript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const storyRow = new Storyteller.StorytellerStoriesRowView('stories-row-id');\n const storyRowConfiguration: IListConfiguration<'StorytellerStoriesRowView'> = {\n basename: 'top-stories', // Needed if there are multiple lists on the same page\n categories: ['category1', 'category2', 'category3'], // Stories only\n cellType: Storyteller.CellType.round, // StorytellerStoriesRowView only\n context: {\n source: 'homepage-stories',\n campaign: 'summer-league'\n },\n displayLimit: 10,\n preload: true, // Stories only\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n storyRow.configuration = storyRowConfiguration;\n ```\n\n### Clips configuration\n\n=== \"JavaScript\"\n\n ```javascript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const clipsRow = new Storyteller.StorytellerClipsRowView(\n 'clips-row-id',\n 'collection-id'\n );\n clipsRow.configuration = {\n basename: 'top-clips', // Needed if there are multiple lists with the same collection on the same page\n context: {\n source: 'homepage-clips',\n campaign: 'summer-league'\n },\n displayLimit: 10,\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n ```\n\n=== \"TypeScript\"\n\n ```typescript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const clipsRow = new Storyteller.StorytellerClipsRowView(\n 'clips-row-id',\n 'collection-id'\n );\n const clipsRowConfiguration: IListConfiguration<'StorytellerClipsRowView'> = {\n basename: 'top-clips', // Needed if there are multiple lists with the same collection on the same page\n context: {\n source: 'homepage-clips',\n campaign: 'summer-league'\n },\n displayLimit: 10,\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n clipsRow.configuration = clipsRowConfiguration;\n ```\n\n### Clips player configuration\n\n=== \"JavaScript\"\n\n ```javascript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const clipPlayer = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { externalId: 'clip-external-id' }\n );\n clipPlayer.configuration = {\n basename: 'highlight-player',\n context: {\n source: 'homepage-highlight',\n campaign: 'google-highlights'\n },\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n clipPlayer.topLevelBackButtonEnabled = true;\n clipPlayer.delegate = {\n onTopLevelBackTapped: () => {\n window.history.back();\n },\n };\n ```\n\n=== \"TypeScript\"\n\n ```typescript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const clipPlayer = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { externalId: 'clip-external-id' }\n );\n const clipPlayerConfiguration: IStorytellerClipsPlayerConfiguration = {\n basename: 'highlight-player',\n context: {\n source: 'homepage-highlight',\n campaign: 'google-highlights'\n },\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n clipPlayer.configuration = clipPlayerConfiguration;\n clipPlayer.topLevelBackButtonEnabled = true;\n clipPlayer.delegate = {\n onTopLevelBackTapped: () => {\n window.history.back();\n },\n };\n ```\n\n### Embedded Clips player configuration\n\n`StorytellerEmbeddedClipsPlayerView` uses the same configuration fields as\n`StorytellerClipsPlayerView`:\n\n=== \"JavaScript\"\n\n ```javascript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const embeddedClipPlayer =\n new Storyteller.StorytellerEmbeddedClipsPlayerView(\n 'embedded-clips-player-id',\n { externalId: 'clip-external-id' }\n );\n embeddedClipPlayer.configuration = {\n basename: 'live-blog-highlight-player',\n context: {\n location: 'live-blog',\n module: 'highlight-player',\n },\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n embeddedClipPlayer.topLevelBackButtonEnabled = true;\n embeddedClipPlayer.delegate = {\n onTopLevelBackTapped: () => {\n window.history.back();\n },\n };\n ```\n\n=== \"TypeScript\"\n\n ```typescript\n const customTheme = new Storyteller.UiTheme(); // See Customize themes\n const embeddedClipPlayer =\n new Storyteller.StorytellerEmbeddedClipsPlayerView(\n 'embedded-clips-player-id',\n { externalId: 'clip-external-id' }\n );\n const embeddedClipPlayerConfiguration: IStorytellerEmbeddedClipsPlayerConfiguration = {\n basename: 'live-blog-highlight-player',\n context: {\n location: 'live-blog',\n module: 'highlight-player',\n },\n theme: customTheme,\n uiStyle: Storyteller.UiStyle.dark,\n };\n embeddedClipPlayer.configuration = embeddedClipPlayerConfiguration;\n embeddedClipPlayer.topLevelBackButtonEnabled = true;\n embeddedClipPlayer.delegate = {\n onTopLevelBackTapped: () => {\n window.history.back();\n },\n };\n ```\n\n!!! info \"Learn more\"\n\n See [Add a Story or Clips row](StorytellerRowView.md) and [Add a Story or Clips grid](StorytellerGridView.md) for the settings specific to rows and grids.\n\n#### basename\n\nEach Stories or Clips view has a `basename`, which is the first segment of the\nplayer's hash URL. For example:\n\n```text\nhttps://www.getstoryteller.com/#basename/story-id\nhttps://www.getstoryteller.com/#basename/collection-id/clip-id\n```\n\nBy default, the `basename` is `stories` for Stories views and `clips` for Clips\nviews. To change it, set `basename` in `configuration`:\n\n```javascript\nstoryRow.configuration = {\n basename: 'top-stories',\n};\n```\n\nIf a page has only one Stories or Clips view, `basename` is optional. Opening a\nStory then goes to `#stories/story-id`, and opening a Clip goes to\n`#clips/collection-id/clip-id`.\n\nIf a page has several views, the SDK derives each view's `basename` from its\nCategories or collection. If two views have the same Categories or collection,\nset a different `basename` on each so that every view has a unique `basename`.\nViews with different Categories don't need one, but you can set it to make the\nplayer URL easier to read.\n\n!!! note\n\n The SDK removes every character from a basename except ASCII letters, numbers, dashes (`-`), and underscores (`_`).\n\n#### categories (Stories only)\n\nSet `categories` to show only Stories from those Categories. Without\n`categories`, the view shows the Stories in your Home list.\n\nTo change the Categories of a Storyteller row, assign new ones in\n`configuration`:\n\n```javascript\nstoryRow.configuration = {\n categories: ['new-category-id-1', 'new-category-id-2'],\n};\n```\n\nCopy Category IDs from the Storyteller CMS.\n\n!!! info \"Learn more\"\n\n See [Categories](https://www.getstoryteller.com/user-guide/stories-and-scheduling/categories) for more information about managing Categories in the CMS.\n\n#### collection (Clips only)\n\nA Clips view needs a collection ID when you create it:\n\n```javascript\nconst clipsRow = new Storyteller.StorytellerClipsRowView(\n 'clips-row-id',\n 'clip-collection-id'\n);\n```\n\nTo change the collection later, set `collection` in `configuration`:\n\n```javascript\nclipsRow.configuration = {\n collection: 'new-clip-collection-id',\n};\n```\n\nCopy the collection ID from the Storyteller CMS.\n\n!!! info \"Learn more\"\n\n See [Creating Collections](https://www.getstoryteller.com/user-guide/clips-and-collections/creating-collections) for more information about managing collections in the CMS.\n\n#### clipId / externalId (Clips player only)\n\nTo play a single Clip in `StorytellerClipsPlayerView` or\n`StorytellerEmbeddedClipsPlayerView`, pass an object with either `clipId` or\n`externalId`:\n\n```javascript\nconst clipPlayerById = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { clipId: 'clip-id' }\n);\n\nconst clipPlayerByExternalId = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { externalId: 'clip-external-id' }\n);\n\nconst embeddedClipPlayerByExternalId =\n new Storyteller.StorytellerEmbeddedClipsPlayerView(\n 'embedded-clips-player-id',\n { externalId: 'clip-external-id' }\n );\n```\n\nTo switch the player to a different Clip later, assign the new identifier in\n`configuration`:\n\n```javascript\nclipPlayerById.configuration = {\n clipId: 'new-clip-id',\n};\n\nclipPlayerByExternalId.configuration = {\n externalId: 'new-clip-external-id',\n};\n```\n\nSet exactly one source on a Clips player: `collection`, `clipId`, or\n`externalId`. The constructor throws an `Error` if you pass no source or more\nthan one. A later `configuration` update with an invalid source logs an error\nand keeps the current source.\n\nThe `IStorytellerClipsPlayerConfiguration` and\n`IStorytellerEmbeddedClipsPlayerConfiguration` types include the same source\nfields.\n\n#### topLevelBackButtonEnabled (Clips player only)\n\nSet `topLevelBackButtonEnabled` on the player itself, not in `configuration`.\nIt shows a back button at the top of a `StorytellerClipsPlayerView` or\n`StorytellerEmbeddedClipsPlayerView`:\n\n```javascript\nconst clipPlayer = new Storyteller.StorytellerClipsPlayerView(\n 'clips-player-id',\n { externalId: 'clip-external-id' }\n);\n\nclipPlayer.topLevelBackButtonEnabled = true;\nclipPlayer.delegate = {\n onTopLevelBackTapped: () => {\n window.history.back();\n },\n};\n```\n\nWhen the user taps the back button:\n\n- If `clipPlayer.delegate.onTopLevelBackTapped` is defined, the SDK calls it and your code decides what happens next.\n- If no callback is defined, the SDK calls `window.history.back()`.\n\n`topLevelBackButtonEnabled` defaults to `false`, which hides the button. While\nthe button is hidden, the SDK doesn't call `onTopLevelBackTapped`.\n\n#### context\n\nUse `context` to identify the placement that produced an analytics event. The\nSDK returns its value in `UserActivityData.context` for each\n`onUserActivityOccurred` callback from the view.\n\n```javascript\nclipsRow.configuration = {\n context: {\n location: 'home',\n module: 'featured-clips',\n sortOrder: 20,\n },\n};\n```\n\nThe field accepts any value. An `undefined` value omits `context` from the\ncallback. Explicit values such as `null`, `false`, `0`, and an empty string\nstay in the callback. Reassign `configuration` to replace the value while the\nview is on the page.\n\nWhen a user opens related Story or Clip content through an SDK action, the\nrelated player keeps the source view's context. If two matching placements\nshare a player, events use the context from the placement that the user chose.\nThe configured value returns after the player is dismissed.\n\nThe SDK adds `context` to the browser callback only. It doesn't add the field\nto Storyteller analytics API requests. The callback runs only while\n`enableUserActivityTracking` is on. Don't put credentials or personal data in\n`context`. See [Analytics](Analytics.md#context) for the supported views,\ndeep-link behavior, tracking controls, and data handling guidance.\n\n#### displayLimit\n\n`displayLimit` is the maximum number of tiles the view shows. It's optional.\n\n#### preload\n\nEach Stories row or grid starts a low-priority download of the AMP player\nscript before the user opens a Story. Set `preload` to `true` to also prepare\nthe Story player in advance. The first Story then opens sooner if that work\nfinishes in time, but users who never open a Story download more code.\n`preload` defaults to `false`. Keep the default when the first page load\nmatters most.\n\n#### theme\n\nSet `theme` to a `UiTheme` to style one view. It overrides the global theme\n(`Storyteller.sharedInstance.theme`) for that view only: the properties you set\nreplace the global values, and the rest come from the global theme. A theme set\nin `configuration` stays in place when `initialize` runs again. See\n[Customize themes](Themes.md).\n\n```javascript\nconst customTheme = new Storyteller.UiTheme({\n light: {\n lists: {\n row: {\n startInset: 0,\n endInset: 0,\n },\n },\n },\n});\n\nstoryRow.configuration = {\n theme: customTheme,\n};\n```\n\n#### uiStyle\n\n`uiStyle` sets whether the view uses the light theme, the dark theme, or\nfollows the system setting. It takes a `Storyteller.UiStyle` value. JavaScript\ncan also pass the strings `'auto'`, `'light'`, and `'dark'`.\n\n- `Storyteller.UiStyle.auto` (default): the view follows the system light or dark mode\n- `Storyteller.UiStyle.light`: the view always uses the light theme\n- `Storyteller.UiStyle.dark`: the view always uses the dark theme\n\nYou can also set `uiStyle` on the container `div` with the `data-ui-style`\nattribute:\n\n```html\n<div id=\"storyteller-row\" data-ui-style=\"dark\"><\/div>\n```\n\n## Methods\n\n### reloadData\n\n```typescript\nreloadData(): Promise<void>\n```\n\n`reloadData` loads the view's Stories or Clips from the API again. When the\nrequest finishes, the view updates its tiles, starts prefetching content, and\nupdates the read status of its Stories or Clips. The view calls\n`onDataLoadStarted` and then `onDataLoadComplete` on its delegate, with the\nresult of the request. Clips views load the first page again. The promise\nresolves when loading finishes.\n\n```javascript\nconst storyRow = new Storyteller.StorytellerStoriesRowView('stories-row-id');\nstoryRow.reloadData();\n```\n\n### destroy {#destroy}\n\n```typescript\ndestroy(): void\n```\n\nCall `destroy` before you remove or replace the view's container, for example\nwhen a single-page application changes route. The view removes what it\nrendered, removes its player container when no other view uses it, stops\nloading content and calling its delegate, and stops following theme changes.\nCalling `destroy` again does nothing. To show content in the same element\nagain, create a new view. `destroy` is available on every view from version\n11.0.0.\n\n```javascript\nstoryRow.destroy();\n```\n\nFor React and Next.js, see\n[Use React or Next.js](getting-started/react-nextjs.md).\n\n### openStory, openStoryByExternalId, openPage, openCollection, openClipByExternalId\n\nThese methods, and `openCategory`, are on `Storyteller.sharedInstance`, not on\nviews.\n\n!!! info \"Learn more\"\n\n See [Open a player programmatically](OpenPlayer.md) for examples, and [Use additional SDK methods](AdditionalMethods.md#instance-methods) for the full signatures.\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}