Manage, constrain and use CSS class properties on ViewComponent components.
Note: At this point in time this should be considered a proof of concept.
ViewComponentProperties allows you to:
- apply tightly constrained CSS classes ("properties") to ViewComponents using properties defined once, but available to be applied anywhere
- quickly create simple ViewComponents using a provided base utility component
The goal of ViewComponentProperties is to facilitate implementing a design system by providing well defined and clear constraints on the CSS that can be used to build HTML views with ViewComponents. When combined with a comprehensive CSS framework (such as Tailwind CSS), once your components and properties have been defined, it should be possible to implement the design intent of a design system in a view while writing less HTML and/or CSS. (..maybe even none at all)
While not a requirement, the current version is somewhat built assuming usage of Tailwind CSS for styling.
ViewComponentProperties depends on ViewComponent and therefore is intended to work with Ruby on Rails, v5.0+
The gem has not yet been published but you can install in your app using by adding this to your Gemfile
:
gem 'view_component_properties', git: 'https://github.com/simonrand/view_component_properties.git'
Ensure you have ViewComponent working in your Rails app.
First, define an ApplicationComponent
which inherits from ViewComponentProperties::BaseComponent
.
app/components/application_component.rb
:
class ApplicationComponent < ViewComponentProperties::BaseComponent
end
app/components/example_component.rb
:
class ExampleComponent < ApplicationComponent
private
def tag_name # optional, :div is the default
:p
end
end
ViewComponentProperties::BaseComponent
implements an inline template which simply returns our content wrapped in the defined tag_name
, so using our ExampleComponent
above:
<%= render(ExampleComponent.new) do %>
Hello, World!
<% end %>
Returns:
<p>Hello, World!</p>
Define our property and the allowed values in app/components/properties/margin/bottom.rb
:
module Properties
module Margin
module Bottom
include ViewComponentProperties::Properties::Base
# NOTE: mb-* are Tailwind CSS margin bottom utility classes, see
# https://tailwindcss.com/docs/margin/#add-margin-to-a-single-side
CLASSES = {
2 => 'mb-2',
4 => 'mb-4'
}
end
end
end
The path and module name defines the parameter name which will set the property on a component, so in the case of our margin bottom property, the parameter name will be margin_bottom
.
Add our property to our ExampleComponent
by adding the parameter name the properties
class method.
app/components/example_component.rb
:
class ExampleComponent < ApplicationComponent
# NOTE: You can include multiple properties here, for example `properties :margin_bottom, :margin_top`
properties :margin_bottom
end
Now we can apply our property to the component:
<%= render(ExampleComponent.new(margin_bottom: 2)) do %>
Hello, World!
<% end %>
Returning:
<div class="mb-2">Hello, World!</div>
Responsive properties (again following Tailwind CSS conventions) are supported by passing a hash value for the property value. For example:
app/components/example_component.rb
:
class ExampleComponent < ApplicationComponent
properties :margin_bottom # as per the "Adding a margin bottom property to a component" example above
end
<%= render(ExampleComponent.new(margin_bottom: { default: 2, lg: 4 })) do %>
Hello, World!
<% end %>
Returns:
<div class="mb-2 lg:mb-4">Hello, World!</div>
By default passing invalid property values to will result in no class being returned:
app/components/example_component.rb
:
class ExampleComponent < ApplicationComponent
properties :margin_bottom # as per the "Adding a margin bottom property to a component" example above
end
Now we can apply our property to the component:
<%= render(ExampleComponent.new(margin_bottom: 1)) do %>
Hello, World!
<% end %>
Returning:
<div>Hello, World!</div>
However, for non-production environments it would be recommended that you raise an error on invalid property values, you can do this by setting the raise_error_for_invalid_property_values
configuration option to true:
ViewComponentProperties.config.raise_error_for_invalid_property_values = true
No when we provide an invalid property value:
<%= render(ExampleComponent.new(margin_bottom: 1)) do %>
Hello, World!
<% end %>
This will raise with:
ViewComponentProperties::PropertyError
It is not recommended to raise exceptions in production environments.
- Continue exploring this proof of concept
Bug reports and pull requests are welcome on GitHub at https://github.com/simonrand/view_component_properties. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.