Sidekick & AI

Scriban Fallbacks and Truncation for Sidekick-Assisted Fields

Code on screen close-up
Photo: AltumCode / Unsplash · Royalty-free

Sidekick Writes Fields, Scriban Delivers Them

Sidekick can suggest a headline, teaser, or CTA label. Scriban on your rendering variant or headless layout decides what actually appears when the field is empty, too long, or still in rich text markup authors never see on the front end. Teams that wire AI copy without Scriban guards get blank cards, broken General Links, and Experience Editor previews that do not match CD output.

This post walks through Scriban patterns we use on XM with SXA style partial designs and JSS Layout Service consumers. Examples assume field names on a typical page branch; adjust IDs to your templates.

Code on screen in dark theme editor
Scriban belongs in variant definitions so delivery rules stay centralized.
Photo by Markus Spiske on Unsplash

CTA General Link Guards

General Link fields serialize as structured objects, not strings. Sidekick often outputs link text without verifying target item or URL. Guard before rendering the anchor.

{{~ $link = i_item.cta_link $hasLink = $link && ($link.url != "" || $link.target != "") $text = $link.text if !$text || $text == "" $text = i_item.cta_fallback_text | default "Learn more" end
~}}
{{ if $hasLink }} <a href="{{ $link.url }}" class="btn btn-primary" {{ if $link.target != "" }}target="{{ $link.target }}"{{ end }} {{ if $link.title != "" }}title="{{ $link.title }}"{{ end }}> {{ $text }} </a>
{{ end }}

Do not render an empty <a href="">. Accessibility audits flag that faster than SEO issues.

Sidekick empty CTA behavior

When Sidekick leaves CTA empty, fall back to site standard values on the CTA partial design, not hardcoded English in every variant.

{{~ $link = i_item.cta_link if !$link || ($link.url == "" && $link.target == "") $link = i_site.root.cta_standard_link end
~}}

Document in author one pager: Sidekick fills CTA Label text field; authors must pick link target manually or accept standard link from partial design.

Parent Headline Inheritance

Card teasers and breadcrumb titles often need parent context when child Title is empty. Walk ancestors with Scriban @ or explicit parent fetch depending on your SXA version.

{{~ $title = i_item.title if !$title || $title == "" $parent = i_item.parent while $parent && ($title == "" || !$title) $title = $parent.title $parent = $parent.parent end end if !$title $title = i_item.name end
~}}
<h2 class="card-title">{{ $title }}</h2>

Cap inheritance depth to avoid pulling a site root slogan into a deep product card. We stop at three levels or when template ID matches section landing type.

{{~ $depth = 0 $maxDepth = 3 while $parent && $depth < $maxDepth && ($title == "" || !$title) if $parent.template_id == "section-landing-template-guid" $title = $parent.title break end $title = $parent.title $parent = $parent.parent $depth = $depth + 1 end
~}}

Rich Text strip_html and Truncate

Sidekick may write rich text into fields used as plain teasers. Strip markup before length limits.

{{~ $raw = i_item.teaser | default "" $plain = $raw | strip_html | string.strip $max = 160 if $plain.size > $max $plain = $plain | string.truncate $max end
~}}
<p class="teaser">{{ $plain }}</p>

For card grids, use a shorter max than meta description. Keep two constants in Scriban as variables at top of variant for author documentation parity.

Ellipsis and word boundaries

string.truncate may cut mid word. Optional word boundary trim:

{{~ $plain = $raw | strip_html | string.strip if $plain.size > $max $plain = $plain | string.truncate $max $lastSpace = $plain | string.last_index_of " " if $lastSpace > 50 $plain = $plain | string.slice 0 $lastSpace end $plain = $plain + "..." end
~}}

Card Teasers from Multiple Sources

Priority chain: dedicated teaser field, then summary, then first paragraph of body, then parent headline prefix.

{{~ $teaser = i_item.card_teaser if !$teaser || ($teaser | strip_html | string.strip) == "" $teaser = i_item.summary end if !$teaser || ($teaser | strip_html | string.strip) == "" $body = i_item.body | default "" $teaser = $body | strip_html | string.strip | string.truncate 120 end if !$teaser || $teaser == "" $teaser = "Updates from " + (i_item.parent.title | default "our team") end
~}}

When Sidekick populates card_teaser, delivery uses it. When author clears field after bad suggestion, fallback chain prevents empty cards without republishing Sidekick.

Empty Sidekick Fields

Distinguish null, empty string, and whitespace only. Sidekick sometimes writes whitespace that passes EE validation.

{{~ func is_blank(s) if !s ret true end ret (s | string.strip) == "" end $headline = i_item.sidekick_headline if is_blank $headline $headline = i_item.manual_headline end if is_blank $headline $headline = i_item.title end
~}}

Expose manual_headline as author override always visible in EE. Sidekick suggestions write to sidekick_headline; approving copies or replaces per workflow rule. Scriban prefers manual when present.

Experience Editor vs Delivery

EE shows field raw values. CD applies Scriban. Authors report bugs when EE headline shows HTML entities and site shows truncated plain text.

Alignment strategies

  • Honest labeling: Help text on teaser field states “Rendered as plain text, max 160 characters on site.”
  • EE chrome script: Lightweight JS in EE reads same truncate rules via data attributes generated by a simplified Scriban preview endpoint (heavier maintenance).
  • Separate fields: Sidekick writes to internal rich field; scheduled save action or apply step copies stripped value to display field (CM only processor).

We prefer separate display fields for regulated clients so legal approves exactly what Scriban reads without runtime strip surprises.

{{~ # Delivery reads approved display field only $headline = i_item.headline_display | default i_item.title
~}}

Additional Scriban Blocks

Meta description fallback

{{~ $meta = i_item.meta_description if is_blank $meta $meta = i_item.teaser | strip_html | string.strip | string.truncate 155 end
~}}
<meta name="description" content="{{ $meta | html.escape }}" />

Image alt from Sidekick or media item

{{~ $img = i_item.hero_image $alt = i_item.sidekick_image_alt if is_blank $alt && $img $alt = $img.alt | default $img.title end if is_blank $alt $alt = i_item.title end
~}}

Conditional AI badge for audit demos

{{~ $promptVer = i_item.sidekick_prompt_version
~}}
{{ if $promptVer && $env == "staging" }} <span class="ai-audit-badge" data-prompt="{{ $promptVer }}">AI draft</span>
{{ end }}

Never show audit badge on production customer facing pages unless legal explicitly requires transparency.

Design mockups and content layout review
Author one pagers should show EE field vs rendered output side by side.
Photo by Kelly Sikkema on Unsplash

Author One-Pager Structure

Give authors a single PDF or Sitecore help topic per template family.

  1. Field map table: field name, Sidekick yes or no, Scriban fallback, max length.
  2. Workflow: suggest, apply on approve, manual override field names.
  3. EE vs site: screenshot pair for teaser truncation and CTA link.
  4. Do not edit: Connect owned commerce fields listed read only.
  5. Support: link to prompt release notes and rubric failure examples.

Example row: “Card Teaser | Sidekick suggests to sidekick_card_teaser | Scriban uses card_teaser then summary then body truncate 120 | 120 plain chars after strip_html”

Testing Scriban with Sidekick

  • Fixture items with empty, whitespace, and overflow rich text in Sidekick fields.
  • Snapshot rendered HTML from Layout Service, not EE DOM.
  • Verify General Link with text only, URL only, external URL, and media link target types.
  • Regression when partial design standard values change CTA fallback link.

SXA Variant Organization

Place Scriban in variant fields, not scattered in rendering parameters authors duplicate. One Hero variant named Default with AI fallbacks documents which fields participate in chains. When authors clone variants for campaigns, they inherit guards. Avoid copy paste Scriban into twelve variants; centralize with Scriban includes if your Sitecore version supports include files in themes.

{{ include "field-guards/is_blank.scriban" }}
{{ include "field-guards/teaser_chain.scriban" }}

Theme repo review includes Scriban diff same as prompt JSON review when Sidekick field names change.

Layout Service and JSS Field Contracts

Headless consumers may read raw field values before Scriban runs if developers map JSON incorrectly. Scriban executes in SXA rendering pipeline on CD; JSS may expose datasource fields directly to React. Decide where truncation happens:

  • Server side Scriban only: Layout Service returns final strings; React is dumb display.
  • Client truncate: duplicate logic in TypeScript; avoid unless SSR unavailable.
  • Dual: guaranteed drift; pick one source of truth.

Document in component README: “Card teaser max 120 chars enforced in HeroCard.tsx line 45″ or ” enforced in Scriban variant X”. Sidekick authors read one place.

Performance Considerations

Parent walk loops on deep trees add cost at scale. Cache parent title in custom index field populated on save if cards number in thousands on listing pages. Sidekick can suggest the cached field value at authoring time; Scriban reads flat field at delivery. Tradeoff: another field to maintain in field ownership matrix.

strip_html on large rich text bodies in card grids is expensive. Prefer dedicated teaser field Sidekick writes over truncating 2000 word body on every request.

Accessibility and AI Copy

Sidekick may generate “click here” or duplicate link text across cards. Scriban cannot fix semantic HTML errors in body rich text. Add post apply grep in Sidekick test pipeline for link text patterns. For CTA Scriban, enforce minimum text length and ban generic phrases via fallback to title when grep matches.

{{~ $badPhrases = ["click here", "read more", "learn more here"] $textLower = $text | string.downcase for $phrase in $badPhrases if $textLower == $phrase $text = i_item.title break end end
~}}

Versioning Scriban with Prompt Packs

When prompt pack v4 shortens headline max from 80 to 60 characters, update Scriban constants and author one pager same release. Tag theme git repo alongside prompt pack tag. Parallel publish test compares listing page HTML before and after; card layout CSS may assume longer strings.

Common Mistakes

  • Using i_item.field when datasource is child item in rendering; should be i_datasource.
  • Forgetting General Link query string encoding on external URLs with UTM params Sidekick adds in text field not link field.
  • html.escape only on attributes, not on rich text body where formatting is intentional.
  • Assuming Sidekick writes to display field when workflow writes to staging field only.

Experience Accelerator and Partial Design Interplay

Partial designs inject standard values authors never see unless they expand inheritance. Sidekick may write item level teaser while partial design standard value still supplies fallback CTA. Scriban must read effective values or authors see correct CTA on site but wrong field highlighted in EE. Use i_item.cta_link.raw vs resolved patterns per your SXA version docs. Test with partial design change: update standard link, verify items without item level override pick up new URL without Sidekick rerun.

GraphQL Edge Cases

GraphQL content API may expose nested fields Sidekick populates on related items. Card grid datasource pointing to children needs Scriban or resolver logic per child, not only parent. Map each rendering datasource template in author one pager appendix. Headless teams often miss that Sidekick wrote child teaser but parent component reads parent summary field only.

Debugging Scriban in Production Incidents

When legal flags a truncated disclaimer on live site, compare CM field raw value, Sidekick audit field, and CD rendered HTML in one ticket. Most incidents are Scriban strip_html removing allowed markup authors thought would show, not Sidekick inventing claims. Enable short term debug comment in Scriban variant only on staging: output which branch of fallback chain supplied value. Remove before prod promotion. Keep variant name suffix -debug forbidden in deployment script allowlist.

Teach support to collect item ID, language, rendering variant name, and prompt pack version before escalating to platform. Cuts triage from hours to minutes.

Include Scriban variant name in Sidekick author training slides. Authors who know which variant governs their template ask better questions when EE and preview diverge.

When migrating templates, export Scriban variants to git before bulk field rename. Diff variants in PR alongside template serialization to catch orphaned field references before Sidekick prompts target renamed fields.

Closing Checklist

  • General Link Scriban guards prevent empty href anchors
  • CTA fallback reads from partial design standard values when item link empty
  • Parent headline inheritance capped by depth or template type
  • Teaser fields use strip_html before truncate with documented max lengths
  • Card teaser priority chain documented and matches author one pager
  • is_blank helper used for Sidekick vs manual override field precedence
  • EE help text or display field strategy closes preview vs delivery gap
  • Meta and alt text fallbacks wired with html.escape on output
  • Author one pager includes field map, workflow, and screenshot pairs
  • Layout Service snapshot tests cover empty Sidekick field fixtures