It seems that styled-components is all the rage now; for example, it's officially the future for styling in Material-UI.
It seems to use a new kind of syntax I haven't seen (and don't yet understand). I have no idea what, if anything, must change in Fable for it to support this in some way or another, but I thought I'd raise an issue sooner rather than later, just in case.
(I'm not talking about a new syntax for the F# code, which of course is impossible for Fable to do anything about directly, but rather some way to utilize styled-components from F#/Fable.)
I think this is a tagged interpolated string: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
The good thing is the tags from the tagged interpolated strings are just functions.
If you don't need to add any logic, it's easy:
https://styled-components.com/docs/basics#getting-started
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
```f#
let Wrapper = styled.section([|"""
padding: 4em;
background: papayawhip;
"""|])
If you do need the props logic, it becomes uglier:
```ts
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
```f#
let strings = [|
"""
/* Adapt the colors based on primary prop */
background: """
""";
color: """
""";
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;"""
|]
let Button = styled.button(strings , fun (props:MyPropType) -> if props.primary then "palevioletred" else "white", fun (props:MyPropType) -> if props.primary then "white" else "palevioletred")
I think to actually use it you then need to wrap it in React.createElement:
div [] [
React.createElement(Button, butttonProps)
]
```
So the best solution is probably to wait for string interpolation in F#? https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1001-StringInterpolation.md
Could be possible already, albeit pretty ugly:
open System
// TODO: Come up with proper types
type StyledToken = obj
type StyledComponent = obj
type Styled private () =
static member button ([<ParamArray>] style : StyledToken array) : StyledComponent =
failwith "To be done"
type ButtonProps =
{ Primary : bool }
let button = Styled.button ("
padding: 4em;
background: ", (fun props -> if props.Primary then "paleviolettred" else "white"), ";
color: ", (fun props -> if props.Primary then "white" else "palevioletred"), ";
fonts-ize: 1em;
")
Another alternative would be to define the components in JS/TS and import them.
I came up with a hacky solution that looks like it will work for my purposes, just wanted to share.
Bindings:
type IStyled =
{ div: obj array -> obj }
[<ImportDefault("styled-components")>]
let _styled: IStyled = jsNative
module styled =
let div styles props element = React.createElement (_styled.div styles, props, [ element ])
Usage:
let StyledApp = styled.div [| "
background-color: ", (fun props -> if props.primary then "blue" else "red"), ";
height: 100px;
border: ", (fun props -> if props.primary then "20px" else "10px"), " solid black;
border-radius: 10px;
" |]
// appView defined elsewhere
let App = StyledApp { primary = true } (appView())
It works because of the way that styled-components happens to process the arguments passed to the tagged template function. It'd be better if f# had support for string interpolation but until then, this kind of solution will work okay for my side projects anyway.
Unfortunately, since the above bindings wrap the execution of say something like styled.div, you'll get warnings about creating components dynamically inside of other components from the styled-components library. With that, this hacky solution is probably not going to be ideal for many.
That's kind of what I had in mind as well. And as of now, this is the best we can get, besides maybe leveraging JS/TS to define components.
To support this properly, we either have to wait until string interpolation lands in the language (dotnet/fsharp#6770), or come up with something ourselves. I wouldn't "fork" the language, though.
lit-element also uses interpolated strings and really lends itself to be used functionally
I tried using it yesterday but it's quite ugly as well

String interpolation is in F# now, so we can plan how to use it with Fable. The obvious use case does already work with Fable:
Console.WriteLine $"x = {42}"
To enable the "tagged template literals" use case, we'd need to extend Fable to support System.FormattableString. Library authors can then build on that.
Some support for FormattableString has been implemented in 3.2.2. I haven't tried it yet with JS tagged templates, but I think something like this _should_ work: https://gist.github.com/alfonsogarciacaro/ea8a3cfe07e773664ea5078141ca9f82
Most helpful comment
String interpolation is in F# now, so we can plan how to use it with Fable. The obvious use case does already work with Fable:
To enable the "tagged template literals" use case, we'd need to extend Fable to support
System.FormattableString. Library authors can then build on that.