Blocks are boxes of content in Drupal, It is like a component and we can place them on a web page by placing them in any region of the theme. Drupal provides many inbuilt blocks and you can use view to create new blocks. I believe creating a block using a view is the best method. We can create a block with dynamic content using it. However, the Drupal core system provides an annotation to create a custom block.

In this article, we will see how to create and define custom blocks with a single configurable field.
Your first step will be, to create a custom module. I am skipping info.yml as we all know how to do that and let's assume ourblock is our module name.

Annotation

<?php
/ *
 * @Block(
 *   id = "ourblock_simple_block",
 *   admin_label = @Translation("OurBlock: Simple Block")
 * )
 */

Here id is our block unique id or you can say it’s a machine name and admin_label is a translatable label that will show in the admin.

As we are going to define one configurable field with our block so we also need to define its schema under ourblock/config/schema so our system can know which type of value our field will hold.

Here is the schema for our block. (ourblock.schema.yml)

block.settings.ourblock_simple_block:
  type: block_settings
  label: 'Confugration of our block'
  mapping:
    block_secondary_title:
      type: string
      label: 'Block secondary title'

Now we have to define our block class in the directory ourblock/src/Plugin/Block and our namespace will be Drupal\ourblock\Plugin\Block.

<?php
namespace Drupal\ourblock\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
/**
 * Class OurBlockSimpleBlock
 *
 * @package Drupal\ourblock\Plugin\Block
 *
 * @Block(
 *   id = "ourblock_simple_block",
 *   admin_label = @Translation("OurBlock: Simple Block")
 * )
 */
class OurBlockSimpleBlock extends BlockBase {
/**
   * {@inheritdoc}
   *
   * This method sets the block default configuration.
   */
  public function defaultConfiguration() {
    return [
      'block_secondary_title' => $this->t('A default value '),
    ];
  }
/**
   * {@inheritdoc}
   *
   * This method defines form elements for custom block configuration.
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $form['block_secondary_title_text'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Secondary Title'),
      '#description' => $this->t('This will be secondary title'),
      '#default_value' => $this->configuration['block_secondary_title'],
    ];
    return $form;
  }
/**
   * {@inheritdoc}
   *
   * This method processes the blockForm() form fields when the block
   * configuration form is submitted.
   *
   * The blockValidate() method can be used to validate the form submission.
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['block_secondary_title']
      = $form_state->getValue('block_secondary_title_text');
  }
/**
   * {@inheritdoc}
   */
  public function build() {
    return [
      '#markup' => $this->configuration['block_secondary_title'],
    ];
  }
}

Now enable your module from the backend and your block is ready to be placed on regions of the theme, You can place it from Block Layout.