Extending the Schema
The plugin provides a minimal core schema that you can extend with custom fields for your specific use case, such as API documentation, SDK docs, or product documentation.
Core Fields
Section titled “Core Fields”The plugin includes these fields by default:
| Field | Type | Description |
|---|---|---|
label | string | Display name (required) |
description | string | Short description |
color | string | Badge color |
icon | string | Emoji or short text |
permalink | string | Custom URL slug |
hidden | boolean | Hide from tag index |
difficulty | enum | Skill level (beginner/intermediate/advanced) |
contentType | enum | Type of content (lecture/lab/assignment/project/reference/tutorial/assessment) |
prerequisites | string[] | Prerequisite tag IDs |
Adding Custom Fields
Section titled “Adding Custom Fields”Step 1: Create a Custom Schema
Section titled “Step 1: Create a Custom Schema”Create a schema file in your project that extends the base schema:
import { z } from 'astro/zod';import { tagDefinitionSchema } from 'starlight-tags';
export const customTagSchema = tagDefinitionSchema.extend({ // API documentation fields status: z.enum(['stable', 'beta', 'deprecated']).optional(), version: z.string().optional(), apiArea: z.string().optional(), // e.g., "Security", "Data", "Payments" breaking: z.boolean().optional(),});
export type CustomTag = z.infer<typeof customTagSchema>;Step 2: Use Custom Fields in tags.yml
Section titled “Step 2: Use Custom Fields in tags.yml”tags: authentication: label: "Authentication" description: "API authentication methods" apiArea: "Security" status: "stable" version: "1.0"
oauth2-pkce: label: "OAuth 2.0 PKCE" description: "Proof Key for Code Exchange flow" apiArea: "Security" status: "stable" version: "2.0"
legacy-auth: label: "Legacy Authentication" description: "Deprecated authentication method" apiArea: "Security" status: "deprecated" version: "1.0" breaking: trueStep 3: Access Custom Fields in Components
Section titled “Step 3: Access Custom Fields in Components”---import type { ProcessedTag } from 'starlight-tags/schemas/tags';import type { CustomTag } from '../config/tags-schema';
interface Props { tagId: string;}
const { tagId } = Astro.props;
// Get tag data from middlewareconst { tags } = Astro.locals.starlightTags;const baseTag = tags.get(tagId);
// Cast to custom type to access extended fieldsconst tag = baseTag as (ProcessedTag & CustomTag) | undefined;---
{tag && ( <span class="tag" data-status={tag.status}> {tag.icon} {tag.label}
{tag.status === 'deprecated' && ( <span class="badge deprecated">Deprecated</span> )}
{tag.status === 'beta' && ( <span class="badge beta">Beta</span> )}
{tag.version && ( <span class="version">v{tag.version}</span> )} </span>)}
<style> .badge.deprecated { background: #dc2626; color: white; } .badge.beta { background: #f59e0b; color: white; } .version { color: #6b7280; font-size: 0.875em; }</style>Example Schemas
Section titled “Example Schemas”API/SDK Documentation
Section titled “API/SDK Documentation”const apiTagSchema = tagDefinitionSchema.extend({ status: z.enum(['stable', 'beta', 'deprecated', 'experimental']).optional(), version: z.string().optional(), apiArea: z.string().optional(), // e.g., "Security", "Data", "Payments" breaking: z.boolean().optional(), sdks: z.array(z.enum(['js', 'python', 'go', 'java', 'ruby'])).optional(), apiVersion: z.enum(['v1', 'v2', 'v3']).optional(),});Product Documentation
Section titled “Product Documentation”const productTagSchema = tagDefinitionSchema.extend({ product: z.string().optional(), planTier: z.enum(['free', 'pro', 'enterprise']).optional(), feature: z.string().optional(), releaseDate: z.string().optional(),});Open Source Project
Section titled “Open Source Project”const ossTagSchema = tagDefinitionSchema.extend({ complexity: z.enum(['low', 'medium', 'high']).optional(), goodFirstIssue: z.boolean().optional(), area: z.string().optional(), maintainer: z.string().optional(),});How Custom Fields Flow Through the System
Section titled “How Custom Fields Flow Through the System”tags.yml TagProcessor Your Components------------------------------------------------------------------------------
+----------------+ +----------------+ +------------------+| authentication:| | { | | <CustomTagBadge> || label: "Auth"| -> | id: "auth" | -> | {tag.label} || status: "ok" | parse | label: "Auth"| render | {tag.status} || version: "2" | | status: "ok" | | {tag.version} |+----------------+ | version: "2" | +------------------+ | ... | Your Schema | } | Your Component validates +----------------+ decides how to custom fields All fields render them passed throughImportant Notes
Section titled “Important Notes”-
Import paths: You can import from either path:
// Main entry pointimport { tagDefinitionSchema, type ProcessedTag } from 'starlight-tags';// Or subpath exportimport { tagDefinitionSchema, type ProcessedTag } from 'starlight-tags/schemas/tags'; -
The plugin’s built-in components (
TagBadge,TagsList, etc.) only render core fields. Create your own components to display custom fields. -
When accessing tags with custom fields, cast to your custom type:
// Using middleware (recommended)const { tags } = Astro.locals.starlightTags;const tag = tags.get('auth') as (ProcessedTag & CustomTag);// Or with an arrayconst { allTagsSorted } = Astro.locals.starlightTags;const customTags = allTagsSorted as (ProcessedTag & CustomTag)[]; -
Zod validates your
tags.ymlagainst the schema at build time. Invalid custom field values will cause build errors. -
Custom fields are optional, so handle cases where they might be
undefinedin your components.
Next Steps
Section titled “Next Steps”- See the live demo for a working example with product documentation fields
- Learn about the core tag properties
- See how to use components to display tags
- Understand the auto-generated routes