Divider
Horizontal content divider with single-line, double-line, filled, and aligned variants.
Variants
Single, double, filled, and with content.
or
Recent
function DividerVariants() {
return (
<div className="flex w-full max-w-md flex-col gap-6">
<Divider />
<Divider variant="double" />
<Divider variant="fill" />
<Divider>or</Divider>
<Divider align="start">Recent</Divider>
</div>
);
}function DividerVariants() {
return (
<div className="flex w-full max-w-md flex-col gap-6">
<Divider />
<Divider variant="double" />
<Divider variant="fill" />
<Divider>or</Divider>
<Divider align="start">Recent</Divider>
</div>
);
}Installation
npx shadcn@latest add https://boardcn.dev/r/divider.jsonnpx shadcn@latest add https://boardcn.dev/r/divider.jsonBoardCN dependencies
The CLI installs these for you — you do not need to add them yourself.
Source
The file the CLI copies into your project.
import type { HTMLAttributes, ReactNode, Ref } from "react";
import { cx, sortCx } from "@/utils/cx";
export type DividerVariant = "single" | "double" | "fill";
export type DividerAlign = "start" | "center" | "end";
export interface DividerProps
extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
/** Single hairline, two framing hairlines, or a soft filled strip. */
variant?: DividerVariant;
/** Positions the divider content while keeping the remaining line flexible. */
align?: DividerAlign;
/** Text, a button, or any compact control placed in the divider. */
children?: ReactNode;
/** Extra classes for the content wrapper. */
contentClassName?: string;
ref?: Ref<HTMLDivElement>;
}
const styles = sortCx({
root: "w-full",
line: "h-px min-w-0 flex-1 bg-separator-border",
content: "shrink-0 text-body-medium text-text-secondary",
align: {
start: "justify-start",
center: "justify-center",
end: "justify-end",
},
withContent: {
single: "flex items-center gap-3",
double: "flex items-center border-y border-separator-border py-2.5",
fill: "flex items-center rounded-2lg bg-background-secondary-default px-4 py-2.5",
},
empty: {
single: "h-px bg-separator-border",
double: "h-2 border-y border-separator-border",
fill: "h-2 rounded-full bg-background-secondary-default",
},
});
/**
* Horizontal content divider with three BoardCN surface treatments.
*
* `single` places content within one continuous hairline, `double` frames it
* with a line above and below, and `fill` uses the secondary surface color.
* Children stay completely composable, so labels, buttons, and small controls
* can share the same primitive.
*/
export function Divider({
variant = "single",
align = "center",
children,
contentClassName,
className,
ref,
...props
}: DividerProps) {
const hasContent = children !== undefined && children !== null;
if (!hasContent) {
return (
<div
ref={ref}
role="separator"
aria-orientation="horizontal"
data-variant={variant}
className={cx(styles.root, styles.empty[variant], className)}
{...props}
/>
);
}
const showLeadingLine = variant === "single" && align !== "start";
const showTrailingLine = variant === "single" && align !== "end";
return (
<div
ref={ref}
data-variant={variant}
data-align={align}
className={cx(
styles.root,
styles.withContent[variant],
styles.align[align],
className,
)}
{...props}
>
{showLeadingLine ? <span aria-hidden className={styles.line} /> : null}
<div className={cx(styles.content, contentClassName)}>{children}</div>
{showTrailingLine ? <span aria-hidden className={styles.line} /> : null}
</div>
);
}import type { HTMLAttributes, ReactNode, Ref } from "react";
import { cx, sortCx } from "@/utils/cx";
export type DividerVariant = "single" | "double" | "fill";
export type DividerAlign = "start" | "center" | "end";
export interface DividerProps
extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
/** Single hairline, two framing hairlines, or a soft filled strip. */
variant?: DividerVariant;
/** Positions the divider content while keeping the remaining line flexible. */
align?: DividerAlign;
/** Text, a button, or any compact control placed in the divider. */
children?: ReactNode;
/** Extra classes for the content wrapper. */
contentClassName?: string;
ref?: Ref<HTMLDivElement>;
}
const styles = sortCx({
root: "w-full",
line: "h-px min-w-0 flex-1 bg-separator-border",
content: "shrink-0 text-body-medium text-text-secondary",
align: {
start: "justify-start",
center: "justify-center",
end: "justify-end",
},
withContent: {
single: "flex items-center gap-3",
double: "flex items-center border-y border-separator-border py-2.5",
fill: "flex items-center rounded-2lg bg-background-secondary-default px-4 py-2.5",
},
empty: {
single: "h-px bg-separator-border",
double: "h-2 border-y border-separator-border",
fill: "h-2 rounded-full bg-background-secondary-default",
},
});
/**
* Horizontal content divider with three BoardCN surface treatments.
*
* `single` places content within one continuous hairline, `double` frames it
* with a line above and below, and `fill` uses the secondary surface color.
* Children stay completely composable, so labels, buttons, and small controls
* can share the same primitive.
*/
export function Divider({
variant = "single",
align = "center",
children,
contentClassName,
className,
ref,
...props
}: DividerProps) {
const hasContent = children !== undefined && children !== null;
if (!hasContent) {
return (
<div
ref={ref}
role="separator"
aria-orientation="horizontal"
data-variant={variant}
className={cx(styles.root, styles.empty[variant], className)}
{...props}
/>
);
}
const showLeadingLine = variant === "single" && align !== "start";
const showTrailingLine = variant === "single" && align !== "end";
return (
<div
ref={ref}
data-variant={variant}
data-align={align}
className={cx(
styles.root,
styles.withContent[variant],
styles.align[align],
className,
)}
{...props}
>
{showLeadingLine ? <span aria-hidden className={styles.line} /> : null}
<div className={cx(styles.content, contentClassName)}>{children}</div>
{showTrailingLine ? <span aria-hidden className={styles.line} /> : null}
</div>
);
}Props
Generated from the component's TypeScript types. Standard DOM and React Aria props are omitted.
Divider
Horizontal content divider with three BoardCN surface treatments. `single` places content within one continuous hairline, `double` frames it with a line above and below, and `fill` uses the secondary surface color. Children stay completely composable, so labels, buttons, and small controls can share the same primitive.
| Prop | Type | Default | Description |
|---|---|---|---|
| align | "start" | "center" | "end" | center | Positions the divider content while keeping the remaining line flexible. |
| children | ReactNode | — | Text, a button, or any compact control placed in the divider. |
| contentClassName | string | — | Extra classes for the content wrapper. |
| variant | "single" | "double" | "fill" | single | Single hairline, two framing hairlines, or a soft filled strip. |