Marker
Inline status, system note, bordered row or labeled separator inside a conversation.
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker";import { IconPlaceholder } from "@/edmi/icon-placeholder";
export default function Demo() { return ( <div className="flex w-full max-w-md flex-col gap-4"> <Marker variant="separator"> <MarkerContent>Today</MarkerContent> </Marker> <Marker> <MarkerIcon> <IconPlaceholder lucide="SparklesIcon" tabler="IconSparkles" hugeicons="SparklesIcon" phosphor="SparkleIcon" remixicon="RiSparklingLine" /> </MarkerIcon> <MarkerContent>Keeper rebalanced MAG4 · 3 trades</MarkerContent> </Marker> <Marker variant="border"> <MarkerIcon> <IconPlaceholder lucide="CircleCheckIcon" tabler="IconCircleCheck" hugeicons="CheckmarkCircle02Icon" phosphor="CheckCircleIcon" remixicon="RiCheckboxCircleLine" /> </MarkerIcon> <MarkerContent>Transaction confirmed · slot 318,204,551</MarkerContent> </Marker> </div> );}<script setup lang="ts">import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker";import { CircleCheckIcon, SparklesIcon } from "@lucide/vue";</script>
<template> <div class="flex w-full max-w-md flex-col gap-4"> <Marker variant="separator"> <MarkerContent>Today</MarkerContent> </Marker> <Marker> <MarkerIcon><SparklesIcon /></MarkerIcon> <MarkerContent>Keeper rebalanced MAG4 · 3 trades</MarkerContent> </Marker> <Marker variant="border"> <MarkerIcon><CircleCheckIcon /></MarkerIcon> <MarkerContent>Transaction confirmed · slot 318,204,551</MarkerContent> </Marker> </div></template><script lang="ts"> import * as Marker from "$lib/components/ui/marker";</script>
<div class="flex w-full max-w-md flex-col gap-4"> <Marker.Root variant="separator"> <Marker.Content>Today</Marker.Content> </Marker.Root> <Marker.Root> <Marker.Icon>✦</Marker.Icon> <Marker.Content>Keeper rebalanced MAG4 · 3 trades</Marker.Content> </Marker.Root> <Marker.Root variant="border"> <Marker.Icon>✓</Marker.Icon> <Marker.Content>Transaction confirmed · slot 318,204,551</Marker.Content> </Marker.Root></div>Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/markerpnpm dlx shadcn@latest add @edmi-ui/markeryarn dlx shadcn@latest add @edmi-ui/markerbunx shadcn@latest add @edmi-ui/markerPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @base-ui/react class-variance-authorityTerminal window pnpm add @base-ui/react class-variance-authorityTerminal window yarn add @base-ui/react class-variance-authorityTerminal window bun add @base-ui/react class-variance-authorityCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/markerpnpm dlx shadcn-vue@latest add @edmi-ui/markeryarn dlx shadcn-vue@latest add @edmi-ui/markerbunx shadcn-vue@latest add @edmi-ui/markerPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install reka-ui class-variance-authorityTerminal window pnpm add reka-ui class-variance-authorityTerminal window yarn add reka-ui class-variance-authorityTerminal window bun add reka-ui class-variance-authorityCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Copy the code from Component source into your project and update the import paths to match your aliases.
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker";
<div className="flex w-full max-w-md flex-col gap-4"> <Marker variant="separator"> <MarkerContent>Today</MarkerContent> </Marker> <Marker> <MarkerIcon> <SparkleIcon /> </MarkerIcon> <MarkerContent>Keeper rebalanced MAG4 · 3 trades</MarkerContent> </Marker> <Marker variant="border"> <MarkerIcon> <CheckCircleIcon /> </MarkerIcon> <MarkerContent>Transaction confirmed · slot 318,204,551</MarkerContent> </Marker></div><script setup lang="ts">import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker";</script>
<template> <div class="flex w-full max-w-md flex-col gap-4"> <Marker variant="separator"> <MarkerContent>Today</MarkerContent> </Marker> <Marker> <MarkerIcon><SparklesIcon /></MarkerIcon> <MarkerContent>Keeper rebalanced MAG4 · 3 trades</MarkerContent> </Marker> <Marker variant="border"> <MarkerIcon><CircleCheckIcon /></MarkerIcon> <MarkerContent>Transaction confirmed · slot 318,204,551</MarkerContent> </Marker> </div></template><script lang="ts"> import * as Marker from "$lib/components/ui/marker";</script>
<div class="flex w-full max-w-md flex-col gap-4"> <Marker.Root variant="separator"> <Marker.Content>Today</Marker.Content> </Marker.Root> <Marker.Root> <Marker.Icon>✦</Marker.Icon> <Marker.Content>Keeper rebalanced MAG4 · 3 trades</Marker.Content> </Marker.Root> <Marker.Root variant="border"> <Marker.Icon>✓</Marker.Icon> <Marker.Content>Transaction confirmed · slot 318,204,551</Marker.Content> </Marker.Root></div>Component source
Section titled “Component source”import { mergeProps } from "@base-ui/react/merge-props";import { useRender } from "@base-ui/react/use-render";import { cva, type VariantProps } from "class-variance-authority";import { cn } from "cn";import type * as React from "react";
const markerVariants = cva( "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-[12.5px] text-muted-foreground [&_svg:not([class*='size-'])]:size-3.5 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground", { variants: { variant: { default: "", separator: "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border", border: "border-b border-border pb-2.5", }, }, defaultVariants: { variant: "default" }, },);
function Marker({ className, variant = "default", render, ...props}: useRender.ComponentProps<"div"> & VariantProps<typeof markerVariants>) { return useRender({ defaultTagName: "div", props: mergeProps<"div">( { className: cn(markerVariants({ variant }), className), }, props, ), render, state: { slot: "marker", variant, }, });}
function MarkerIcon({ className, ...props }: React.ComponentProps<"span">) { return ( <span data-slot="marker-icon" aria-hidden="true" className={cn( "inline-flex size-3.5 shrink-0 items-center justify-center [&_svg:not([class*='size-'])]:size-3.5", className, )} {...props} /> );}
function MarkerContent({ className, ...props }: React.ComponentProps<"span">) { return ( <span data-slot="marker-content" className={cn( "min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", className, )} {...props} /> );}
export { Marker, MarkerContent, MarkerIcon, markerVariants };<script setup lang="ts">import type { PrimitiveProps } from "reka-ui"import type { HTMLAttributes } from "vue"import type { MarkerVariants } from "."import { Primitive } from "reka-ui"import { cn } from "@/registry/edmi/lib/utils"import { markerVariants } from "."
interface Props extends PrimitiveProps { variant?: MarkerVariants["variant"] class?: HTMLAttributes["class"]}
const props = withDefaults(defineProps<Props>(), { as: "div",})</script>
<template> <Primitive data-slot="marker" :data-variant="variant" :as="as" :as-child="asChild" :class="cn(markerVariants({ variant }), props.class)" > <slot /> </Primitive></template><script setup lang="ts">import type { HTMLAttributes } from "vue"import { cn } from "@/registry/edmi/lib/utils"
interface Props { class?: HTMLAttributes["class"]}
const props = defineProps<Props>()</script>
<template> <span data-slot="marker-content" :class="cn('min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground', props.class)" > <slot /> </span></template><script setup lang="ts">import type { HTMLAttributes } from "vue"import { cn } from "@/registry/edmi/lib/utils"
interface Props { class?: HTMLAttributes["class"]}
const props = defineProps<Props>()</script>
<template> <span data-slot="marker-icon" aria-hidden="true" :class="cn(`inline-flex size-3.5 shrink-0 items-center justify-center [&_svg:not([class*='size-'])]:size-3.5`, props.class)" > <slot /> </span></template>import type { VariantProps } from "class-variance-authority";import { cva } from "class-variance-authority";
export { default as Marker } from "./Marker.vue";export { default as MarkerContent } from "./MarkerContent.vue";export { default as MarkerIcon } from "./MarkerIcon.vue";
export const markerVariants = cva( "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-[12.5px] text-muted-foreground [&_svg:not([class*='size-'])]:size-3.5 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground", { variants: { variant: { default: "", separator: "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border", border: "border-b border-border pb-2.5", }, }, defaultVariants: { variant: "default" }, },);export type MarkerVariants = VariantProps<typeof markerVariants>;<script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();</script>
<span bind:this={ref} data-slot="marker-content" class={cn( "min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", className )} {...restProps}> {@render children?.()}</span><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();</script>
<span bind:this={ref} data-slot="marker-icon" aria-hidden="true" class={cn( "inline-flex size-3.5 shrink-0 items-center justify-center [&_svg:not([class*='size-'])]:size-3.5", className )} {...restProps}> {@render children?.()}</span><script lang="ts" module> import { type VariantProps, tv } from "tailwind-variants";
export const markerVariants = tv({ base: "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-[12.5px] text-muted-foreground [&_svg:not([class*='size-'])]:size-3.5 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground", variants: { variant: { default: "", separator: "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border", border: "border-b border-border pb-2.5", }, }, defaultVariants: { variant: "default" }, });
export type MarkerVariant = VariantProps<typeof markerVariants>["variant"];</script>
<script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAnchorAttributes, HTMLAttributes } from "svelte/elements";
// Renders a `<div>`; pass `href` to render an `<a>`. let { ref = $bindable(null), class: className, variant = "default", href = undefined, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLElement>> & WithElementRef<HTMLAnchorAttributes> & { variant?: MarkerVariant } = $props();</script>
{#if href} <a bind:this={ref} data-slot="marker" data-variant={variant} class={cn(markerVariants({ variant }), className)} {href} {...restProps} > {@render children?.()} </a>{:else} <div bind:this={ref} data-slot="marker" data-variant={variant} class={cn(markerVariants({ variant }), className)} {...restProps} > {@render children?.()} </div>{/if}import Root, { type MarkerVariant, markerVariants } from "./marker.svelte";import Content from "./marker-content.svelte";import Icon from "./marker-icon.svelte";
export { Content, Content as MarkerContent, Icon, Icon as MarkerIcon, type MarkerVariant, markerVariants, Root, // Root as Marker,};| Part | Prop | Type | Default |
|---|---|---|---|
| Marker | variant | default | border | separator |
default |
| Marker | render | ReactElement |
none |
| MarkerIcon, MarkerContent | span props |
✦ Edmi additions
Section titled “✦ Edmi additions”- 12.5px muted text and a 14px icon, matching the conversation board.
Vue / Svelte differences
Section titled “Vue / Svelte differences”- Svelte:
Markerhas norenderprop. Passhrefto render an<a>.