ui
ui copied to clipboard
Typography could be components
Hi,
Typography could be in components folder as components.
Regards,
Geraldo
This is not a component library, therefore Typography component is not suited here. Is there any specific feature that you would like the Typography component to perform?
I'm not a designer, and I've been learning CSS for what feels like forever (it never seems to stick), but I know that this approach is the right one. I've been trying to use Stitches before, and if a designer is part of the project, they can make changes to the components that are bootstrapped by this marvelous library and handed to us. Therefore, I think it would be helpful to have the example code presented as components.
@shadcn need your inputs here
Agreed. We can add the typography with the same command as other components: npx shadcn-ui add typography
.
Potential Approaches?
I am posting this here as a follow up from the work by @nilaq and discussion on-going in #363! I recently had to implement something like this in a different codebase, and opted for custom components for each HTML tag.
- Only including and exporting a
typographyVariants(...)
cva function for use anywhere in your project, as suggested by @armandsalle - Using a polymorphic Typography component as implemented by @nilaq in same PR.
- Having a custom component to match each HTML tag / variant - an approach I implemented recently
- External Github Gist/library or something
I am leaning toward a middle-ground between approaches 1 and 3...but possibly also including 2?
2 (Polymorphic)
This is already being implemented in #363
<Typography variant="h1">...</Typography>
// OR
<Typography variant="h1" as="h2">...</Typography>
Pros
- Easy to use, established pattern
Cons
- Can be cumbersome to type/ensure type-safety + accessibility in general (e.g rendering h1 as link but forgetting to add href)
- This is component library territory? as noted by @abhinav-anshul
1, 3 (cva + component per tag)
// ui/typography.tsx
export const typographyVariants = cva(...)
export const H1 = React.forwardRef({ className, ...props }, ref){
return <h1 ref={ref} className={cn(typographyVariants({ variant: "h1" }), className)} {...props}/>
}
H1.displayName = "H1"
//...
Pros
- It is straightforward to add new Typography components (e.g
<Mark />
,<A />
etc.) - Easy find and replace: Find all
h1
and replace withH1
. - The approach is not as opinionated in the rendering logic, and somewhat matches the existing examples in current docs already. This may be what @shadcn was going for by adopting the
className
-only approach? - Plug and play into things like MDX
Cons
- It is more code which could mean way more maintenance overhead especially if you want to make sweeping functionality changes across Typography components - then you'd need more copy-pasta.
1, 2, 3 (cva + "polymorphic" + custom component per tag)
To mitigate the Con's from above, a polymorphic typography component could be an implementation detail of the custom HTML components.
Further, instead of being "polymorphic", the base Typography
component could use the asChild
functionality similar to what ui/button.tsx
uses to ensure base Typography
behavior across all custom HTML components, which is recommended by Radix docs (over the deprecated Polymorphic
utilities).
CLI
The cli for this could also be interactive opt-in for which typography components you want in your codebase...depending on the approach taken.
Not taking any action on this yet, just something for @shadcn and community to consider!
That would be great!
Creating a rich typography system is a pain. And just plain boring
I was wondering. Given that much of this project is based on reusing radix-ui and providing additional styles on top of it, is it worth re-using the typography system as defined in the radix-ui docs?
Plus one on this ➕
It would be great help for developers to have such Typography components :+1:
Would be awesome!
@rexfordessilfie I created some semantic typography components on top of the "polymorphic Typography component" idea from the PR @nilaq started (https://github.com/shadcn/ui/pull/363) that you mentioned. (I added the code as a large comment to that PR).
I think the "polymorphic Typography component" idea could be a powerful one, as you could:
- use it directly (Typography variant="x" for your entire app), or
- use semantic components that wrap it (Heading, Text, Blockquote, etc.), or
- use "custom component to match each HTML tag / variant" that wrap it (H1, H2, P, etc.).
The "base" polymorphic Typography component could house all the main logic/etc. in one place, with the wrapper components being pretty "dumb", and as a dev you're able to choose which implementation you want to use 😎
(this is what I've started doing already with my semantic components, see https://github.com/shadcn/ui/pull/363)
As mentioned by @rexfordessilfie to use the Polymorphic approach for this "feature". I've implemented this approach for real world use.
EDIT: In certain use cases, the added margin top on the paragraphs is undesirable. Therefore I've added an affect to remove it when desired. ("removePMargin").
import { cn } from "@/lib/utils"
import { cva, type VariantProps } from "class-variance-authority"
import React from "react"
export const typographyVariants = cva("text-xl", {
variants: {
variant: {
h1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg: text-5xl",
h2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0",
h3: "scroll-m-20 text-2xl font-semibold tracking-tight",
h4: "scroll-m-20 text-xl font-semibold tracking-tight",
p: "leading-7 [&:not(:first-child)]:mt-6",
// blockquote: "mt-6 border-l-2 pl-6 italic",
// list: "my-6 ml-6 list-disc [&>li]:mt-2",
},
affects: {
default: "",
lead: "text-xl text-muted-foreground",
large: "text-lg font-semibold",
small: "text-sm font-medium leading-none",
muted: "text-sm text-muted-foreground",
removePMargin: "[&:not(:first-child)]:mt-0",
},
},
defaultVariants: {
variant: "h1",
affects: "default",
},
})
export interface TypographyProps
extends React.HTMLAttributes<HTMLHeadingElement>,
VariantProps<typeof typographyVariants> {}
const Typography = React.forwardRef<HTMLHeadingElement, TypographyProps>(
({ className, variant, affects, ...props }, ref) => {
const Comp = variant || "p"
return (
<Comp
className={cn(typographyVariants({ variant, affects, className }))}
ref={ref}
{...props}
/>
)
},
)
Typography.displayName = "H1"
export default Typography
Blockquotes, Table items, and list have been omitted.
affects
Thank you, @MeatBoyed! It would be good to include multiple affects
support!
In the meantime ive made reusable components out of it. They can be copy pasted or used as a package via npm :)
https://github.com/kian1991/shadcn-typography?tab=readme-ov-file#installation
Thank you so much @kian1991! That's exactly what I needed!
Thank you so much @kian1991! That's exactly what I needed!
Glad you liked it! :)
Hi, It's a bit late to contribute, but I thought this could still be useful.
I created my own versions of the Typography Addon for shadcn. The folder contains 3 versions:
- A 1:1 copy with shadcn under
Typography.tsx
. - One that can be rendered as a given tag, named
TypographyAs.tsx
. - One inspired by this discussion, that includes Affects, still drawing inspiration from the original Typography rule set. This one is under the name
TypographyCommunity.tsx
.
Here's the README for the original 1:1 version https://github.com/ARCADEGC/shadcnAddons/blob/main/README.md
I recommend using the As version. It simplifies things by letting you change the tag directly inline with as
attribute, without needing asChild. https://github.com/ARCADEGC/shadcnAddons/blob/main/components/ui/TypographyAs.tsx
This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.