Separator
Visually or semantically separates content.
Usage
Horizontal
RubyUI
An open-source UI component library.
Beautifully designed Phlex components that you can customize, extend, and build on.
div(class: "flex flex-col gap-4 text-sm") do
div(class: "flex flex-col gap-1") do
div(class: "leading-none font-medium") { "RubyUI" }
div(class: "text-muted-foreground") { "An open-source UI component library." }
end
Separator()
div { "Beautifully designed Phlex components that you can customize, extend, and build on." }
end
Vertical
A vertical separator stretches to the height of its flex row.
Blog
Docs
Source
div(class: "flex h-5 items-center gap-4 text-sm") do
div { "Blog" }
Separator(orientation: :vertical)
div { "Docs" }
Separator(orientation: :vertical)
div { "Source" }
end
Vertical menu
No fixed height needed: the separator fills the row.
SettingsManage preferences
AccountProfile & security
HelpSupport & docs
div(class: "flex items-center gap-2 text-sm md:gap-4") do
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Settings" }
span(class: "text-xs text-muted-foreground") { "Manage preferences" }
end
Separator(orientation: :vertical)
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Account" }
span(class: "text-xs text-muted-foreground") { "Profile & security" }
end
Separator(orientation: :vertical)
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Help" }
span(class: "text-xs text-muted-foreground") { "Support & docs" }
end
end
In list
- Item 1
- Value 1
- Item 2
- Value 2
- Item 3
- Value 3
div(class: "flex flex-col gap-2 text-sm") do
dl(class: "flex items-center justify-between") do
dt { "Item 1" }
dd(class: "text-muted-foreground") { "Value 1" }
end
Separator()
dl(class: "flex items-center justify-between") do
dt { "Item 2" }
dd(class: "text-muted-foreground") { "Value 2" }
end
Separator()
dl(class: "flex items-center justify-between") do
dt { "Item 3" }
dd(class: "text-muted-foreground") { "Value 3" }
end
end
Decorative
Separators are announced by screen readers (role="separator" with aria-orientation). Pass decorative: true for a purely visual line (role="none").
Profile
Settings
div(class: "flex h-5 items-center gap-4 text-sm") do
div { "Profile" }
Separator(orientation: :vertical, decorative: true)
div { "Settings" }
end
As <hr>
as: :hr renders the native separator element. Its separator role is implicit, so no role attribute is added.
Section one
Section two
div(class: "flex flex-col gap-4 text-sm") do
div { "Section one" }
Separator(as: :hr)
div { "Section two" }
end
Installation
Using RubyUI CLI
Run the install command
rails g ruby_ui:component Separator
Manual installation
1
Add RubyUI::Separator to app/components/ruby_ui/separator/separator.rb
# frozen_string_literal: true
module RubyUI
class Separator < Base
ORIENTATIONS = %i[horizontal vertical].freeze
# decorative: true renders role="none" for a purely visual line (hidden
# from assistive tech). shadcn (Base UI) has no such prop: it always
# renders a semantic separator, which is the default here too.
def initialize(as: :div, orientation: :horizontal, decorative: false, **attrs)
raise ArgumentError, "Invalid orientation: #{orientation}" unless ORIENTATIONS.include?(orientation.to_sym)
@as = as
@orientation = orientation.to_sym
@decorative = decorative
super(**attrs)
end
def view_template(&)
tag(@as, **attrs, &)
end
private
def default_attrs
{
role: role,
aria: {orientation: aria_orientation},
data: {slot: "separator", orientation: @orientation},
class: [
"shrink-0 bg-border",
orientation_classes,
hr_classes
]
}
end
# <hr> already has the separator role: an explicit one would be redundant.
def role
return "none" if @decorative
"separator" unless hr?
end
# The separator role's implicit aria-orientation is horizontal, so <hr>
# only needs it when vertical. A decorative line has no orientation.
def aria_orientation
return if @decorative
return if hr? && @orientation == :horizontal
@orientation.to_s
end
def hr?
@as.to_sym == :hr
end
# Tailwind's preflight sets hr { height: 0; border-top-width: 1px }: drop the
# border (h-px already draws the line) and, when vertical, the fixed height,
# or self-stretch can't stretch it.
def hr_classes
return unless hr?
return "border-0 h-auto" if @orientation == :vertical
"border-0"
end
# shadcn keys these on data-orientation via its data-horizontal:/data-vertical:
# custom variants, which RubyUI's Tailwind setup doesn't define; the classes are
# picked here instead. self-stretch (not h-full) fills a flex row with no fixed height.
def orientation_classes
return "h-px w-full" if @orientation == :horizontal
"w-px self-stretch"
end
end
end
2
Add RubyUI::SeparatorDocs to app/components/ruby_ui/separator/separator_docs.rb
# frozen_string_literal: true
class Views::Docs::Separator < Views::Base
def view_template
component = "Separator"
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
render Docs::Header.new(title: "Separator", description: "Visually or semantically separates content.")
Heading(level: 2) { "Usage" }
render Docs::VisualCodeExample.new(title: "Horizontal", context: self) do
<<~RUBY
div(class: "flex flex-col gap-4 text-sm") do
div(class: "flex flex-col gap-1") do
div(class: "leading-none font-medium") { "RubyUI" }
div(class: "text-muted-foreground") { "An open-source UI component library." }
end
Separator()
div { "Beautifully designed Phlex components that you can customize, extend, and build on." }
end
RUBY
end
render Docs::VisualCodeExample.new(title: "Vertical", description: "A vertical separator stretches to the height of its flex row.", context: self) do
<<~RUBY
div(class: "flex h-5 items-center gap-4 text-sm") do
div { "Blog" }
Separator(orientation: :vertical)
div { "Docs" }
Separator(orientation: :vertical)
div { "Source" }
end
RUBY
end
render Docs::VisualCodeExample.new(title: "Vertical Menu", description: "No fixed height needed: the separator fills the row.", context: self) do
<<~RUBY
div(class: "flex items-center gap-2 text-sm md:gap-4") do
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Settings" }
span(class: "text-xs text-muted-foreground") { "Manage preferences" }
end
Separator(orientation: :vertical)
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Account" }
span(class: "text-xs text-muted-foreground") { "Profile & security" }
end
Separator(orientation: :vertical)
div(class: "flex flex-col gap-1") do
span(class: "font-medium") { "Help" }
span(class: "text-xs text-muted-foreground") { "Support & docs" }
end
end
RUBY
end
render Docs::VisualCodeExample.new(title: "In List", context: self) do
<<~RUBY
div(class: "flex flex-col gap-2 text-sm") do
dl(class: "flex items-center justify-between") do
dt { "Item 1" }
dd(class: "text-muted-foreground") { "Value 1" }
end
Separator()
dl(class: "flex items-center justify-between") do
dt { "Item 2" }
dd(class: "text-muted-foreground") { "Value 2" }
end
Separator()
dl(class: "flex items-center justify-between") do
dt { "Item 3" }
dd(class: "text-muted-foreground") { "Value 3" }
end
end
RUBY
end
render Docs::VisualCodeExample.new(title: "Decorative", description: "Separators are announced by screen readers (role=\"separator\" with aria-orientation). Pass decorative: true for a purely visual line (role=\"none\").", context: self) do
<<~RUBY
div(class: "flex h-5 items-center gap-4 text-sm") do
div { "Profile" }
Separator(orientation: :vertical, decorative: true)
div { "Settings" }
end
RUBY
end
render Docs::VisualCodeExample.new(title: "As <hr>", description: "as: :hr renders the native separator element. Its separator role is implicit, so no role attribute is added.", context: self) do
<<~RUBY
div(class: "flex flex-col gap-4 text-sm") do
div { "Section one" }
Separator(as: :hr)
div { "Section two" }
end
RUBY
end
render Components::ComponentSetup::Tabs.new(component_name: component)
render Docs::ComponentsTable.new(component_files(component))
end
end
end
Components
| Component | Built using | Source |
|---|---|---|
Separator | Phlex | |
SeparatorDocs | Phlex |