yarn add @ceteio/chakra-capsize
Usage
import { withCappedText } from "@ceteio/chakra-capsize/theme";
import { CappedText, CappedHeading } from "@ceteio/chakra-capsize";
import { ChakraProvider, extendTheme } from "@chakra-ui/react";
import robotoFontMetrics from "@capsizecss/metrics/roboto";
const theme = extendTheme(
defaultTheme,
{
fonts: {
heading: "Roboto",
body: "Roboto"
},
capHeights: {
sm: 10,
md: 14,
lg: 18,
xl: 24
}
},
withCappedText({
fontMetrics: {
Roboto: robotoFontMetrics
}
})
);
const App = () => {
return (
<ChakraProvider theme={theme}>
<div>
<CappedHeading as="h1" size="2xl">
Hi!
</CappedHeading>
<CappedText>
This paragraph will have surrounding whitespace trimmed. It will also
have space between the lines of text reduced to 0.
</CappedText>
<CappedText capHeight="lg" lineGap={4}>
Setting a capHeight overrides any fontSize prop for more exact sizing.
Meanwhile, a lineGap uses the Chakra 'spacings' scale to insert space
between lines of text just like any other Chakra element.
</CappedText>
</div>
</ChakraProvider>
);
};
Setting up your theme requires the following:
- A defined body & heading font
- Font metrics for each defined font
- Text size theme keys
- Extending the theme with
withCappedText
Capsize recommends using non-system / non-fallback fonts to get the best results & most accurate trimming.
Specying fonts can be done in the following ways;
- Using chakra's fonts theme
key (default)
chakra-capsize
will use the theme'sfonts.body
&fonts.heading
theme values for<CappedText>
&<CappedHeading>
respectively unless a more specific font family is passed in.
- Setting
fontFamily
oncomponents.Text
/components.Heading
.- This is particularly useful when you have variants that use different font faces such as pull quotes or buttons.
- Passing
fontFamily
directly to a<CappedText>
/<CappedHeading>
.- The
fontFamily
prop passed will override any value onComponents.Text
/components.Heading
or the fonts theme key.
- The
Once your component has a font, chakra-capsize
requires the corresponding font
metrics to be available for calculating the correct trim values.
Importantly, the key used when passing metrics to the
withCappedText##fontMetrics
option must exactly match the font family name.
For example, when using the Open Sans
font, you must set it up like so:
withCappedText({
fontMetrics: {
'Open Sans': { ... }
}
})
// ...
<CappedText fontFamily="Open Sans">...
chakra-capsize
has two primary configuration methods, mapping to the
underlaying implementation of capsize
:
- Text size
- Space between lines of text
chakra-capsize
allows defining the Text size as either a fontSize
value, or
a capHeight
value, where capHeight
will override fontSize
if set.
By default, chakra-capsize
will use fontSize
as it's the easiest to get
started with, and often more closely matches measurements from design tools such
as Figma & Sketch.
When you're ready to have more accurate control over the exact size of text, you
can use the capHeight
prop by setting the capHeights
key in your Chakra
theme:
const theme = {
capHeights: {
sm: 10,
md: 12,
lg: 14
// ...
}
};
Then the corresponding values can be passed either directly to a <CappedText>
/ <CappedHeading>
component:
<CappedText capHeight="lg">...
or on variants, etc, in your component theme:
const theme = {
components: {
Text: {
variants: {
huge: {
capHeight: "2xl"
}
}
}
}
};
When multiple lines of text are displayed, a default gap of 0px
is applied,
resulting in lines of text whos capital letters press up againt each other.
This gap can be configured in multiple ways, two of which (lineGap
&
leading
) are closely related while the third (lineHeight
) is available to
support values supplied in Chakra's default theme.
lineGap
is the number of pixels between the bottom of one capital letter and
the top of a capital letter on the next line. lineGap
uses the spacings
theme key.
leading
can be thought of as lineGap + capHeight
. Or, to put it another way;
the distance from the bottom of one capital letter to the bottom of a capital
letter on the next line. leading
uses the sizes
theme key.
lineHeight
will set the value directly onto the text, however it's important
to note that it will not affect the spacing at the top/bottom of the text
element (it will remain trimmed).
As with capHeight
, lineGap
& leading
can be specified on the component
directly:
<CappedText lineGap={6}>...
or on variants, etc, in your component theme:
const theme = {
components: {
Text: {
variants: {
huge: {
lineGap: 12
}
}
}
}
};
Extending Chakra's <Text>
and
<Heading>
components,
<CappedText>
/ <CappedHeading>
uses capsize
to trim space surrounding and
between lines of text.
Note when using isTruncated
or noOfLines
props: To avoid ascenders and
descenders from being cut off (due to overflow: hidden
), an extra <span>
element is inserted inside the element when either isTruncated
or noOfLines
is set.
All of <Text>
/ <Heading>
's props are fully supported. In addition,
the following props are available:
A note on responsive values: Each of the following props fully support
responsive formats (both array and object) with one restriction: a base
size
must be set, otherwise an error is thrown.
Specifies the height, in pixels, of a capital letter in the line of text.
Internally, chakra-capsize
trims surrounding whitespace via capsize which
makes capHeight
equivalent to setting min-height
on a <div>
.
Can be a number, or one of the capHeights
theme key (which resolves to a
number).
When set, capHeight
will override any fontSize
values set.
Default: 0
.
When multiple lines of text are displayed, lineGap
specifies the gap, in
pixels, between those lines.
lineGap
uses the spacings
theme scale.
When set, lineGap
will override any leading
or lineHeight
values set.
When multiple lines of text are displayed, leading
specifies the distance
between one baseline to the next.
leading
uses the sizes
theme scale.
Using the sx
prop is fully supported, however behaviour is undefined when
attempting to set any of fontSize
, lineHeight
, ::before
, or :;after
. It
is recommended to only set fontSize
and lineHeight
via props, and avoid
setting ::before
or ::after
at all.
<CappedText>
and <CappedHeading>
can be passed a ref
to access the React
DOM node under the hood. However, when either isTruncated
or noOfLines
is
set, an extra inner <span>
is rendered; to access this inner DOM node, use the
truncatedRef
prop.
import { withCappedText } from '@ceteio/chakra-capsize/theme'
Add support for capsize to your Chakra theme via withCappedText
. It must be
passed in as an argument to Chakra's extendTheme
to correctly extend the the
values required.
Capsize requires a set of known font metrics to correctly trim whitespace from around and between lines of text.
chakra-capsize
also uses font metrics to support theming with Chakra.
The easiest way to generate font metrics is with the
@capsizecss/metrics
package:
import robotoFontMetrics from "@capsizecss/metrics/roboto";
// ...
extendTheme(
withCappedText({
fontMetrics: {
Roboto: robotoFontMetrics
}
})
);
(See the capsize docs for more ways of obtaining the necessary font metrics.)
Default: 'md'
For chakra-capsize
to work correctly out of the box, a default font size must
be set for all <Text>
/ <CappedText>
/ <Heading>
/ <CappedHeading>
components. The defaultFontSize
option will use the fontSizes
theme scale.
Default: 16
To safely convert between rem
& px
font sizes needed by Capsize,
chakra-capsize
must know what the html font size is. All modern browsers set
this default to 16px
, and chakra-capsize
does too.
You should only ever need to set this if you explicitly change the font-size
of the html
element.
To fix it, add a lineGap
that is at least the height of the descenders.
This occurs due to chakra-capsize
s default of lineGap = 0
which instructs
capsize to set the container to be the same height as a capital letter. Then
when isTruncated
sets overflow: hidden
, the ascenders & descenders are cut
off. By setting a lineGap
(or leading
or lineHeight
), the height of the
container is increased to stop the cut off while maintaining the correct