Skip to content

Conversation

@alexbiehl
Copy link
Contributor

@alexbiehl alexbiehl commented Aug 23, 2025

Hamlet already has ^{..} for embedding an existing Widget/Html value.
But it lacks a way to call a function with a captured block of template code. That’s where $component comes in.

^{..} — embed a value

Use when you already have a widget in scope:

header :: Widget
header = [whamlet| <h1>Welcome! |]

-- in a template:
^{header}

This only works if header has already been constructed in Haskell.

$component — call a function with a block

Use when you want to invoke a function that takes a Widget argument, directly inside Hamlet:

button :: Text -> Widget -> Widget
button clazz inner =
  [whamlet| <button class=#{clazz}> ^{inner} |]

-- in a template:
$component button "info"
  Click Here!

Conceptually this desugars to:

^{ button "info" [whamlet| Click Here! |] }

Which can not be expressed today.

@alexbiehl alexbiehl changed the title Support $component command Support $component directive Aug 23, 2025
@parsonsmatt
Copy link
Collaborator

Very cool!

hamlet templates can already embed other hamlet templates with the ^{embed something here} directive. Can you explain how $component name arg0 arg1 may differ from ^{name arg0 arg1}?

@alexbiehl
Copy link
Contributor Author

Ah, @parsonsmatt I've updated the PR description.

@parsonsmatt
Copy link
Collaborator

OK, that makes a lot of sense, thanks for clarifying!

Comment on lines +545 to +583
it "supports $component with binding (modal example)" $
let
modalWidget :: (ExampleModal (HtmlUrl url) -> HtmlUrl url) -> HtmlUrl url
modalWidget body =
let
exampleModal =
ExampleModal
{ modalHeader = \content ->
[hamlet|
$newline never
<div class="modal-header">
^{content}
|],
modalContent = \content ->
[hamlet|
$newline never
<div class="modal-content">
^{content}
|]
}
in
[hamlet|
$newline never
<div class="modal">
^{body exampleModal}
|]
in
helper "<div class=\"modal\"><div class=\"modal-header\"><h1>This is the title</h1></div><div class=\"modal-content\"><p>This is the content</p></div></div><p>outside</p>"
[hamlet|
$newline never
$component modal <- modalWidget
$component modalHeader modal
<h1>This is the title

$component modalContent modal
<p>This is the content
<p>outside
|]

Copy link
Contributor Author

@alexbiehl alexbiehl Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another use-case that greatly simplifies and localises the development of Hamlet templates in our application is this pattern. Note how we pass down into the component how to render individual parts of the Modal.

Allowing us to abstract over components in ways that let's you assemble widgets and individual content while still being guided by a skeleton.

@alexbiehl alexbiehl force-pushed the master branch 2 times, most recently from b048262 to 876efc6 Compare August 27, 2025 11:19
@alexbiehl
Copy link
Contributor Author

alexbiehl commented Oct 5, 2025

Any chance I can pitch the idea to anybody for inclusion in shakespeare? Happy to hop on a calls or anything to spark the discussion.

@parsonsmatt
Copy link
Collaborator

I think this is great and I'm in favor of inclusion. Could you update the changelog, write some documentation, and bump the version? Adding new constructors to the sum type is a breaking change, so it'll need to be a major version bump.

@alexbiehl
Copy link
Contributor Author

Cool, thanks! For the documentation, where would I put it? Are we talking https://github.com/yesodweb/yesodweb.com-content?

@parsonsmatt
Copy link
Collaborator

Hmmm, it is occurring to me that that is the only location with documentation on shakespeare! Yeah, let's get this merged and worry about docs later or in that repository.

@alexbiehl
Copy link
Contributor Author

alexbiehl commented Oct 7, 2025

Sounds good! Before I do that, do you think $component is the name we should go with? I could imagine $widget or $view or $block as more or less fitting alternatives.

@parsonsmatt
Copy link
Collaborator

I have no objection to component - it's a pretty common term for a reusable bit of template. Widget is a bit overloaded already in Yesod.

@alexbiehl
Copy link
Contributor Author

Alright then! I will add the changelog and version and we should be good to go then.

@alexbiehl
Copy link
Contributor Author

Alright, check out the changelog.

@alexbiehl
Copy link
Contributor Author

Cool, I think we are good to go at this point. Anything that you would like to see from this PR?

@alexbiehl
Copy link
Contributor Author

@parsonsmatt any last doubts getting this in?

@parsonsmatt
Copy link
Collaborator

Sorry, nope - I'll merge and release. Thanks so much for getting this in!

@parsonsmatt parsonsmatt merged commit 7b72d98 into yesodweb:master Nov 4, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants