CSS strategies for PureScript apps

I’m a fan of the styled-components/emotion type of workflow, and am looking for something comparable.

I’ve found purescript-css and see it can output styling inline on the element, or to a file.
I don’t think the inlining all styles is a route I want to take, which leaves file output. It’d be great if someone could point towards an example project using this setup, specifically about how to consume the generated CSS file, deal with things like file version hashing, etc.

I’ve also come across purescript-styled-components, but not certain of it’s stability/usability levels just yet.

How do people usually go about handling styling for mid/large sized apps?

Thanks in advance!

3 Likes

How do people usually go about handling styling for mid/large sized apps?

It’s probably not the answer you’re looking for, but we just have the CSS separate and use the BEM model for naming and such. :smile:

purescript-css leaves a bit to be desired (partially my fault, since there’s a backlog of improvements that I’m accepting fairly slowly) so I’m not sure how great an experience you’d have with it compared with maintaining CSS separately anyway. It certainly doesn’t really offer much that is actually advantageous in terms of type safety and the like in its current form.

4 Likes

I haven’t worked on any of my CSS packages in a couple of months but I’m hoping to get back to some of it soon.

These are somewhat experimental but may be of interest to you anyway:

(Halogen) component styling: https://github.com/paulyoung/purescript-styled-components/blob/83d0e4f34c33375ebb78c1e0d32e34e734a7e1ff/examples/buttons/src/Example/Button.purs

Theme-based design systems: https://github.com/paulyoung/purescript-styled-system/blob/8cbdd35967bd2e12b00d028ca191837396f3b3e9/examples/purescript-styled-components/src/Example/Box.purs

CSS using row types: https://github.com/paulyoung/purescript-style/blob/9643b39b86fee771777e45d22f323433bad8ead0/test/Main.purs

6 Likes

Has this landscape changed? I’ve started messing with Purescript some days ago and I’m struggling to find a “standard” way of changing an element’s style via Purescript without using external libraries (I’d like to animate an element by changing it’s left and top style properties or through CSS’s transform). The way that looks easier is by defining a foreign function that gives access to the style property of an element object. Another alternative would be via the setAttribute function but this seems too much of a stretch.

It seems that Halogen has some helpers for dealing with CSS and purescript-react too, by the props function. If they are something like the CSS-in-JS approach, I’m interested. But for now I’d like to stick to the standard packages.

I’m currently thinking about a system for css which isn’t based on inline css styles but on generating css based on given types. Something like sass but in a typed manner maybe also possible to do that in dhall. What do you think about that? With that you can do stuff like sass and be sure that you’ll always get valid output.

1 Like

@m3tti https://github.com/paulyoung/purescript-style can render stylesheets as well as inline CSS.

1 Like

See https://github.com/paulyoung/purescript-style/blob/62b09a52778fa8923f8be376dc4b23ff2c168d69/test/Main.purs#L82

1 Like

Quick heads up: there was also an issue opened on Real World Halogen which discusses CSS strategies for Halogen apps and relates to this discussion.

4 Likes

Hey there,

In terms of a css-in-purescript solution for Halogen, I’ve found the following is a pretty nice system for getting your styles set up:

  1. mount a secondary tree in the head which contains your styles - it only needs a single component, which creates a Style tag.
  2. for each component module, have a style module which exports the following:
    • the HTML classnames used by a module as either Strings or Halogen classnames
    • a concatenated set of css rules for your component (you can build these using the combinators and rules provided by the purescript-css package)
  3. import and use the htrml classnames in your Halogen component - this mostly provides typesafety around your classes, that they are strings exported from the styles module rather than random strings that your app might not care about
  4. in the Style component mounted in step 1. import the styles from each of your Halogen componets, concatenate them, and render them as text content of your style tag.

This is more or less what styled components and emotion do under the hood, and appears to be a low-overhead approach.

Unfortunately this approach isn’t great if you want to do style code-splitting.

in those cases you would probably need to mount secondary Style container tags when you get your second bundle.

1 Like

Also, freedom framework implements styling by replacing & in class .& { ... } with hash like .XXX { ... }. More here

Using Purescript CSS module and halogen-css with Halogen and this is basically my approach.

  1. For each component write a CSS.ComponentName module that includes all the css for that particular component
  2. Include all the CSS within the relevant component. The reason I do this is because if I only include it in the head of the main page, those styles won’t be present if a user only decides to include a single Component. I render this as stylesheet (included in the Halogen CSS package). The reason I don’t do inline css for each separate element is because with inline hover doesn’t work etc.
  3. Annotate your div’s with classnames as well, even if you don’t use them with your Halogen CSS module. It’s good for when you ship your components and other people might want to alter the CSS not through Purescript.

Doing CSS-in-Purescript has been very nice. This way I can ship components without having to import the css specifically. And the purescript-css package is very nice and expressive

1 Like

@naglalakk could you include example of CSS.ComponentName (maybe as the link to the GitHub gist)

I do it in this repo for example

In this folder I have components and then corresponding CSS modules located in CSS/.
This repo is very much a work in progress but this is the structure I’ve been going for.
If you look at the render function for e.g. Browser component I define classes with css “className”. I then declare the stylesheet with BrowserStyle.stylesheet. In each CSS module I define a separate function for each class and then collect them into a stylesheet which I can then use in the component. I usually just add the component stylesheet to the top div of the component.

1 Like

It’s not a PureScript solution, and it doesn’t add type safety to CSS, but I’ve used Hacss in a Halogen app like so:

[ HH.button [ HP.class_ $ H.ClassName "color:blue; :hover{color:red;}" ]
  [ HH.text "Button Text" ] ]
1 Like

What about CSS Modules?

Parcel has them by default: CSS Modules in Parcel

import * as classes from './styles.module.css';

document.body.className = classes.body;

But when I try to implement this, the spago build output does not copy the module.css files, which results in @parcel/core: Failed to resolve './x.module.css' from './output/LogIn/foreign.js'

I guess I could try to copy all s?css files to the output directory of spago build but maybe there is a better way/strategy?

I can’t find a way to let parcel know which files to copy alongside purs/js.

This is what I’m trying:

/* LogIn.module.css */
.default {
  color: red
}
// LogIn.js (still on purs 0.14)
exports.classes = require('./LogIn.module.css');
-- LogIn.purs
foreign import classes :: { default :: String }

Haskell project to generate purescript code from css modules

1 Like

Here’s another option: GitHub - nsaunders/purescript-tecton: CSS in PureScript

There’s still a lot of work left to do, but compared to purescript-css it’s more complete, offers better type safety, and features a “highly-overloaded API” that closely resembles the CSS output it produces.

1 Like

How about using emotion? That’s what I do

1 Like