Version 0.4.0 now released! See the release notes on GitHub Releases

Polymorphic heading

How big a heading looks and which level it is are two separate decisions. A card title might need to look large and still be an <h3> in the outline. So the component shouldn't be locked to one tag: the size is a typed variant, and the tag is picked wherever the heading is used.

Define it

components/heading.css.ts
import { styled } from "@salty-css/react/styled";

// "h2" is only the default tag — every instance can swap it.
export const Heading = styled("h2", {
  base: {
    margin: 0,
    lineHeight: 1.15,
    fontWeight: 600,
  },
  variants: {
    size: {
      small: { fontSize: "1.25rem" },
      regular: { fontSize: "1.75rem" },
      large: { fontSize: "2.5rem", letterSpacing: "-0.01em" },
    },
  },
  defaultVariants: {
    size: "regular",
  },
});

Use it

Example
import { Heading } from "./heading.css";

<>
  <Heading as="h1" size="large">Pricing</Heading>
  {/* Looks just as big, but sits lower in the outline. */}
  <Heading as="h3" size="large">Pro plan</Heading>
  <Heading>Defaults to an h2 at regular size</Heading>
</>;

as is a per-instance shorthand for the element option — use element: "h3" in the styled() options when every instance should default to another tag. The size prop is consumed by Salty for styling and never reaches the DOM; what ships is a hashed class per size, compiled ahead of time.