Skip to content
edmi-ui

Marker

Inline status, system note, bordered row or labeled separator inside a conversation.

StackBlitz ↗StackBlitz ↗StackBlitz ↗
Today
Keeper rebalanced MAG4 · 3 trades
Transaction confirmed · slot 318,204,551
Today
Keeper rebalanced MAG4 · 3 trades
Transaction confirmed · slot 318,204,551
Today
Keeper rebalanced MAG4 · 3 trades
Transaction confirmed · slot 318,204,551
Terminal window
npx shadcn@latest add @edmi-ui/marker
Terminal window
pnpm dlx shadcn@latest add @edmi-ui/marker
Terminal window
yarn dlx shadcn@latest add @edmi-ui/marker
Terminal window
bunx shadcn@latest add @edmi-ui/marker

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-vue@latest add @edmi-ui/marker
Terminal window
pnpm dlx shadcn-vue@latest add @edmi-ui/marker
Terminal window
yarn dlx shadcn-vue@latest add @edmi-ui/marker
Terminal window
bunx shadcn-vue@latest add @edmi-ui/marker

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.json
Terminal window
yarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.json
Terminal window
bunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/marker.json

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

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>
registry/ui/marker.tsx
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 };
registry/ui/marker/Marker.vue
<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>
registry/ui/marker/MarkerContent.vue
<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>
registry/ui/marker/MarkerIcon.vue
<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>
registry/ui/marker/index.ts
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>;
src/lib/registry/ui/marker/marker-content.svelte
<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>
src/lib/registry/ui/marker/marker-icon.svelte
<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>
src/lib/registry/ui/marker/marker.svelte
<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}
src/lib/registry/ui/marker/index.ts
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
  • 12.5px muted text and a 14px icon, matching the conversation board.
  • Svelte: Marker has no render prop. Pass href to render an <a>.