An Accordion block is officially coming to WordPress. If you’re a theme designer like me, you’re probably breaking out the fireworks already. Boom! Pop! Hooray!
And if you’re anything like me, you’ve likely already been tinkering with the block’s design, creating cool customizations. It’s OK if you haven’t gotten there already. That’s what this guide is for.
In this tutorial, let’s walk through customizing the Accordion block output so that it matches whatever theme that you’re designing.
To test the Accordion block before WordPress 6.9 is released, install the latest version of the Gutenberg plugin or WordPress 6.9 Beta. Also keep up with any changes made to the block during the final stages of the 6.9 release cycle.
Table of Contents
A use case: FAQs
Whenever I test new blocks for WordPress, I begin thinking of the various scenarios that I’d use it for. A FAQs page immediately came to mind.
In this tutorial, you’ll learn how to style the Accordion block—and its nested blocks—so that you or your users can quickly build a FAQs page like this:

That’s a screenshot of a personal theme project, so your colors, typography, and other stylistic elements will likely look different. But that’s the point: build what makes sense for your design.
And if you don’t have a theme of your own to tinker with right now, use Twenty Twenty-Five.
To build your FAQs page, begin by creating a new page via the Pages Add Page screen in the WordPress admin. Then add an Accordion block, which will automatically insert a nested Accordion Item, Accordion Heading, and Accordion Panel.
Go ahead and add a few items of your own. Or, if you prefer the easy route, you can copy the block markup from this GitHub Gist and paste it into the editor’s content area.
A look at the default Accordion design
If you added the blocks to the editor from the previous step, you probably noticed that your FAQs page looks much different than the screenshot of the finished design from earlier:

It’s a bare-bones implementation of accordions, and I like that approach. It means that I don’t have to fight quite as many specificity battles as is sometimes necessary when styling Core blocks. It’s nearly a blank canvas for folks like you and I to use whatever brush strokes we’d like on.
The Accordion block is not a single block. There are actually four with a nested structure:
- Accordion: Primary container block for nested Accordion Items.
- Accordion Item: Direct child of the Accordion block that contains Accordion Heading and Accordion Panel blocks.
- Accordion Heading: An
<h3>tag that wraps a<button>element for opening/closing the Accordion Panel. - Accordion Panel: A container block where you can insert custom blocks, such as Paragraph, Image, and more.
It’s also worth looking at the markup that it produces, as shown below. Note that I redacted some attributes since they’re unrelated to design.
<div class="wp-block-accordion is-layout-flow wp-block-accordion-is-layout-flow">
<div class="wp-block-accordion-item is-layout-flow wp-block-accordion-item-is-layout-flow is-open">
<h3 class="wp-block-accordion-heading">
<button aria-expanded="true" class="wp-block-accordion-heading__toggle">
<span class="wp-block-accordion-heading__toggle-title">Heading Text</span>
<span class="wp-block-accordion-heading__toggle-icon" aria-hidden="true">+</span>
</button>
</h3>
<div class="wp-block-accordion-panel is-layout-flow wp-block-accordion-panel-is-layout-flow">
<!-- Custom Blocks Here. -->
</div>
</div>
</div>
You can get some decent designs with theme.json alone, but to really take this to the next level, you’ll likely be using custom CSS. In the next sections, I’ll walk you through how I handle styling everything.
Styling Accordion and nested blocks
To style Accordion and its child blocks, you start with the styles.blocks object in theme.json. It will look similar to this:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"styles": {
"blocks": {
}
}
}
You don’t need to add any styles for the wrapping Accordion block itself for these next steps (you’re only styling the nested blocks). But if you needed to, you’d target styles.blocks.core/accordion in your theme.json.
Styling the Accordion Item block
To style the Accordion Item block, you target styles.blocks.core/accordion-item. In the earlier screenshot, this was the most styled piece of the design since it acts as the wrapper for each nested element.
Add this code to the styles.blocks object in theme.json:
"core/accordion-item": {
"border": {
"color": "#d5dae2",
"style": "solid",
"width": "1px",
"radius": "12px"
},
"color": {
"background": "#f6f7f9",
"text": "#343b46"
},
"shadow": "0 10px 15px -3px #80000080, 0 4px 6px -4px #80000080",
"spacing": {
"blockGap": "0"
}
}
This adds border, color, shadow, and spacing styles. The example code above and throughout the tutorial uses several hard-coded CSS values, but in a real-world project, you should be referencing presets in theme.json styles.
If you refresh your editor screen, you should see your changes applied, which is a good start:

Styling the Accordion Heading block
With the Accordion Item wrapper styles in place, it’s time to tackle the Accordion Header so that it looks like the proposed FAQs design.
If you remember from the HTML output I shared earlier, you probably noted that this block is an <h3> element. That means any styles applied to headings or the <h3> element in particular will also apply to this block. In the below code, I’m overwriting my theme’s heading typography to essentially reset it, but you may need more styles for your theme.
Add this code to your styles.blocks object in theme.json:
"core/accordion-heading": {
"css": "&__toggle { padding: var(--wp--preset--spacing--40) var(--wp--style--block-gap); }",
"typography": {
"fontFamily": "inherit",
"fontSize": "inherit",
"fontStyle": "inherit",
"fontWeight": "500",
"lineHeight": "inherit",
"textTransform": "inherit"
}
}
The code contains the css property that adds some padding to the nested toggle button. There’s no way to target this otherwise in theme.json. I also didn’t want the padding on the Accordion Heading block itself since I wanted the button to stretch the full width and height of it.
To learn more about the css attribute in theme.json, check out this tutorial on how to use it.
Now let’s refresh the screen to see how far we’ve come:

Pretty close!
Styling the Accordion Panel block
The final piece to styling via theme.json is to add padding to the Accordion Panel block so that there’s some breathing room between the content and the edges of the container.
Add this code to the styles.blocks object in theme.json:
"core/accordion-panel": {
"spacing": {
"padding": {
"top": "var(--wp--style--block-gap)",
"bottom": "var(--wp--style--block-gap)",
"left": "var(--wp--style--block-gap)",
"right": "var(--wp--style--block-gap)"
}
}
}
After refreshing the edit screen, you should see this design:

It’s not a 100% exact match with the original screenshot, but it’s nearly there. Now we need to step outside of theme.json.
Fine-tuning with CSS
The primary missing piece of the design is a different background color that is applied to the toggle button when it’s hovered/focused or when the Accordion Panel is open.

You’ll use a block stylesheet to handle styling in this case. First, create a file named block-accordion.css and place it in your theme’s /assets folder (or your preferred location for custom stylesheets).
Then, enqueue that stylesheet by adding this code to your theme’s functions.php file:
add_action( 'init', 'themeslug_enqueue_block_styles' );
function themeslug_enqueue_block_styles() {
wp_enqueue_block_style( 'core/accordion', array(
'handle' => 'themeslug-block-accordion',
'src' => get_theme_file_uri( "assets/block-accordion.css" ),
'path' => get_theme_file_path( "assets/block-accordion.css" )
) );
}
If you’re asking why you’re creating a stylesheet for the Accordion block rather than Accordion Heading, that’s a good question—the toggle button is an element within the Accordion Heading, afterall. In this case, I prefer to keep it all in one stylesheet because each of the accordion-related blocks will always be loaded together. Plus, I’ll walk you through some other styles later in this tutorial, so one stylesheet makes it easier.
Inside the block-accordion.css file, add this CSS:
/* Add toggle button background on open/hover/focus. */
.wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle,
.wp-block-accordion-heading__toggle:hover,
.wp-block-accordion-heading__toggle:focus {
background: #eceff2; /* Use a preset here. */
}
And voila! You now have a nicely styled Accordion block.
The above code changes the background color to a darker gray when the panel is open or the toggle button is hovered/focused. But you can play around with it a bit more.
You could stick these custom styles inside the css property in theme.json as you did in a previous step, but that method gets a little unwieldy once you’ve added more than a few bits of CSS.
Offering users a design choice with Block Style Variations
One of the enjoyable things about accordions in web design is that you can style them in so many ways. There’s really no limit to what you can do.
Let’s walk through registering an Accordion block style variation named Minimal. The final design will look like this:

Create a style variation JSON file
WordPress 6.6 introduced block style variations via JSON, making it easier than ever to create custom styles for any block. Using this technique, you will learn how to build a style variation for the Accordion block.
Create a new file named accordion-minimal.json in your theme’s styles folder (or in a subfolder, such as styles/block, if you prefer).
I prefer to prefix single-block style variation slugs with the block name. This makes it easier for me to know which block they belong to. It also reduces custom CSS since I can reference the class directly without also targeting the block. For example, .is-style-accordion-minimal is cleaner than .wp-block-accordion.is-style-minimal.
Add this code to your accordion-minimal.json file:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "Minimal",
"slug": "accordion-minimal",
"blockTypes": [ "core/accordion" ],
"styles": {
"css": "& .wp-block-accordion-item { margin-top: 0; } & > :first-child { border-top: none; }",
"spacing": {
"blockGap": "0"
},
"blocks": {
"core/accordion-item": {
"border": {
"radius": "0",
"bottom": {
"width": "0"
},
"left": {
"width": "0"
},
"right": {
"width": "0"
}
},
"color": {
"background": "transparent"
},
"shadow": "none"
},
"core/accordion-panel": {
"spacing": {
"padding": {
"top": "0",
"left": "0",
"right": "0"
}
}
}
}
}
}
Essentially, this is just resetting many of the styles in the default block design for your theme. But I did want to point out the css property:
"css": "& .wp-block-accordion-item { margin-top: 0; } & > :first-child { border-top: none; }",
This is doing two things:
- Removes the top margin from the Accordion Item. You might be thinking that
spacing.blockGapshould’ve done this. In theory, it should, but there is currently a bug preventing it from applying to block style variations. - Removes the top border from the first child (Accordion Item) to create the “divider” effect.
I like to keep these styles in the JSON file rather than in a separate CSS file since they are directly related to the other styles defined in the JSON.
Add custom CSS
Even though this is a more minimal design than the first, it has extensive toggle and toggle icon styles. And there’s no good way to target those items via JSON. That means you need to use a little custom CSS.
Open your assets/block-accordion.css file and add this code to it:
/* Reset heading toggle padding. */
.is-style-accordion-minimal .wp-block-accordion-heading__toggle {
padding-left: 0;
padding-right: 0;
}
/* Reset heading toggle background on open/hover/focus. */
.is-style-accordion-minimal .wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle,
.is-style-accordion-minimal .wp-block-accordion-heading__toggle:hover,
.is-style-accordion-minimal .wp-block-accordion-heading__toggle:focus {
background: transparent;
}
/* Define toggle icon design. */
.is-style-accordion-minimal .wp-block-accordion-heading__toggle-icon {
background: #f6f7f9; /* Use a preset here. */
display: inline-block;
padding: 0.5rem;
line-height: 1;
text-align: center;
border-radius: calc(infinity * 1px);
}
/* Define the toggle icon background on open/hover/focus. */
.is-style-accordion-minimal .wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle-icon,
.is-style-accordion-minimal .wp-block-accordion-heading__toggle:hover .wp-block-accordion-heading__toggle-icon,
.is-style-accordion-minimal .wp-block-accordion-heading__toggle:focus .wp-block-accordion-heading__toggle-icon {
background: #eceff2; /* Use a preset here. */
}
It looks like more code than it really is. Mostly, it needs to target the different states the panel might be in: open, toggle hover, and toggle focus. Aside from some more extensive customization of the icon, it’s mostly minimal adjustments.
Accordion-based patterns
The previous steps should get you started on your creative journey with the Accordion block. Beyond that, just have fun and tinker with the design.
But there is something you can do to take this to the next level for yourself, clients, or theme users: build patterns with the Accordion block! Let’s take what I covered throughout this tutorial and apply it to a FAQs pattern, using the Minimal block style variation:

Patterns make it so much easier to hit the ground running with these more complex nested block use cases.
Create a new faqs-accordion.php file inside your theme’s patterns folder. Then add this code:
<?php
/**
* Title: FAQs
* Slug: themeslug/faqs-accordion
* Description: Outputs an accordion of configurable FAQ items.
* Categories: text
* Keywords: faq, accordion, toggle, questions, answers
* Viewport Width: 640
* Block Types: core/accordion
*/
// Prevent direct access.
defined('ABSPATH') || exit;
?>
<!-- wp:accordion {"className":"is-style-accordion-minimal"} -->
<div role="group" class="wp-block-accordion is-style-accordion-minimal">
<?php foreach (range(1, 4) as $number): ?>
<!-- wp:accordion-item -->
<div class="wp-block-accordion-item">
<!-- wp:accordion-heading -->
<h3 class="wp-block-accordion-heading"><button class="wp-block-accordion-heading__toggle"><span class="wp-block-accordion-heading__toggle-title"><?= esc_html( sprintf( __( 'Question %d', 'themeslug' ), $number ) ); ?></span><span class="wp-block-accordion-heading__toggle-icon" aria-hidden="true">+</span></button></h3>
<!-- /wp:accordion-heading -->
<!-- wp:accordion-panel -->
<div role="region" class="wp-block-accordion-panel">
<!-- wp:paragraph -->
<p><?php esc_html_e( 'Answer goes here.', 'themeslug' ); ?></p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:accordion-panel -->
</div>
<!-- /wp:accordion-item -->
<?php endforeach; ?>
</div>
<!-- /wp:accordion -->
You’ll notice that I used a foreach loop with PHP’s range() function to output four Accordion Item blocks. This keeps the pattern file clean without unnecessarily duplicating code. Plus, you can quickly change the second parameter inside range() to output the number of items that you want.
Give the pattern a try. You’ll find it under the Text category in the inserter in the editor.
Then go out and build additional patterns. And build even more Accordion block style variations. There’s so much you can do with it. I know I’m going to have a lot of fun with this block in the coming weeks, months, and years.
Update: If you’d like to add Schema.org microdata (structured data) for FAQs, read this Snippet on filtering the output with the HTML API.
Props to @bph and @welcher for feedback and review on this post.
Leave a Reply