Aspect Ratio
Displays content within a desired ratio.
Usage
16/9
ratio: takes a "W/H" String or a Numeric (16.0 / 9). The image is positioned by its own classes; AspectRatio only sizes the box.

AspectRatio(ratio: "16/9", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
4/3

AspectRatio(ratio: "4/3", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
1/1

AspectRatio(ratio: "1/1", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
21/9

AspectRatio(ratio: "21/9", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
Content taller than the ratio
The box grows when its content is taller than the ratio allows. With overflow-hidden it keeps its 4/1 ratio and clips the lines that don't fit. Remove overflow-hidden and the box grows to show all eight.
One
Two
Three
Four
Five
Six
Seven
Eight
AspectRatio(ratio: "4/1", class: "overflow-hidden rounded-lg bg-muted p-3 text-sm text-muted-foreground") do
%w[One Two Three Four Five Six Seven Eight].each do |line|
div { line }
end
end
Installation
Using RubyUI CLI
Run the install command
rails g ruby_ui:component AspectRatio
Manual installation
1
Add RubyUI::AspectRatio to app/components/ruby_ui/aspect_ratio/aspect_ratio.rb
# frozen_string_literal: true
module RubyUI
class AspectRatio < Base
# ratio: width / height, as a Numeric (16.0 / 9, 1.5) or a "W/H" String ("16/9", "2.39/1").
# aspect_ratio: is the deprecated name of ratio:.
def initialize(ratio: nil, aspect_ratio: nil, **attrs)
unless aspect_ratio.nil?
Warning.warn("RubyUI::AspectRatio: `aspect_ratio:` is deprecated, use `ratio:`\n", category: :deprecated)
end
ratio = aspect_ratio if ratio.nil?
@ratio = parse_ratio(ratio.nil? ? "16/9" : ratio)
user_style = attrs.delete(:style)
super(**attrs)
@attrs[:style] = ratio_style(user_style)
end
def view_template(&)
div(**attrs, &)
end
private
def parse_ratio(value)
ratio =
case value
when Numeric then value.to_f if value.real?
when String
width, height = value.split("/", 2)
height ? Float(width) / Float(height) : Float(width)
end
return ratio if ratio&.finite? && ratio.positive?
raise ArgumentError
rescue ArgumentError, TypeError
raise ArgumentError, "ratio must be a positive Numeric (16.0 / 9) or a \"W/H\" String (\"16/9\"), got #{value.inspect}"
end
# Phlex's mix can't combine a String style with a Hash one, so the caller's
# style is merged here, in whichever form it came.
def ratio_style(user_style)
case user_style
when nil then "--ratio: #{@ratio};"
when Hash then {"--ratio" => @ratio}.merge(user_style)
else "--ratio: #{@ratio}; #{user_style}"
end
end
def default_attrs
{
data: {slot: "aspect-ratio"},
class: "relative aspect-(--ratio)"
}
end
end
end
2
Add RubyUI::AspectRatioDocs to app/components/ruby_ui/aspect_ratio/aspect_ratio_docs.rb
# frozen_string_literal: true
class Views::Docs::AspectRatio < Views::Base
def view_template
component = "AspectRatio"
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
render Docs::Header.new(title: "Aspect Ratio", description: "Displays content within a desired ratio.")
Heading(level: 2) { "Usage" }
render Docs::VisualCodeExample.new(title: "16/9", description: "ratio: takes a \"W/H\" String or a Numeric (16.0 / 9). The image is positioned by its own classes; AspectRatio only sizes the box.", context: self) do
<<~RUBY
AspectRatio(ratio: "16/9", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
RUBY
end
render Docs::VisualCodeExample.new(title: "4/3", context: self) do
<<~RUBY
AspectRatio(ratio: "4/3", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
RUBY
end
render Docs::VisualCodeExample.new(title: "1/1", context: self) do
<<~RUBY
AspectRatio(ratio: "1/1", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
RUBY
end
render Docs::VisualCodeExample.new(title: "21/9", context: self) do
<<~RUBY
AspectRatio(ratio: "21/9", class: "rounded-lg bg-muted") do
img(
alt: "Placeholder",
class: "absolute inset-0 size-full rounded-lg object-cover",
loading: "lazy",
src: image_path('pattern.jpg')
)
end
RUBY
end
render Docs::VisualCodeExample.new(title: "Content taller than the ratio", description: "The box grows when its content is taller than the ratio allows. With overflow-hidden it keeps its 4/1 ratio and clips the lines that don't fit. Remove overflow-hidden and the box grows to show all eight.", context: self) do
<<~RUBY
AspectRatio(ratio: "4/1", class: "overflow-hidden rounded-lg bg-muted p-3 text-sm text-muted-foreground") do
%w[One Two Three Four Five Six Seven Eight].each do |line|
div { line }
end
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 |
|---|---|---|
AspectRatio | Phlex | |
AspectRatioDocs | Phlex |