Channel Welcome
The header that opens a channel, shown above its very first message.
The header that opens a channel, shown above its very first message. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.
import {
ChannelWelcome,
ChannelWelcomeAction,
ChannelWelcomeDate,
ChannelWelcomeDescription,
ChannelWelcomeIcon,
ChannelWelcomeTitle,
} from "@/registry/bases/newt/ui/channel-welcome"
export default function ChannelWelcomeDemo() {
return (
<ChannelWelcome>
<ChannelWelcomeIcon />
<ChannelWelcomeTitle>Welcome to #general!</ChannelWelcomeTitle>
<ChannelWelcomeDescription>
This is the start of the #general channel. Say hello and tell us what
you are building.
</ChannelWelcomeDescription>
<ChannelWelcomeAction>
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="currentColor">
<path d="m11.3 1.7 3 3-8.4 8.4-3.6.6.6-3.6 8.4-8.4Z" />
</svg>
Edit Channel
</ChannelWelcomeAction>
<ChannelWelcomeDate dateTime="2026-01-14">
14 January 2026
</ChannelWelcomeDate>
</ChannelWelcome>
)
}<script setup lang="ts">
import {
ChannelWelcome,
ChannelWelcomeAction,
ChannelWelcomeDate,
ChannelWelcomeDescription,
ChannelWelcomeIcon,
ChannelWelcomeTitle,
} from "~~/registry/bases/newt/ui/channel-welcome"
</script>
<template>
<ChannelWelcome>
<ChannelWelcomeIcon />
<ChannelWelcomeTitle>Welcome to #general!</ChannelWelcomeTitle>
<ChannelWelcomeDescription>
This is the start of the #general channel. Say hello and tell us what you
are building.
</ChannelWelcomeDescription>
<ChannelWelcomeAction>
<svg viewBox="0 0 16 16" class="h-4 w-4" fill="currentColor">
<path d="m11.3 1.7 3 3-8.4 8.4-3.6.6.6-3.6 8.4-8.4Z" />
</svg>
Edit Channel
</ChannelWelcomeAction>
<ChannelWelcomeDate date-time="2026-01-14">
14 January 2026
</ChannelWelcomeDate>
</ChannelWelcome>
</template>Installation
pnpm dlx newtui@latest add channel-welcomenpx newtui@latest add channel-welcomeyarn dlx newtui@latest add channel-welcomebunx newtui@latest add channel-welcomeCopy the source into your project
import * as React from "react"
import { cn } from "@/lib/utils"
/* The header that opens a channel, shown above its very first message. */
const ChannelWelcome = React.forwardRef<
HTMLElement,
React.ComponentProps<"section">
>(({ className, ...props }, ref) => (
<section ref={ref} className={cn("px-4 pb-2 pt-10", className)} {...props} />
))
ChannelWelcome.displayName = "ChannelWelcome"
const ChannelWelcomeIcon = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, children = "#", ...props }, ref) => (
<div
ref={ref}
aria-hidden="true"
className={cn(
"mb-4 flex h-[68px] w-[68px] items-center justify-center rounded-full bg-newt-bg-elevated text-[32px] font-bold leading-none text-newt-text-primary",
className
)}
{...props}
>
{children}
</div>
))
ChannelWelcomeIcon.displayName = "ChannelWelcomeIcon"
const ChannelWelcomeTitle = React.forwardRef<
HTMLHeadingElement,
React.ComponentProps<"h2">
>(({ className, ...props }, ref) => (
<h2
ref={ref}
className={cn(
"text-[28px] font-bold leading-tight text-newt-text-primary",
className
)}
{...props}
/>
))
ChannelWelcomeTitle.displayName = "ChannelWelcomeTitle"
const ChannelWelcomeDescription = React.forwardRef<
HTMLParagraphElement,
React.ComponentProps<"p">
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("mt-2 text-base text-newt-text-muted", className)}
{...props}
/>
))
ChannelWelcomeDescription.displayName = "ChannelWelcomeDescription"
const ChannelWelcomeAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button">
>(({ className, type = "button", ...props }, ref) => (
<button
ref={ref}
type={type}
className={cn(
"mt-3 inline-flex cursor-pointer items-center gap-2 rounded-sm border-0 bg-newt-bg-elevated px-4 py-1.5 text-sm font-medium text-newt-text-primary transition-colors duration-fast ease-newt",
"hover:bg-newt-bg-hover",
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-newt-text-link",
className
)}
{...props}
/>
))
ChannelWelcomeAction.displayName = "ChannelWelcomeAction"
export interface ChannelWelcomeDateProps extends Omit<
React.ComponentProps<"div">,
"children"
> {
/** Machine-readable date for the rendered `<time>` element. */
dateTime?: string
children?: React.ReactNode
}
/* Creation date, centred between two hairlines. */
const ChannelWelcomeDate = React.forwardRef<
HTMLDivElement,
ChannelWelcomeDateProps
>(({ className, dateTime, children, ...props }, ref) => (
<div
ref={ref}
className={cn(
"mt-6 grid grid-cols-[1fr_auto_1fr] items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-newt-text-muted",
"[&>span]:h-px [&>span]:bg-newt-border",
className
)}
{...props}
>
<span aria-hidden="true" />
<time dateTime={dateTime}>{children}</time>
<span aria-hidden="true" />
</div>
))
ChannelWelcomeDate.displayName = "ChannelWelcomeDate"
export {
ChannelWelcome,
ChannelWelcomeIcon,
ChannelWelcomeTitle,
ChannelWelcomeDescription,
ChannelWelcomeAction,
ChannelWelcomeDate,
}<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<section :class="cn('px-4 pb-2 pt-10', props.class)">
<slot />
</section>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
aria-hidden="true"
:class="
cn(
'mb-4 flex h-[68px] w-[68px] items-center justify-center rounded-full bg-newt-bg-elevated text-[32px] font-bold leading-none text-newt-text-primary',
props.class
)
"
>
<slot>#</slot>
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<h2
:class="
cn(
'text-[28px] font-bold leading-tight text-newt-text-primary',
props.class
)
"
>
<slot />
</h2>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<p :class="cn('mt-2 text-base text-newt-text-muted', props.class)">
<slot />
</p>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<button
type="button"
:class="
cn(
'mt-3 inline-flex cursor-pointer items-center gap-2 rounded-sm border-0 bg-newt-bg-elevated px-4 py-1.5 text-sm font-medium text-newt-text-primary transition-colors duration-fast ease-newt',
'hover:bg-newt-bg-hover',
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-newt-text-link',
props.class
)
"
>
<slot />
</button>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
/** Machine-readable date for the rendered `<time>` element. */
dateTime?: string
}>()
</script>
<template>
<!-- Creation date, centred between two hairlines. -->
<div
:class="
cn(
'mt-6 grid grid-cols-[1fr_auto_1fr] items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-newt-text-muted',
'[&>span]:h-px [&>span]:bg-newt-border',
props.class
)
"
>
<span aria-hidden="true" />
<time :datetime="props.dateTime"><slot /></time>
<span aria-hidden="true" />
</div>
</template>export { default as ChannelWelcome } from "./ChannelWelcome.vue"
export { default as ChannelWelcomeIcon } from "./ChannelWelcomeIcon.vue"
export { default as ChannelWelcomeTitle } from "./ChannelWelcomeTitle.vue"
export { default as ChannelWelcomeDescription } from "./ChannelWelcomeDescription.vue"
export { default as ChannelWelcomeAction } from "./ChannelWelcomeAction.vue"
export { default as ChannelWelcomeDate } from "./ChannelWelcomeDate.vue"Update the import paths
The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.
Usage
import { ChannelWelcome } from "@/components/ui/channel-welcome"
export function Example() {
return <ChannelWelcome />
}<script setup lang="ts">
import { ChannelWelcome, ChannelWelcomeIcon, ChannelWelcomeTitle, ChannelWelcomeDescription, ChannelWelcomeAction, ChannelWelcomeDate } from "@/components/ui/channel-welcome"
</script>
<template>
<ChannelWelcome />
</template>API reference
ChannelWelcomeDate
dateTime?string | undefined
Machine-readable date for the rendered `<time>` element.
string | undefinedchildren?React.ReactNode | undefined
Optional children value.
React.ReactNode | undefinedThe registry exports ChannelWelcome, ChannelWelcomeIcon, ChannelWelcomeTitle, ChannelWelcomeDescription, ChannelWelcomeAction, ChannelWelcomeDate. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.
Accessibility
Preserve the native semantics of the rendered elements and pass through ARIA attributes when the surrounding context needs a label or description. Any interactive child needs a visible focus indicator, and meaning must not rely on colour alone.
Tokens
Channel Welcome reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer.