name: folio-view-component description: >- Develops and maintains Folio ViewComponents: generators, BEM, Slim, Stimulus data attributes, colocated assets, tests, and composition. Use when building or editing UI in app/components, adding Stimulus to a component, writing component tests, or when the user asks for ViewComponent / frontend component patterns in Folio or a host app on Folio.
ViewComponent development (Folio)
Path resolution: This skill references Folio repo files (e.g.
docs/components.md). In the Folio gem itself, use paths as-is. In a host app, resolve from the gem root:bundle show folio.
When to use
- New or refactored UI in
app/components/** - Wiring Stimulus (
data-controller, targets, actions) on component markup - Slim + Sass for a feature; BEM class names aligned with the component
- Tests for components (
render_inline, selectors) - Reviewing whether to use a slot, child
render, or a partial
Required reading
Open and use docs/components.md in this repo (directory layout, naming, BEM, Stimulus placement, testing, slots vs html_safe). Do not rely on memory alone.
JavaScript behavior: follow .skills/folio-javascript/SKILL.md for ES6+ conventions, Folio.Api, and flash events. For Stimulus controllers, see .skills/folio-stimulus/SKILL.md. For migrating legacy jQuery/IIFE scripts, see .skills/folio-stimulus-migration-from-legacy-js/SKILL.md.
Testing: follow .skills/folio-testing/SKILL.md for behavior-facing component tests, one render per test, and JavaScript behavior coverage.
Generators
Always create new components with the Folio generator — do not copy-paste empty classes by hand.
Folio engine (
Folio::…namespace): leading slash:rails generate folio:component /folio/console/ui/exampleHost app components: omit the app namespace when using a relative path; the generator auto-prefixes it (e.g. in MyProject, use
rails generate folio:component footer/menuforMyProject::Web::Footer::MenuComponent). Use a leading slash only when specifying the full namespace explicitly.
See AGENTS.md (Generators + View Components) for the slash rule and examples.
Base classes
| Context | Inherit |
|---|---|
| Folio engine, console admin | Folio::Console::ApplicationComponent |
| Folio engine, non-console | Folio::ApplicationComponent |
| Host app (typical) | App’s ApplicationComponent < Folio::ApplicationComponent (and console analogue if applicable) — match sibling components; do not subclass Folio::ApplicationComponent directly if the app defines its own base. |
Generator parent is configurable via folio_component_generator_parent_component_class_name_proc.
Initialize
- Components should define
initializemost of the time — even an emptydef initialize; endis preferable to omitting it. - Required when the component inherits directly from
Folio::ApplicationComponent/Folio::Console::ApplicationComponent(or the host app'sApplicationComponent). - Skippable only in rare cases where a shared ancestor or concern already defines
initializefor this component family.
Markup & styling
- Templates: Slim; keep templates thin; logic in the component class (mostly
privatemethods). Follow.skills/folio-slim/SKILL.mdfor formatting conventions (multi-line attributes, multipleclassattrs, avoiding inline Ruby and==). - BEM block from the component class name (
Folio::Console::…→f-c-…prefix). Elements__, modifiers--. SeeAGENTS.mdView Components section. - Styles: colocated
_component.sass(or.scss) next to the Ruby/Slim file; scope to the block. Follow.skills/folio-scss/SKILL.mdfor BEM nesting, scoping rules, and avoiding cross-component styling. - Composition: prefer
render ChildComponent.new(...)or slots over subclassing another ViewComponent that has its own template. Avoid passing large HTML strings /html_safewhere a slot fits.
Stimulus
Full conventions in .skills/folio-stimulus/SKILL.md. Key points for component markup:
StimulusHelperis included viaFolio::ApplicationComponent(and appApplicationComponentif it inherits Folio).- Root
datahash:stimulus_controller(sets@stimulus_controller_name);stimulus_merge_datafor multiple controllers. - Children:
stimulus_target/stimulus_action— only after the root sets@stimulus_controller_name. Do not useinline: trueon the primary controller. - Keep Slim concise: complex
datahashes, Stimulus params, and multi-action helper calls belong in private component methods such asdata=suggestion_data(suggestion). - JS file beside the component; register with
window.Folio.Stimulus.register(...); wire into the asset manifest.
Rendering
- From views/controllers:
render MyComponent.new(foo: bar)(or helper wrappers your app uses). - From inside a ViewComponent:
render OtherComponent.new(...)orhelpers.render(...)as in nearby Folio examples.
Testing
- Follow
.skills/folio-testing/SKILL.md. - Subclass
Folio::ComponentTestorFolio::Console::ComponentTest(test/test_helper_base.rb). - Path:
test/components/.../name_component_test.rb.
Quality gates
After edits: rubocop --autocorrect-all on Ruby, slim-lint on Slim, npx standard --fix on component JS (AGENTS.md).
Quick reference
app/helpers/folio/stimulus_helper.rb—stimulus_controller,stimulus_data,stimulus_merge_data, …docs/components.md— full narrative + diagram- Example console components:
app/components/folio/console/ui/*_component.rb