Displays an inline status, system note, bordered row, or labeled separator in a conversation.
Installation
Install the dependencies
pnpm add cn class-variance-authorityCopy the component
Copy the following files into src/lib/components/ui/marker.
<script lang="ts">
import type { MarkerProps, MarkerState } from './types.js';
import { cn } from 'cn';
import { markerVariants } from './variants.js';
let { children, class: classProp, variant = 'default', render, ...props }: MarkerProps = $props();
const state: MarkerState = $derived({ slot: 'marker', variant });
const hostProps = $derived({ 'data-slot': 'marker', 'data-variant': variant, ...props, class: cn(markerVariants({ variant, class: classProp })) });
</script>
{#if render}
{@render render(hostProps, state, children)}
{:else}
<div {...hostProps}>{@render children?.()}</div>
{/if}<script lang="ts">
import type { MarkerContentProps } from './types.js';
import { cn } from 'cn';
let { children, class: classProp, ...props }: MarkerContentProps = $props();
</script>
<span data-slot="marker-content" {...props} class={cn('group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:hover:text-foreground *:[a]:underline *:[a]:underline-offset-3 min-w-0 wrap-break-word', classProp)}>
{@render children?.()}
</span><script lang="ts">
import type { MarkerIconProps } from './types.js';
import { cn } from 'cn';
let { children, class: classProp, ...props }: MarkerIconProps = $props();
</script>
<span data-slot="marker-icon" aria-hidden="true" {...props} class={cn("size-4 [&_svg:not([class*='size-'])]:size-4 shrink-0", classProp)}>
{@render children?.()}
</span>import type { HTMLAttributes } from 'svelte/elements';
import type { RenderSnippet } from '../shared/render.js';
import type { MarkerVariants } from './variants.js';
export type MarkerState = { slot: 'marker'; variant: MarkerVariants['variant'] };
export type MarkerProps = HTMLAttributes<HTMLDivElement> & MarkerVariants & { render?: RenderSnippet<MarkerState, HTMLDivElement> };
export type MarkerIconProps = HTMLAttributes<HTMLSpanElement>;
export type MarkerContentProps = HTMLAttributes<HTMLSpanElement>;// Adapted from shadcn-ui/ui d75a96ab; MIT: apps/docs/registry/THIRD_PARTY_NOTICES.md.
import { cva } from 'class-variance-authority';
import type { VariantProps } from 'class-variance-authority';
export const markerVariants = cva("gap-2 text-sm text-muted-foreground [a]:hover:text-foreground [a]:underline-offset-3 [a]:underline [&_svg:not([class*='size-'])]:size-4 min-h-4 text-left group/marker relative flex w-full items-center", {
variants: {
variant: {
default: '',
separator: 'before:h-px before:min-w-0 before:flex-1 before:bg-border after:h-px after:min-w-0 after:flex-1 after:bg-border before:mr-1 after:ml-1',
border: 'border-b border-border pb-2',
},
},
});
export type MarkerVariants = VariantProps<typeof markerVariants>;import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
/**
* Replaces a part's default element, like the `render` snippets of Sveltery Base.
* Spread `props` onto the host element and render `children` inside it.
* `Host` is the element the part renders by default, so its typed event handlers carry over.
*/
export type RenderSnippet<State, Host extends HTMLElement = HTMLElement> = Snippet<[props: HTMLAttributes<Host>, state: State, children: Snippet | undefined]>;export { default as Marker } from './Marker.svelte';
export { default as MarkerIcon } from './MarkerIcon.svelte';
export { default as MarkerContent } from './MarkerContent.svelte';
export { markerVariants } from './variants.js';
export type { MarkerVariants } from './variants.js';
export type { MarkerProps, MarkerState, MarkerIconProps, MarkerContentProps } from './types.js';Update the import paths
Change the imports to match your project setup.
Usage
<script lang="ts">
import { Marker, MarkerContent, MarkerIcon } from '$lib/components/ui/marker';
</script><Marker variant="separator">
<MarkerContent>Worked for 42s</MarkerContent>
</Marker>Link
Pass a render snippet to render the marker as a link or a button. Spread props onto it and render children inside it.
<Marker>
{#snippet render(props, state, children)}
<a href="/history" {...props}>{@render children?.()}</a>
{/snippet}
<MarkerContent>View history</MarkerContent>
</Marker>